4 Commits

Author SHA1 Message Date
e48798ebff fix(ci): release.yml invalide, ': ' dans un nom d'étape cassait le YAML
All checks were successful
CI / Build & test (Node 22) (push) Successful in 10m13s
CI / Build & test (Node 24) (push) Successful in 10m6s
CI / No em/en dashes (push) Successful in 3s
Release / Publish to Gitea npm registry (push) Successful in 9m59s
CI / Pack & boot smoke (Node 22) (push) Successful in 9m58s
Séquelle du nettoyage des tirets : un tiret cadratin dans le nom de l'étape
« Publish » avait été remplacé par ' : ', or un scalaire YAML non quoté ne
peut pas contenir deux-points+espace ("mapping values are not allowed").
Remplacé par une virgule. Gitea refusait de lancer le workflow → la
publication npm du daemon sur un tag v* ne partait pas.
2026-07-17 21:55:53 +02:00
1a74576955 feat(desktop): logo de fenêtre, homepage vitrine, licence MIT ; attache release idempotente
Some checks failed
Desktop Release / Build Linux (AppImage + deb) (push) Successful in 13m34s
CI / Build & test (Node 22) (push) Has been cancelled
CI / Build & test (Node 24) (push) Has been cancelled
CI / Pack & boot smoke (Node 22) (push) Has been cancelled
CI / No em/en dashes (push) Has been cancelled
- Fenêtre principale : icône explicite (resolveIconPath partagé dans paths.ts,
  réutilisé par le tray) pour afficher le logo Arboretum en fenêtre/barre des
  tâches au lieu de l'icône Electron générique.
- package.json desktop : homepage -> https://git-arboretum.com (la vitrine, plus
  le dépôt Gitea) et champ license: MIT. Copyright daté avec le nom dans
  electron-builder.yml. Licence MIT + author aussi au package.json racine.
- desktop-release.yml : attache des assets idempotente (supprime l'asset de même
  nom avant ré-upload) pour que le dernier build gagne sur un re-run.
2026-07-17 21:46:22 +02:00
bd76e53570 docs(ci): documenter la portée write:repository requise de NPM_TOKEN
All checks were successful
CI / Build & test (Node 22) (push) Successful in 10m15s
CI / Build & test (Node 24) (push) Successful in 10m10s
CI / No em/en dashes (push) Successful in 3s
Desktop Release / Build Linux (AppImage + deb) (push) Successful in 14m1s
CI / Pack & boot smoke (Node 22) (push) Successful in 10m5s
L'attache des installeurs/VSIX à la release Gitea réutilise NPM_TOKEN ; ce
token doit porter write:repository EN PLUS de write:package, sinon l'API
release renvoie 403 (l'étape est best-effort, non bloquante : les artefacts
restent disponibles via upload-artifact).
2026-07-17 20:42:21 +02:00
b0a75df204 fix(desktop): métadonnées de packaging .deb (homepage, author.email, maintainer)
Some checks failed
CI / Build & test (Node 22) (push) Successful in 10m10s
CI / Build & test (Node 24) (push) Successful in 10m6s
CI / No em/en dashes (push) Successful in 5s
Desktop Release / Build Linux (AppImage + deb) (push) Successful in 13m39s
CI / Pack & boot smoke (Node 22) (push) Has been cancelled
electron-builder exige un homepage projet, un author.email et un maintainer
.deb : le build Linux produisait l'AppImage mais échouait sur la cible deb.
Ajoute ces champs au package.json desktop et fixe explicitement le
maintainer dans electron-builder.yml.
2026-07-17 20:04:50 +02:00
9 changed files with 41 additions and 15 deletions

View File

@@ -50,7 +50,9 @@ jobs:
packages/desktop/release/*.deb packages/desktop/release/*.deb
packages/desktop/release/latest-linux.yml packages/desktop/release/latest-linux.yml
# Best-effort : attache les installeurs (+ latest-linux.yml pour l'auto-update) à la release # Best-effort : attache les installeurs (+ latest-linux.yml pour l'auto-update) à la release
# Gitea du tag (crée la release si absente). Réutilise NPM_TOKEN (même token Gitea). # Gitea du tag (crée la release si absente). Réutilise NPM_TOKEN (même token Gitea) : ce token
# doit porter la portée write:repository en plus de write:package, sinon l'API release renvoie
# un 403 (l'attache est ignorée, les installeurs restent disponibles en artefact du run).
- name: Attach installers to Gitea release - name: Attach installers to Gitea release
continue-on-error: true continue-on-error: true
env: env:
@@ -72,6 +74,13 @@ jobs:
for f in packages/desktop/release/*.AppImage packages/desktop/release/*.deb packages/desktop/release/latest-linux.yml; do for f in packages/desktop/release/*.AppImage packages/desktop/release/*.deb packages/desktop/release/latest-linux.yml; do
[ -f "$f" ] || continue [ -f "$f" ] || continue
name=$(basename "$f") name=$(basename "$f")
# Re-run idempotent : supprimer un asset existant du même nom avant de ré-uploader, pour
# que le dernier build gagne (l'API Gitea refuse sinon un asset déjà présent).
existing=$(curl -fsSL -H "$auth" "${api}/releases/${rid}/assets" | node -e "const a=JSON.parse(require('fs').readFileSync(0,'utf8'));const m=Array.isArray(a)?a.find(x=>x.name===process.argv[1]):null;process.stdout.write(m?String(m.id):'')" "$name" || true)
if [ -n "$existing" ]; then
echo "replacing existing $name (asset $existing)"
curl -fsSL -X DELETE -H "$auth" "${api}/releases/${rid}/assets/${existing}" || true
fi
echo "attaching $name" echo "attaching $name"
curl -fsSL -X POST -H "$auth" -F "attachment=@${f}" "${api}/releases/${rid}/assets?name=${name}" curl -fsSL -X POST -H "$auth" -F "attachment=@${f}" "${api}/releases/${rid}/assets?name=${name}"
done done

View File

@@ -44,7 +44,7 @@ jobs:
# `bash -eo pipefail` : on isole l'échec attendu dans la condition d'un `if` pour ne pas # `bash -eo pipefail` : on isole l'échec attendu dans la condition d'un `if` pour ne pas
# déclencher `set -e`. Le secret du registre est mappé sur NODE_AUTH_TOKEN lu par le .npmrc # déclencher `set -e`. Le secret du registre est mappé sur NODE_AUTH_TOKEN lu par le .npmrc
# de setup-node. # de setup-node.
- name: Publish (idempotent : tolère un 409 « already exists ») - name: Publish (idempotent, tolère un 409 « already exists »)
run: | run: |
if out="$(npm publish -w @johanleroy/git-arboretum 2>&1)"; then if out="$(npm publish -w @johanleroy/git-arboretum 2>&1)"; then
printf '%s\n' "$out" printf '%s\n' "$out"

View File

@@ -46,9 +46,10 @@ jobs:
name: vsix name: vsix
path: packages/vscode/*.vsix path: packages/vscode/*.vsix
# Best-effort : attache le VSIX à la release Gitea du tag (crée la release si absente). # Best-effort : attache le VSIX à la release Gitea du tag (crée la release si absente).
# Réutilise le secret NPM_TOKEN (même token Gitea que la publication du daemon, droits # Réutilise le secret NPM_TOKEN (même token Gitea que la publication du daemon) : ce token doit
# repository suffisants pour l'API release). Sans lui, l'étape est ignorée sans faire échouer # porter write:repository en plus de write:package, sinon l'API release renvoie un 403. Sans
# le job (continue-on-error) ; le VSIX reste disponible en artefact. # token, l'étape est ignorée sans faire échouer le job (continue-on-error) ; le VSIX reste
# disponible en artefact.
- name: Attach VSIX to Gitea release - name: Attach VSIX to Gitea release
continue-on-error: true continue-on-error: true
env: env:

View File

@@ -2,6 +2,8 @@
"name": "arboretum-monorepo", "name": "arboretum-monorepo",
"private": true, "private": true,
"version": "0.0.0", "version": "0.0.0",
"license": "MIT",
"author": "Johan LEROY <contact@johanleroy.fr>",
"type": "module", "type": "module",
"workspaces": [ "workspaces": [
"packages/shared", "packages/shared",

View File

@@ -1,6 +1,6 @@
appId: fr.lidge.arboretum appId: fr.lidge.arboretum
productName: Arboretum productName: Arboretum
copyright: Copyright Johan Leroy copyright: Copyright © 2026 Johan Leroy
directories: directories:
output: release output: release
@@ -32,6 +32,8 @@ linux:
deb: deb:
# git est requis pour les operations de worktree ; claude n'est pas dans les depots (documente). # git est requis pour les operations de worktree ; claude n'est pas dans les depots (documente).
depends: [git] depends: [git]
# Mainteneur .deb explicite (electron-builder l'exige ; sinon derive de author.email du package.json).
maintainer: Johan LEROY <contact@johanleroy.fr>
win: win:
target: target:

View File

@@ -3,6 +3,12 @@
"private": true, "private": true,
"version": "0.1.0", "version": "0.1.0",
"description": "Arboretum desktop app: Electron shell that runs the daemon and shows its web UI", "description": "Arboretum desktop app: Electron shell that runs the daemon and shows its web UI",
"homepage": "https://git-arboretum.com",
"license": "MIT",
"author": {
"name": "Johan LEROY",
"email": "contact@johanleroy.fr"
},
"main": "dist/main.js", "main": "dist/main.js",
"type": "commonjs", "type": "commonjs",
"scripts": { "scripts": {

View File

@@ -5,6 +5,7 @@ import { seedSessionCookie } from './auth';
import { loadWindowState, saveWindowState } from './window-state'; import { loadWindowState, saveWindowState } from './window-state';
import { createTray } from './tray'; import { createTray } from './tray';
import { initUpdater } from './updater'; import { initUpdater } from './updater';
import { resolveIconPath } from './paths';
const PARTITION = 'persist:arboretum'; const PARTITION = 'persist:arboretum';
const PORT = 7317; const PORT = 7317;
@@ -53,6 +54,8 @@ function createWindow(url: string): void {
width: state.width, width: state.width,
height: state.height, height: state.height,
backgroundColor: '#09090b', backgroundColor: '#09090b',
// Logo de la fenêtre / barre des tâches (sinon icône Electron générique sous Linux/Windows).
icon: resolveIconPath(),
webPreferences: { webPreferences: {
partition: PARTITION, partition: PARTITION,
contextIsolation: true, contextIsolation: true,

View File

@@ -14,6 +14,15 @@ export function resolveServerEntry(): string {
return join(__dirname, '..', '..', 'server', 'dist', 'index.js'); return join(__dirname, '..', '..', 'server', 'dist', 'index.js');
} }
/** Logo de l'app (fenêtre, tray, barre des tâches) : le mark Arboretum embarqué. */
export function resolveIconPath(): string {
// packagé : extraResources copie resources/icon.png à la racine de resources/.
// dev : depuis dist/main.js -> ../resources/icon.png.
return app.isPackaged
? join(process.resourcesPath, 'icon.png')
: join(__dirname, '..', 'resources', 'icon.png');
}
/** Binaire Node qui exécute le daemon (>= 22.16 : node:sqlite + ABI node-pty maîtrisé). */ /** Binaire Node qui exécute le daemon (>= 22.16 : node:sqlite + ABI node-pty maîtrisé). */
export function resolveNodeBin(): string { export function resolveNodeBin(): string {
if (app.isPackaged) { if (app.isPackaged) {

View File

@@ -1,16 +1,10 @@
import { app, Menu, Tray, nativeImage } from 'electron'; import { Menu, Tray, nativeImage } from 'electron';
import { join } from 'node:path';
import { isAutoStartEnabled, setAutoStart } from './autostart'; import { isAutoStartEnabled, setAutoStart } from './autostart';
import { resolveIconPath } from './paths';
function iconPath(): string {
return app.isPackaged
? join(process.resourcesPath, 'icon.png')
: join(__dirname, '..', 'resources', 'icon.png');
}
/** Icône de barre système : ouvrir la fenêtre, basculer le lancement au login, quitter. */ /** Icône de barre système : ouvrir la fenêtre, basculer le lancement au login, quitter. */
export function createTray(opts: { show: () => void; quit: () => void }): Tray { export function createTray(opts: { show: () => void; quit: () => void }): Tray {
const image = nativeImage.createFromPath(iconPath()); const image = nativeImage.createFromPath(resolveIconPath());
const tray = new Tray(image.isEmpty() ? nativeImage.createEmpty() : image.resize({ width: 18, height: 18 })); const tray = new Tray(image.isEmpty() ? nativeImage.createEmpty() : image.resize({ width: 18, height: 18 }));
tray.setToolTip('Arboretum'); tray.setToolTip('Arboretum');