diff --git a/ops/README.md b/ops/README.md index fcf018f2d..dd87dcf71 100644 --- a/ops/README.md +++ b/ops/README.md @@ -24,6 +24,13 @@ Après déploiement, le contrôle qui compte n'est pas que le nouveau widget s'affiche : c'est que les intégrations **préexistantes** fonctionnent encore. C'est la seule preuve que `SECRET_ENCRYPTION_KEY` n'a pas bougé. +Le premier déploiement d'une v2 sur une base v1 est **à sens unique** : Homarr +migre la base au démarrage, et une v1 ne sait plus la lire. Le retour arrière +passe alors par la copie `/root/homarr-db-.sqlite` que fait le +script, pas par la seule archive de `/opt/homarr`. La v2 change aussi l'échelle +des tableaux (cellules fixes de 200 × 200) : les widgets paraîtront plus petits, +ce qui se règle avec le nombre de colonnes, pas avec un retour en v1. + ## Déplacer l'état hors de /appdata `/appdata` vient de l'image Docker, où c'est un point de montage. Sur une @@ -77,18 +84,47 @@ git rebase v1.78.0 feat/unifi-os-integration # remplace par la version vis Puis, dans cet ordre — chaque étape a déjà attrapé quelque chose : +Depuis la v2, le dépôt se construit avec **bun** et exige un Node récent, aux +versions fixées dans `mise.toml` (bun 1.4.2, Node ≥ 24.18). Sur ce poste : + ```bash -pnpm install # le lockfile bouge presque à chaque version -pnpm turbo typecheck # les 37 paquets -pnpm test packages/integrations/ packages/widgets/ -pnpm test packages/widgets/src/manifest.spec.ts # les points d'enregistrement +export PATH="$HOME/.local/share/nvm/v24.21.0/bin:$PATH" +npm i -g bun@1.4.2 # une fois, dans le préfixe de ce Node +``` + +```bash +bun install # le lockfile bouge presque à chaque version +bun run turbo typecheck # les 38 paquets +bun run test packages/integrations/ packages/widgets/ packages/definitions/ +bun run test packages/widgets/src/manifest.spec.ts # les points d'enregistrement ops/deploy-lxc.sh --dry-run ``` -`manifest.spec.ts` mérite sa ligne à part : il compare l'icône du catalogue à -celle de la définition **par identité**, et c'est le seul test qui détecte un +`manifest.spec.ts` mérite sa ligne à part : c'est le seul test qui détecte un point d'enregistrement perdu dans un conflit. +Après un passage de pnpm à bun, ou si le typecheck se plaint de deux copies +d'une même dépendance, repartir d'un `node_modules` propre : pnpm laissait des +copies imbriquées que bun ne nettoie pas. + +#### Les échecs de tests à ne pas confondre avec une régression + +Comparer avec l'étiquette amont, pas avec zéro. Sur v2.3.0, 19 tests échouent +déjà sans ce fork (Unifi Controller, widgets Custom JSX, Pi-hole, et +`manifest.spec.ts` lui-même, à cause d'une requête Immich absente de +`refetch-intervals.ts`). Pour les lister : + +```bash +git worktree add /tmp/homarr-amont v2.3.0 && (cd /tmp/homarr-amont && bun install && bun run test packages/) +``` + +Deux échecs sont propres au fork, et assumés : + +- `api-key-url.spec.ts` exige une page de documentation homarr.dev pour chaque + intégration ; les nôtres n'en ont pas (`documentationSlug: null`). +- `widget-integration-map.spec.ts` exige que chaque widget accepte l'intégration + `mock`, qui ne sert qu'à la galerie de démonstration de l'amont. + ### Où les conflits vont tomber Le gros du travail vit dans des dossiers neufs — `packages/integrations/src/unifi-os/`, @@ -101,24 +137,22 @@ ajoute une ligne dans une liste que l'amont fait vivre aussi : | `packages/definitions/src/integration.ts` | les deux genres d'intégration | | `packages/definitions/src/widget.ts` | les deux genres de widget | | `packages/definitions/src/widget-integration-map.ts` | l'association widget ↔ intégration | -| `packages/definitions/src/docs/integration-doc-slugs.ts` | les slugs de documentation | -| `packages/definitions/src/docs/widget-doc-slugs.ts` | idem, côté widgets | -| `packages/integrations/src/base/creator.ts` | la construction des classes | +| `packages/definitions/src/docs/widget-doc-slugs.ts` | le slug de documentation des widgets | +| `packages/integrations/src/base/creator.ts` | la construction, en import différé | | `packages/integrations/src/index.ts` | les exports | | `packages/integrations/src/types.ts` | les types réexportés **côté client** | | `packages/api/src/router/widgets/index.ts` | les routeurs tRPC | -| `packages/widgets/src/manifest.ts` | deux cartes distinctes, module et composant | -| `packages/widgets/src/index.tsx` | l'import et l'entrée | -| `packages/widgets/src/catalog.ts` | l'icône | +| `packages/widgets/src/registry.ts` | quatre entrées : import de type, module, type, composant | +| `packages/ui/src/widget-icons.ts` | l'icône | | `packages/widgets/src/refetch-intervals.ts` | l'intervalle de rafraîchissement | -| `apps/nextjs/src/components/integration/integration-grid-shared.ts` | le libellé de catégorie | +| `packages/ui/src/integration-select-grid/integration-grid-shared.ts` | le libellé de catégorie | | `apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-icons.ts` | l'icône du secret | | `packages/translation/src/lang/en.json` | tous les libellés | Deux de ces lignes ne sont vérifiées par **aucun** compilateur, et les perdre dans un conflit passerait tous les tests : -- `integration-grid-shared.ts` est typé `Record` : une entrée +- `integration-grid-shared.ts` (dans `packages/ui` depuis la v2) est typé `Record` : une entrée manquante affiche `UNIFISITEMANAGER` en majuscules collées au lieu du nom. - `en.json` n'est pas typé du tout : une clé perdue affiche son chemin brut. @@ -144,7 +178,7 @@ liste autour. ```bash SKIP_ENV_VALIDATION=true CI=true DISABLE_REDIS_LOGS=true \ - pnpm turbo build --concurrency=1 --filter=@homarr/nextjs... --filter=@homarr/cli + bun run turbo run build --concurrency=1 --filter=@homarr/nextjs... --filter=@homarr/cli ``` `SKIP_ENV_VALIDATION` n'est pas optionnel : le build charge `next.config.ts`, qui diff --git a/ops/assemble-standalone.sh b/ops/assemble-standalone.sh index c50cc6f4b..d92e613b2 100755 --- a/ops/assemble-standalone.sh +++ b/ops/assemble-standalone.sh @@ -3,7 +3,7 @@ # Assemble l'arborescence d'exécution à partir d'un dépôt déjà construit. # # Le dépôt et l'instance qui tourne n'ont PAS la même forme : le clone contient -# des sources et un `apps/nextjs/.next/standalone` ; l'instance attend +# des sources et un `apps/nextjs/.output/standalone` ; l'instance attend # `apps/nextjs/server.js`, `db/migrations/`, `build/better_sqlite3.node` à sa # racine. Ce script fait la conversion — les mêmes COPY que le stage `runner` # du Dockerfile officiel, d'où vient la disposition de /opt/homarr. @@ -11,7 +11,7 @@ # Usage : ops/assemble-standalone.sh # # Construire d'abord : -# pnpm turbo build --filter=@homarr/nextjs... --filter=@homarr/cli +# bun run turbo run build --filter=@homarr/nextjs... --filter=@homarr/cli # set -euo pipefail @@ -20,20 +20,20 @@ REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$REPO" -[ -d apps/nextjs/.next/standalone ] || { - echo "apps/nextjs/.next/standalone absent — construis d'abord :" >&2 - echo " pnpm turbo build --filter=@homarr/nextjs... --filter=@homarr/cli" >&2 +# Depuis la v2, la sortie est .output/standalone. Next écrit encore un +# .next/standalone intermédiaire, incomplet : ne jamais le prendre à la place. +[ -f apps/nextjs/.output/standalone/apps/nextjs/server.js ] || { + echo "apps/nextjs/.output/standalone absent — construis d'abord :" >&2 + echo " bun run turbo run build --filter=@homarr/nextjs... --filter=@homarr/cli" >&2 exit 1 } mkdir -p "$DEST" -# L'ordre suit le Dockerfile : le standalone d'abord, le reste par-dessus. -cp -a apps/nextjs/.next/standalone/. "$DEST/" -mkdir -p "$DEST/apps/nextjs/.next" -cp -a apps/nextjs/.next/static "$DEST/apps/nextjs/.next/static" -cp -a apps/nextjs/public "$DEST/apps/nextjs/public" -cp -a apps/nextjs/next.config.ts apps/nextjs/package.json pnpm-workspace.yaml "$DEST/" +# L'ordre suit le Dockerfile : le standalone d'abord, le reste par-dessus. En v2, +# le standalone embarque déjà .next/static, public, next.config.ts et +# package.json — le Dockerfile ne les copie plus à part. +cp -a apps/nextjs/.output/standalone/. "$DEST/" mkdir -p "$DEST/apps/cli" cp -a packages/cli/cli.cjs "$DEST/apps/cli/cli.cjs" diff --git a/ops/deploy-lxc.sh b/ops/deploy-lxc.sh index 529102c25..0ab0b2cee 100755 --- a/ops/deploy-lxc.sh +++ b/ops/deploy-lxc.sh @@ -39,11 +39,19 @@ echo "Commit déployé : $(git log --oneline -1)" # Le dépôt exige un Node récent (champ engines.node). Le Node par défaut du poste # est plus ancien que ça : sans ce contrôle, l'échec surviendrait au milieu du -# build, avec un message de pnpm qui ne dit pas quoi faire. +# build, avec un message de bun qui ne dit pas quoi faire. required_node="$(grep -oP '^node = "\K[^"]+' "$REPO/mise.toml" 2>/dev/null || echo '24.18.0')" if ! node -e "process.exit(process.versions.node.localeCompare('$required_node', undefined, { numeric: true }) < 0 ? 1 : 0)"; then echo "Node $(node -v) est trop ancien — il en faut au moins v$required_node." >&2 - echo "Par exemple : export PATH=\"\$HOME/.local/share/nvm/v24.20.0/bin:\$PATH\"" >&2 + echo "Par exemple : export PATH=\"\$HOME/.local/share/nvm/v24.21.0/bin:\$PATH\"" >&2 + exit 1 +fi + +# Depuis la v2, le dépôt se construit avec bun (version fixée dans mise.toml). +required_bun="$(grep -oP '^bun = "\K[^"]+' "$REPO/mise.toml" 2>/dev/null || echo '1.4.2')" +if [ "$(bun --version 2>/dev/null)" != "$required_bun" ]; then + echo "bun $required_bun requis (trouvé : $(bun --version 2>/dev/null || echo aucun))." >&2 + echo "Par exemple : npm i -g bun@$required_bun, avec le Node ci-dessus dans le PATH." >&2 exit 1 fi @@ -73,7 +81,7 @@ say "Build" # build valide les variables d'exécution — dont URL, qui n'a aucun sens à la # compilation — et échoue partout où il ne traîne pas un .env à la racine. SKIP_ENV_VALIDATION=true CI=true DISABLE_REDIS_LOGS=true \ - pnpm turbo build --filter=@homarr/nextjs... --filter=@homarr/cli + bun run turbo run build --filter=@homarr/nextjs... --filter=@homarr/cli # --------------------------------------------------------------------------- say "Assemblage de l'arborescence à envoyer"