From 229bd4b3ed8c033297fe889324a382aaa76b39d5 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 7 Oct 2026 16:38:14 +0200 Subject: [PATCH] chore: use Bun package management and Turbo remote caching (#6978) * feat: migrate tooling and runtimes to bun * fix: serialize act installs and adapt backup checks * fix: finish bun scripts and rootless act setup * fix: support bun images in runtime benchmarks * fix: keep a single bun toolchain configuration * fix: include docs mascot sources in workshop build * docs: use bun in remaining tool commands * fix: complete bun sqlite development tooling * docs: explain sqlite development adapter * fix: align remaining commands and local ci validation * fix: use renovate regex fallback with bun * fix: finalize bun sqlite connections during cleanup * fix: preserve sqlite foreign key enforcement * fix: align docker build frontends * fix: prepare release versions with bun * Add Bun benchmarks and preserve SQLite connection defaults * Benchmark Bun installs, conflicts and production workloads * Force Bun workspace tools and HTTP/1.1 upstream streaming * Exclude benchmark evidence from Docker contexts * Expose branch benchmarks through CI * Verify hydrated widget data in production benchmarks * Measure image archives and document benchmark protocol * Audit dependency sharing across every workspace * Pin pnpm for nested baseline benchmark scripts * Preserve nested manager pinning on benchmark resume * Include application and runtime image footprints * Fail benchmark gates on candidate command errors * Report complete build overhead and sampled memory bounds * Validate migration comparisons across pinned revisions * Record configurable runtime memory budgets * Retain out-of-memory kills in runtime budget probes * Reject OOM events consistently across runtime metrics * Record complete Bun migration benchmarks * Record memory diagnosis and correct Turbo caching * Use Bun package management while preserving Node runtimes * Keep native build fallbacks and exclude development artifacts * Fix Node ESM metadata and isolate local CI configuration * Measure development performance and isolate act environment * Support isolated environment files in rootless act * Validate the full migration range with act * Preserve native SQLite binding for bundled migrations * Use documented dev defaults and report benchmark scope * Validate dev defaults and isolate restart measurements * Record package-manager and development benchmarks * Keep benchmark measurements and link full command artifacts * Clean up temporary act environment files * Validate Node runtimes in package-manager comparisons * Validate every workspace in manual CI runs * Retain patched nested brace expansion versions * Complete package-manager and Node performance report * Normalize archived benchmark logs * Record final hosted validation * Cache both Next builds with platform isolation * Prime cache with write-only mode * Split Next artifacts below Cloudflare upload limit * Assemble coherent standalone cache outputs * Preserve traced middleware entrypoints * Assemble traced directory links before files * Separate cached dependencies from assembled output * Record signed Turbo cache benchmarks * Remove archived benchmark captures Full benchmark evidence is preserved at 8f7d3bcd14109bfb13fa664d31710b88d820ad66. * Remove migration benchmark harness * fix: correct migration launch and local Act prerequisites * Consolidate Turbo caches and production artifacts * Exclude generated files from Docker cache inputs * fix: address Bun migration review findings * fix: check restored compiler bundle manifests --- .agents/skills/codebase-context/SKILL.md | 6 +- .../references/architecture.md | 12 +- .agents/skills/documentation-sync/SKILL.md | 4 +- .agents/skills/mcp-integration/SKILL.md | 4 +- .dockerignore | 18 +- .github/act/README.md | 14 +- .../extract-build-artifact/action.yaml | 7 - .github/renovate.json5 | 14 +- .github/workflows/autofix.yml | 2 +- .github/workflows/ci.yml | 43 +- .github/workflows/database.yml | 11 +- .github/workflows/deployment-docker-image.yml | 11 +- .github/workflows/deployment-docs.yml | 19 +- .../workflows/docs-update-contributors.yml | 2 +- .github/workflows/docs-update-openapi.yml | 2 +- .github/workflows/on-pr-renovate-validate.yml | 9 +- .github/workflows/on-release.yml | 2 +- .github/workflows/update-contributors.yml | 10 +- .github/workflows/update-integration-list.yml | 2 +- .github/workflows/validate-docs.yml | 27 +- .github/workflows/workshop.yml | 61 +- .gitignore | 6 +- .mcp.json | 4 +- .mise.toml | 2 - .npmrc | 2 - .releaserc.json | 9 +- ...migration_postgresql_generate.run copy.xml | 2 +- .run/db_migration_sqlite_generate.run.xml | 2 +- .run/db_push.run.xml | 2 +- .run/db_studio.run.xml | 2 +- .run/dev.run.xml | 2 +- .run/docker_dev.run.xml | 2 +- .run/format.run.xml | 2 +- .run/format_fix.run.xml | 2 +- .run/test.run.xml | 2 +- .run/test_ui.run.xml | 2 +- .run/typecheck.run.xml | 2 +- .vscode/launch.json | 18 +- AGENTS.md | 35 +- Dockerfile | 86 +- apps/docs/.gitignore | 2 +- apps/docs/README.md | 20 +- .../command-line/development/index.mdx | 12 +- .../docs/docs/advanced/command-line/index.mdx | 6 +- .../advanced/development/getting-started.mdx | 98 +- .../docs/advanced/development/workshop.mdx | 2 +- .../docs/getting-started/installation/helm.md | 317 +- .../getting-started/installation/source.mdx | 16 +- apps/docs/next.config.mjs | 3 + apps/docs/package.json | 7 +- apps/docs/scripts/validate-links.test.ts | 2 +- apps/docs/turbo.json | 33 + apps/nextjs/README.md | 12 +- apps/nextjs/package.json | 12 +- apps/nextjs/scripts/assemble-standalone.mjs | 39 + apps/nextjs/scripts/cache-standalone.mjs | 8 + apps/nextjs/scripts/compile-standalone.mjs | 6 + apps/nextjs/scripts/standalone-artifact.mjs | 82 + apps/nextjs/src/versions/package-reader.ts | 26 +- apps/nextjs/turbo.json | 49 + apps/tasks/package.json | 3 +- apps/websocket/package.json | 3 +- apps/workshop/Dockerfile | 37 +- apps/workshop/README.md | 14 +- apps/workshop/preview-docs.sh | 2 +- apps/workshop/test-image.sh | 2 +- bun.lock | 6444 ++++ bunfig.toml | 7 + deployments/prebuilt-debian/Dockerfile | 12 +- deployments/prebuilt-debian/bun.lock | 92 + deployments/prebuilt-debian/package.json | 11 +- deployments/prebuilt-debian/pnpm-lock.yaml | 287 - .../prebuilt-debian/pnpm-workspace.yaml | 2 - mise.toml | 1 + package.json | 363 +- packages/cli/package.json | 2 +- packages/cli/turbo.json | 8 + packages/custom-widgets/package.json | 4 +- packages/db/package.json | 28 +- packages/db/turbo.json | 8 + packages/definitions/package.json | 4 +- packages/definitions/src/docs/codegen.ts | 118 +- .../src/docs/homarr-docs-sitemap.ts | 367 +- packages/definitions/src/docs/metadata.ts | 55 + .../definitions/src/docs/sitemap-paths.json | 284 + paseo.json | 20 +- patches/dns-caching.patch | 9 + patches/trpc-to-openapi.patch | 6 +- pnpm-lock.yaml | 26484 ---------------- pnpm-workspace.yaml | 331 - scripts/check-custom-widget-bundle.mjs | 3 +- scripts/check-custom-widget-bundle.spec.ts | 5 +- scripts/ci/act.sh | 25 +- scripts/release-version.mjs | 14 + test/renovate.spec.ts | 14 +- tooling/github/docker-build.sh | 11 + tooling/github/setup/action.yml | 63 +- tools/assistant-benchmark/README.md | 2 +- tools/homarr-dev/README.md | 24 +- tools/homarr-dev/internal/cli/doctor.go | 2 +- tools/motion-reel/README.md | 8 +- tools/mysql-to-sqlite/Dockerfile | 12 +- tools/mysql-to-sqlite/README.md | 6 +- tools/mysql-to-sqlite/bun.lock | 39 + tools/mysql-to-sqlite/package-lock.json | 160 - tools/v2-showreel/bun.lock | 104 + tools/v2-showreel/package-lock.json | 627 - tools/v2-showreel/recap/index.html | 4 +- turbo.json | 35 +- 109 files changed, 8507 insertions(+), 28875 deletions(-) delete mode 100644 .mise.toml delete mode 100644 .npmrc create mode 100644 apps/docs/turbo.json create mode 100644 apps/nextjs/scripts/assemble-standalone.mjs create mode 100644 apps/nextjs/scripts/cache-standalone.mjs create mode 100644 apps/nextjs/scripts/compile-standalone.mjs create mode 100644 apps/nextjs/scripts/standalone-artifact.mjs create mode 100644 apps/nextjs/turbo.json create mode 100644 bun.lock create mode 100644 bunfig.toml create mode 100644 deployments/prebuilt-debian/bun.lock delete mode 100644 deployments/prebuilt-debian/pnpm-lock.yaml delete mode 100644 deployments/prebuilt-debian/pnpm-workspace.yaml create mode 100644 packages/cli/turbo.json create mode 100644 packages/db/turbo.json create mode 100644 packages/definitions/src/docs/metadata.ts create mode 100644 packages/definitions/src/docs/sitemap-paths.json create mode 100644 patches/dns-caching.patch delete mode 100644 pnpm-lock.yaml delete mode 100644 pnpm-workspace.yaml create mode 100644 scripts/release-version.mjs create mode 100644 tooling/github/docker-build.sh create mode 100644 tools/mysql-to-sqlite/bun.lock delete mode 100644 tools/mysql-to-sqlite/package-lock.json create mode 100644 tools/v2-showreel/bun.lock delete mode 100644 tools/v2-showreel/package-lock.json diff --git a/.agents/skills/codebase-context/SKILL.md b/.agents/skills/codebase-context/SKILL.md index d7676ad92..61ee9476b 100644 --- a/.agents/skills/codebase-context/SKILL.md +++ b/.agents/skills/codebase-context/SKILL.md @@ -17,11 +17,11 @@ Orient from the current checkout before editing. Treat package manifests, export ## Current toolchain -- Use Node `24.18.0` from `mise.toml` and pnpm `11.15.1` from `package.json`. -- Use pnpm workspaces with Turborepo. Workspace packages use the `@homarr/` scope and catalog-managed dependencies. +- Use Node `24.18.0` for application runtimes and Bun `1.4.2` for package management, pinned in `mise.toml` and `package.json`. +- Use Bun workspaces with Turborepo and a shared hoisted install. Workspace packages use the `@homarr/` scope and catalog-managed dependencies. - Use Next.js App Router, TypeScript, tRPC, Drizzle, Mantine v9, Tabler icons, Jotai, TanStack Query, next-intl, Vitest, and Playwright. - Use oxlint and oxfmt. Mantine is the application UI system; Tailwind is limited to the docs app. -- `pnpm dev` starts only `@homarr/nextjs`. Start a standalone runtime explicitly when the task needs it. +- `bun run dev` starts only `@homarr/nextjs`. Start a standalone runtime explicitly when the task needs it. ## High-value seams diff --git a/.agents/skills/codebase-context/references/architecture.md b/.agents/skills/codebase-context/references/architecture.md index 04f517a4c..9259bed0f 100644 --- a/.agents/skills/codebase-context/references/architecture.md +++ b/.agents/skills/codebase-context/references/architecture.md @@ -18,9 +18,9 @@ | `apps/websocket` | tRPC WebSocket subscriptions on port 3001 | | `apps/workshop` | Go/PocketBase Workshop service and provider integration | -`pnpm dev` runs only `@homarr/nextjs`. Use `pnpm --filter @homarr/tasks dev`, `pnpm --filter @homarr/websocket dev`, or `pnpm dev:docs` when a task needs those runtimes. +`bun run dev` runs only `@homarr/nextjs`. Use `bun run --filter @homarr/tasks dev`, `bun run --filter @homarr/websocket dev`, or `bun run dev:docs` when a task needs those runtimes. -In production, `apps/nextjs/src/instrumentation-node.ts` starts the tasks and WebSocket runtimes inside the Node process. Nginx listens on port 7575, proxies `/websockets` to port 3001, and sends other traffic to port 3000. Redis can run internally or externally. +In production, `apps/nextjs/src/instrumentation-node.ts` starts the tasks and WebSocket runtimes inside the Bun process. Nginx listens on port 7575, proxies `/websockets` to port 3001, and sends other traffic to port 3000. Redis can run internally or externally. ## Package map @@ -34,7 +34,7 @@ In production, `apps/nextjs/src/instrumentation-node.ts` starts the tasks and We ### Data, identity, and transport -- `db`: Drizzle schemas, queries, migrations, and three database drivers. +- `db`: Drizzle schemas, queries, migrations, and SQLite and PostgreSQL drivers. - `auth`: Auth.js/NextAuth configuration, sessions, providers, and API keys. - `api`: tRPC routers, contexts, MCP metadata extraction, OpenAPI, and client/server entrypoints. - `redis`: Redis clients, pub/sub channels, and caches. @@ -57,7 +57,7 @@ In production, `apps/nextjs/src/instrumentation-node.ts` starts the tasks and We - `settings`, `spotlight`, `notifications`, `onboarding`: cross-feature UI flows. - `widgets`: widget definitions, dynamic component loaders, and shared widget UI. - `translation`: next-intl configuration and locale catalogs. -- `cli`: Node operations CLI. `tools/homarr-dev` is the separate Go developer CLI. +- `cli`: Bun operations CLI. `tools/homarr-dev` is the separate Go developer CLI. ## Dependency direction @@ -103,8 +103,8 @@ User routes live below `apps/nextjs/src/app/[locale]/`; the locale segment does ## Commands and conventions - Read current scripts from the root or package `package.json`; avoid caching commands that do not exist. -- Use `pnpm dev` for Next.js, `pnpm dev:docs` for docs, and `pnpm dev:cli -- ` for the Go developer CLI. -- Use `pnpm docker:dev:up` for the Redis development dependency. +- Use `bun run dev` for Next.js, `bun run dev:docs` for docs, and `bun run dev:cli -- ` for the Go developer CLI. +- Use `bun run docker:dev:up` for the Redis development dependency. - Follow the Testing section in `AGENTS.md` for test creation and validation scope. - Use `~/*` only inside the Next.js app. Use public `@homarr/*` entrypoints across package boundaries. - Keep Mantine application styles separate from the Tailwind-based docs app. diff --git a/.agents/skills/documentation-sync/SKILL.md b/.agents/skills/documentation-sync/SKILL.md index ecf88992c..d1bc91e51 100644 --- a/.agents/skills/documentation-sync/SKILL.md +++ b/.agents/skills/documentation-sync/SKILL.md @@ -53,5 +53,5 @@ For a widget: 1. Every passage adds information a user needs and cannot reasonably infer from the interface. Remove obvious, repetitive, or unnecessary prose. 2. Keep names, defaults, paths, screenshots, links, and prerequisites consistent with code. 3. Update every affected page and remove superseded guidance. -4. Run the narrowest useful docs validation. Use `pnpm turbo build --filter=@homarr/docs` when links, MDX, generated definitions, or navigation can fail; otherwise run the docs package formatter on touched files. -5. Treat broken links and anchors as failures; run `pnpm --filter @homarr/docs validate:links` after the static build. +4. Run the narrowest useful docs validation. Use `bun run turbo build --filter=@homarr/docs` when links, MDX, generated definitions, or navigation can fail; otherwise run the docs package formatter on touched files. +5. Treat broken links and anchors as failures; run `bun run --filter @homarr/docs validate:links` after the static build. diff --git a/.agents/skills/mcp-integration/SKILL.md b/.agents/skills/mcp-integration/SKILL.md index 6d7282b61..bdd7e9da1 100644 --- a/.agents/skills/mcp-integration/SKILL.md +++ b/.agents/skills/mcp-integration/SKILL.md @@ -93,6 +93,6 @@ Register the smallest router that owns the enabled procedures. If a parent route 1. Confirm the procedure still enforces its ordinary auth and permission boundary. 2. Confirm `packages/api/src/mcp.ts` eagerly includes the procedure. 3. Confirm the generated tool name, description, and JSON schema are unambiguous. -4. When validating tool-list or extraction changes, use the focused API MCP spec: `pnpm test packages/api/src/test/mcp.spec.ts`. -5. When validating protocol or transport changes, use the focused route spec: `pnpm test apps/nextjs/src/app/api/mcp/[transport]/route.spec.ts`. +4. When validating tool-list or extraction changes, use the focused API MCP spec: `bun run test packages/api/src/test/mcp.spec.ts`. +5. When validating protocol or transport changes, use the focused route spec: `bun run test apps/nextjs/src/app/api/mcp/[transport]/route.spec.ts`. 6. If manually probing `/api/mcp/`, use a scoped API key and avoid printing credentials or secret-bearing results. diff --git a/.dockerignore b/.dockerignore index c0f2129a3..d71b297e3 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,9 +5,18 @@ node_modules npm-debug.log README.md .next +**/.output .turbo -.pnpm-store -**/.pnpm-store +**/.turbo +**/next-env.d.ts +packages/db/migrations/*/migrate.cjs +packages/cli/cli.cjs +apps/tasks/tasks.cjs +apps/tasks/tasks.css +apps/websocket/wssServer.cjs +apps/websocket/wssServer.css +.bun-cache +**/.bun-cache coverage **/coverage **/.docusaurus @@ -23,3 +32,8 @@ apps/nextjs/.next .env .env.* !.env.example + +benchmark-results +scripts/benchmarks/results +**/__pycache__ +**/*.tsbuildinfo diff --git a/.github/act/README.md b/.github/act/README.md index 8bac83dfa..3c9eae371 100644 --- a/.github/act/README.md +++ b/.github/act/README.md @@ -3,18 +3,20 @@ Install [Act](https://nektosact.com/installation/index.html) and ensure Docker is running, then use: ```bash -pnpm ci:act:fast -pnpm ci:act:docker -pnpm ci:act:all -pnpm ci:act:cleanup +bun run ci:act:fast +bun run ci:act:docker +bun run ci:act:all +bun run ci:act:cleanup ``` -`fast` runs the quality gate. `docker` and `all` run the gate followed by the single container build, E2E suite, and memory regression test. `cleanup` validates the manual cleanup path without calling GitHub. The wrapper supports regular clones and Git worktrees, including non-default Docker contexts. Linux dependencies are kept in Docker volumes instead of overwriting host `node_modules`. The first run downloads the Act runner and Playwright browser dependencies. +`fast` runs the database checks and quality gate and requires an `origin/dev` tracking ref. `docker` and `all` use the manual validation event to run those checks, build the container once, and run the converter boot/restart smoke test. `cleanup` validates the manual cleanup path without calling GitHub. The wrapper supports regular clones and Git worktrees, including non-default Docker contexts. Linux dependencies are kept in Docker volumes instead of overwriting host `node_modules`. The first run downloads the Act runner and Playwright browser dependencies. + +For rootless Docker, set `ACT_TESTCONTAINERS_HOST` to a host address reachable from the runner when loopback callbacks are unavailable. Remote caching is optional locally. Copy `.github/act/.secrets.example` to `.github/act/.secrets`, populate it with rotated credentials, and run with: ```bash -ACT_SECRET_FILE=.github/act/.secrets pnpm ci:act:all +ACT_SECRET_FILE=.github/act/.secrets bun run ci:act:all ``` Act never publishes or deletes GHCR images. The secret file is ignored by Git. diff --git a/.github/actions/extract-build-artifact/action.yaml b/.github/actions/extract-build-artifact/action.yaml index 2f0c66c34..663fc0a3b 100644 --- a/.github/actions/extract-build-artifact/action.yaml +++ b/.github/actions/extract-build-artifact/action.yaml @@ -19,11 +19,6 @@ inputs: runs: using: "composite" steps: - - name: Prebuilt debian dependencies - uses: ./.github/actions/prebuilt-debian - id: prebuilt-debian - with: - architecture: ${{ inputs.architecture }} - name: Start docker container for ${{ inputs.architecture }} run: | docker run --name homarr \ @@ -43,8 +38,6 @@ runs: shell: bash - name: Extract source from ${{ inputs.architecture }} container (debian) run: | - docker cp ${{ steps.prebuilt-debian.outputs.path }}/. homarr:/app/build && \ - docker cp ${{ steps.prebuilt-debian.outputs.path }}/. homarr:/app/node_modules/better-sqlite3/build/Release && \ docker exec homarr tar -czf extraction-debian.tar.gz -C /app . && \ docker cp homarr:/app/extraction-debian.tar.gz ${{ runner.temp }}/extraction/${{ inputs.architecture }}/build-debian-${{ inputs.architecture }}.tar.gz shell: bash diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 900c3d97e..716d400d3 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -6,11 +6,6 @@ matchPackageNames: ["^@homarr/"], enabled: false, }, - // Reenable once https://github.com/privatenumber/tsx/issues/737 is fixed - { - matchPackageNames: ["tsx"], - enabled: false, - }, // Reenable once bug with undici v8 is fixed (https://github.com/homarr-labs/homarr/issues/5467) { matchPackageNames: ["undici"], @@ -22,11 +17,10 @@ automerge: true, }, { - // disallow automerge for allowBuilds dependencies (native builds need manual verification) + // disallow automerge for trustedDependencies (native builds need manual verification) matchPackageNames: [ "@tree-sitter-grammars/tree-sitter-yaml", "bcrypt", - "better-sqlite3", "cpu-features", "esbuild", "sharp", @@ -37,12 +31,6 @@ automerge: false, }, ], - // Updates lockfile for prebuilt-debian after if package.json is updated, otherwise only root lockfile is updated - postUpgradeTasks: { - commands: ["cd deployments/prebuilt-debian && pnpm install --ignore-workspace --lockfile-only"], - fileFilters: ["deployments/prebuilt-debian/pnpm-lock.yaml"], - executionMode: "update", - }, updateInternalDeps: true, rangeStrategy: "bump", automerge: false, diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml index f5958a45a..2e71ad5f3 100644 --- a/.github/workflows/autofix.yml +++ b/.github/workflows/autofix.yml @@ -32,4 +32,4 @@ jobs: run: | git diff --name-only --diff-filter=ACMR -z "origin/${BASE_REF}...HEAD" -- \ '*.css' '*.js' '*.json' '*.jsonc' '*.jsx' '*.md' '*.mdx' '*.scss' '*.ts' '*.tsx' '*.yaml' '*.yml' \ - | xargs -0 -r pnpm exec oxfmt --check --no-error-on-unmatched-pattern -- + | xargs -0 -r bun x oxfmt --check --no-error-on-unmatched-pattern -- diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 95d1e1503..d3d9ce861 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,7 +67,6 @@ jobs: TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} TURBO_SCM_BASE: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before || 'HEAD~1' }} TURBO_SCM_HEAD: ${{ github.sha }} - TURBO_PLATFORM: linux/amd64 steps: - name: Require database validation env: @@ -92,26 +91,34 @@ jobs: - name: Setup uses: ./tooling/github/setup + with: + next-cache: "all" + turbo-cache: "true" - name: Copy environment defaults run: cp .env.example .env - - name: Lint, typecheck, and build affected workspaces - run: pnpm turbo run lint typecheck build --affected --continue=dependencies-successful --concurrency=2 + - name: Lint, typecheck, and build workspaces + run: | + scope=(--affected) + if [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" ]]; then + scope=() + fi + bun run turbo run lint typecheck build "${scope[@]}" --continue=dependencies-successful --concurrency=2 - name: Validate workspace configuration - run: pnpm lint:ws + run: bun run lint:ws - name: Validate Custom Widget architecture - run: pnpm check:custom-widgets + run: bun run check:custom-widgets - name: Validate checked-in OpenAPI schema - run: pnpm check:openapi + run: bun run check:openapi - name: Validate Custom Widget bundle budget run: | - pnpm turbo run build --filter=@homarr/nextjs - pnpm check:custom-widget-bundle + bun run turbo run build --filter=@homarr/nextjs + bun run check:custom-widget-bundle container: name: Container and migration smoke @@ -180,14 +187,8 @@ jobs: TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} run: | - secret_args=() - for secret in TURBO_API TURBO_TEAM TURBO_TOKEN TURBO_REMOTE_CACHE_SIGNATURE_KEY; do - if [ -n "${!secret:-}" ]; then - secret_args+=(--secret "id=${secret},env=${secret}") - fi - done - DOCKER_BUILDKIT=1 docker build --platform linux/amd64 \ - --tag homarr-ci --tag homarr-e2e "${secret_args[@]}" . + bash tooling/github/docker-build.sh --platform linux/amd64 \ + --tag homarr-ci --tag homarr-e2e . - name: Cache Playwright browsers if: "!env.ACT" @@ -195,24 +196,24 @@ jobs: uses: actions/cache@v6 with: path: ~/.cache/ms-playwright - key: playwright-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + key: playwright-${{ runner.os }}-${{ hashFiles('bun.lock') }} - name: Install Playwright Chromium if: steps.playwright-cache.outputs.cache-hit != 'true' || env.ACT - run: pnpm exec playwright install --with-deps chromium + run: bun x playwright install --with-deps chromium - name: Install Playwright system deps if: steps.playwright-cache.outputs.cache-hit == 'true' - run: pnpm exec playwright install-deps chromium + run: bun x playwright install-deps chromium - name: Install standalone converter test dependencies - run: npm ci --prefix tools/mysql-to-sqlite + run: bun install --cwd tools/mysql-to-sqlite --frozen-lockfile - name: Verify converted database boots and survives restart env: NODE_ENV: development CI: "true" - run: pnpm exec vitest run --project e2e e2e/mysql-conversion.spec.ts --maxWorkers 1 + run: bun x vitest run --project e2e e2e/mysql-conversion.spec.ts --maxWorkers 1 - name: Upload E2E artifacts if: failure() && !env.ACT diff --git a/.github/workflows/database.yml b/.github/workflows/database.yml index 5692bceef..e414c3137 100644 --- a/.github/workflows/database.yml +++ b/.github/workflows/database.yml @@ -20,6 +20,7 @@ jobs: migrations: ${{ steps.select.outputs.migrations }} steps: - uses: actions/checkout@v7 + if: "!env.ACT" with: fetch-depth: 0 persist-credentials: false @@ -43,7 +44,7 @@ jobs: git diff --name-only -z "$comparison" > "$changed_files" while IFS= read -r -d '' file; do case "$file" in - packages/db/*|packages/core/src/infrastructure/db/*|packages/core/src/infrastructure/certificates/*|packages/auth/*|packages/api/src/router/onboard*|packages/api/src/router/test/onboard*|packages/onboarding/*|apps/nextjs/src/app/api/backup/*|apps/nextjs/src/app/*/init/*|Dockerfile|scripts/run.sh|scripts/entrypoint.sh|deployments/*|package.json|packages/core/package.json|packages/common/package.json|packages/definitions/package.json|packages/server-settings/package.json|packages/validation/package.json|mise.toml|pnpm-lock.yaml|pnpm-workspace.yaml|patches/*|vitest*|tooling/github/*|.github/workflows/database.yml|.github/workflows/ci.yml) + packages/db/*|packages/core/src/infrastructure/db/*|packages/core/src/infrastructure/certificates/*|packages/auth/*|packages/api/src/router/onboard*|packages/api/src/router/test/onboard*|packages/onboarding/*|apps/nextjs/src/app/api/backup/*|apps/nextjs/src/app/*/init/*|Dockerfile|scripts/run.sh|scripts/entrypoint.sh|deployments/*|package.json|packages/core/package.json|packages/common/package.json|packages/definitions/package.json|packages/server-settings/package.json|packages/validation/package.json|mise.toml|bun.lock|bunfig.toml|patches/*|vitest*|tooling/github/*|.github/workflows/database.yml|.github/workflows/ci.yml) migrations=true ;; esac @@ -59,10 +60,11 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@v7 + if: "!env.ACT" with: persist-credentials: false - uses: ./tooling/github/setup - - run: pnpm exec vitest run --project db-node packages/db/test/migration-journal.spec.ts + - run: bun x vitest run --project db-node packages/db/test/migration-journal.spec.ts migrations: name: SQLite and PostgreSQL migrations @@ -72,12 +74,13 @@ jobs: timeout-minutes: 15 steps: - uses: actions/checkout@v7 + if: "!env.ACT" with: persist-credentials: false - uses: ./tooling/github/setup - name: Reject retired database configuration - run: pnpm exec vitest run --project dom packages/core/src/infrastructure/db/env.spec.ts - - run: pnpm exec vitest run --project db-node --project integration packages/db/test/sqlite-migration.spec.ts packages/db/test/postgresql-migration.spec.ts packages/db/proxy-reader.integration.spec.ts --maxWorkers 1 + run: bun x vitest run --project dom packages/core/src/infrastructure/db/env.spec.ts + - run: bun x vitest run --project db-node --project integration packages/db/test/sqlite-migration.spec.ts packages/db/test/postgresql-migration.spec.ts packages/db/proxy-reader.integration.spec.ts --maxWorkers 1 database-gate: name: Database gate diff --git a/.github/workflows/deployment-docker-image.yml b/.github/workflows/deployment-docker-image.yml index ddb986414..e7fb6dcd8 100644 --- a/.github/workflows/deployment-docker-image.yml +++ b/.github/workflows/deployment-docker-image.yml @@ -63,13 +63,10 @@ jobs: with: fetch-depth: 0 persist-credentials: false - - uses: pnpm/action-setup@v6 - if: env.SKIP_RELEASE == 'false' - - uses: actions/setup-node@v6 + - uses: oven-sh/setup-bun@v2 if: env.SKIP_RELEASE == 'false' with: - node-version: 24.18.0 - package-manager-cache: false + bun-version: 1.4.2 - name: Verify major release intent if: env.SKIP_RELEASE == 'false' run: | @@ -92,7 +89,7 @@ jobs: exit 1 - name: Install dependencies if: env.SKIP_RELEASE == 'false' - run: pnpm install --frozen-lockfile + run: bun install --frozen-lockfile - name: Run Semantic Release if: env.SKIP_RELEASE == 'false' env: @@ -102,7 +99,7 @@ jobs: GIT_COMMITTER_NAME: "Releases Homarr" GIT_COMMITTER_EMAIL: "175486441+homarr-releases[bot]@users.noreply.github.com" run: | - pnpm release + bun run release - name: Read semver output # We read the last tag either from the created release or from the current branch, this is to rerun the deployment job for the currently released version when it failed if: env.SKIP_RELEASE == 'false' || github.ref_name == 'main' || github.ref_name == 'beta' diff --git a/.github/workflows/deployment-docs.yml b/.github/workflows/deployment-docs.yml index fa29d53fb..af9e09db0 100644 --- a/.github/workflows/deployment-docs.yml +++ b/.github/workflows/deployment-docs.yml @@ -5,7 +5,13 @@ on: branches: ["dev"] paths: - "apps/docs/**" - - "packages/definitions/src/docs/**" + - "packages/**" + - "tooling/**" + - "tools/motion-reel/three/**" + - "package.json" + - "bun.lock" + - "bunfig.toml" + - "turbo.json" - ".github/workflows/deployment-docs.yml" workflow_dispatch: @@ -33,15 +39,18 @@ jobs: - uses: actions/checkout@v7 - name: Setup uses: ./tooling/github/setup + with: + next-cache: "docs" + turbo-cache: "true" - name: Build docs - run: pnpm turbo build --filter=@homarr/docs + run: bun run turbo run build --filter=@homarr/docs env: CI: "true" - name: Validate exported links and search run: | - pnpm --filter @homarr/docs validate:links - pnpm --filter @homarr/docs verify:search - pnpm --filter @homarr/docs verify:seo + bun run --filter @homarr/docs validate:links + bun run --filter @homarr/docs verify:search + bun run --filter @homarr/docs verify:seo - name: Setup Pages uses: actions/configure-pages@v6 - name: Upload pages artifact diff --git a/.github/workflows/docs-update-contributors.yml b/.github/workflows/docs-update-contributors.yml index 7904f5694..72a669a9e 100644 --- a/.github/workflows/docs-update-contributors.yml +++ b/.github/workflows/docs-update-contributors.yml @@ -28,7 +28,7 @@ jobs: - name: Dump contributors working-directory: apps/docs - run: pnpm api-dump-contributors + run: bun run api-dump-contributors - name: Commit updated contributors uses: EndBug/add-and-commit@v10 diff --git a/.github/workflows/docs-update-openapi.yml b/.github/workflows/docs-update-openapi.yml index 7f90825e2..27b0e1119 100644 --- a/.github/workflows/docs-update-openapi.yml +++ b/.github/workflows/docs-update-openapi.yml @@ -27,7 +27,7 @@ jobs: run: cp .env.example .env - name: Generate and validate OpenAPI spec - run: pnpm scripts:update-openapi + run: bun run scripts:update-openapi - name: Commit updated spec uses: EndBug/add-and-commit@v10 diff --git a/.github/workflows/on-pr-renovate-validate.yml b/.github/workflows/on-pr-renovate-validate.yml index 52e234708..fa85f46d3 100644 --- a/.github/workflows/on-pr-renovate-validate.yml +++ b/.github/workflows/on-pr-renovate-validate.yml @@ -12,8 +12,15 @@ jobs: renovate-validate: runs-on: ubuntu-latest timeout-minutes: 2 + env: + # The optional RE2 addon uses V8 APIs; validation can use JavaScript regexes. + RENOVATE_X_IGNORE_RE2: "true" steps: - uses: actions/checkout@v7 + if: "!env.ACT" + - uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.4.2 - run: | - npx --yes --package renovate -- \ + bun x --package renovate \ renovate-config-validator --strict .github/renovate.json5 diff --git a/.github/workflows/on-release.yml b/.github/workflows/on-release.yml index f23738cd5..08af41f7e 100644 --- a/.github/workflows/on-release.yml +++ b/.github/workflows/on-release.yml @@ -25,7 +25,7 @@ jobs: ref: dev - name: Setup uses: ./tooling/github/setup - - run: pnpm run scripts:update-bug-report-template + - run: bun run scripts:update-bug-report-template env: NEXT_VERSION: ${{ github.event.release.tag_name }} diff --git a/.github/workflows/update-contributors.yml b/.github/workflows/update-contributors.yml index a76841e26..a041a691d 100644 --- a/.github/workflows/update-contributors.yml +++ b/.github/workflows/update-contributors.yml @@ -29,16 +29,12 @@ jobs: uses: actions/checkout@v7 env: GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }} - - - uses: pnpm/action-setup@v6 - - name: Use Node.js - uses: actions/setup-node@v6 + - uses: oven-sh/setup-bun@v2 with: - node-version: 24.18.0 - cache: "pnpm" + bun-version: 1.4.2 - name: Run update script - run: node ./scripts/update-contributors.mjs + run: bun ./scripts/update-contributors.mjs - name: Commit changes env: diff --git a/.github/workflows/update-integration-list.yml b/.github/workflows/update-integration-list.yml index 09d866660..ff633a5d7 100644 --- a/.github/workflows/update-integration-list.yml +++ b/.github/workflows/update-integration-list.yml @@ -33,7 +33,7 @@ jobs: GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }} - name: Setup uses: ./tooling/github/setup - - run: pnpm run scripts:update-readme-integrations + - run: bun run scripts:update-readme-integrations - name: Commit changes env: GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }} diff --git a/.github/workflows/validate-docs.yml b/.github/workflows/validate-docs.yml index f6a8f5800..a6f93f557 100644 --- a/.github/workflows/validate-docs.yml +++ b/.github/workflows/validate-docs.yml @@ -13,10 +13,11 @@ on: - "packages/api/src/**" - "packages/auth/src/**" - "packages/integrations/src/**" + - "tools/motion-reel/three/**" - "tooling/**" - - "pnpm-lock.yaml" + - "bun.lock" - "package.json" - - "pnpm-workspace.yaml" + - "bunfig.toml" - "turbo.json" - ".github/workflows/deployment-docs.yml" - ".github/workflows/validate-docs.yml" @@ -35,20 +36,30 @@ jobs: timeout-minutes: 15 env: SKIP_ENV_VALIDATION: true + TURBO_API: ${{ secrets.TURBO_API }} + TURBO_TEAM: ${{ secrets.TURBO_TEAM }} + TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} steps: - uses: actions/checkout@v7 + if: "!env.ACT" + with: + persist-credentials: false - name: Setup uses: ./tooling/github/setup + with: + next-cache: "docs" + turbo-cache: "true" - name: Validate the published API schema against the application - run: pnpm check:openapi + run: bun run check:openapi - name: Validate browser access and API schema rendering - run: pnpm exec vitest run 'apps/nextjs/src/app/api/[...trpc]/route.spec.ts' apps/docs/src/lib/openapi.spec.ts + run: bun x vitest run 'apps/nextjs/src/app/api/[...trpc]/route.spec.ts' apps/docs/src/lib/openapi.spec.ts - name: Build docs - run: pnpm --filter @homarr/docs build + run: bun run turbo run build --filter=@homarr/docs env: CI: "true" - name: Validate exported links, search, and metadata run: | - pnpm --filter @homarr/docs validate:links - pnpm --filter @homarr/docs verify:search - pnpm --filter @homarr/docs verify:seo + bun run --filter @homarr/docs validate:links + bun run --filter @homarr/docs verify:search + bun run --filter @homarr/docs verify:seo diff --git a/.github/workflows/workshop.yml b/.github/workflows/workshop.yml index 330ce9b15..aff27071c 100644 --- a/.github/workflows/workshop.yml +++ b/.github/workflows/workshop.yml @@ -4,6 +4,7 @@ on: pull_request: paths: - ".github/workflows/workshop.yml" + - "tooling/github/**" - "apps/workshop/**" - "apps/docs/**" - "packages/common/**" @@ -20,14 +21,14 @@ on: - "tooling/typescript/**" - "patches/**" - "package.json" - - "pnpm-lock.yaml" - - "pnpm-workspace.yaml" + - "bun.lock" + - "bunfig.toml" - "turbo.json" - - ".npmrc" push: branches: [dev, v2, release/v2, main] paths: - ".github/workflows/workshop.yml" + - "tooling/github/**" - "apps/workshop/**" - "apps/docs/**" - "packages/common/**" @@ -44,10 +45,9 @@ on: - "tooling/typescript/**" - "patches/**" - "package.json" - - "pnpm-lock.yaml" - - "pnpm-workspace.yaml" + - "bun.lock" + - "bunfig.toml" - "turbo.json" - - ".npmrc" permissions: contents: read @@ -72,10 +72,44 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v7 + if: "!env.ACT" + with: + persist-credentials: false - uses: actions/setup-node@v6 with: node-version: 24.18.0 - - name: Build and exercise the combined production image + - name: Set up Docker Buildx + if: "!env.ACT" + uses: docker/setup-buildx-action@v4 + - name: Build the production image + if: "!env.ACT" + uses: docker/build-push-action@v7 + with: + context: . + file: apps/workshop/Dockerfile + target: production + platforms: linux/${{ matrix.arch }} + load: true + tags: homarr-workshop:smoke + cache-from: type=gha,scope=workshop-linux-${{ matrix.arch }} + cache-to: type=gha,scope=workshop-linux-${{ matrix.arch }},mode=max + secrets: | + TURBO_API=${{ secrets.TURBO_API }} + TURBO_TEAM=${{ secrets.TURBO_TEAM }} + TURBO_TOKEN=${{ secrets.TURBO_TOKEN }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY=${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + - name: Exercise the production image + if: "!env.ACT" + env: + WORKSHOP_IMAGE_TEST_IMAGE: homarr-workshop:smoke + run: sh apps/workshop/test-image.sh + - name: Build and exercise the production image with Act + if: env.ACT + env: + TURBO_API: ${{ secrets.TURBO_API }} + TURBO_TEAM: ${{ secrets.TURBO_TEAM }} + TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} run: sh apps/workshop/test-image.sh validate: @@ -83,6 +117,7 @@ jobs: timeout-minutes: 5 steps: - uses: actions/checkout@v7 + if: "!env.ACT" - run: docker compose --env-file apps/workshop/.env.staging.example -f apps/workshop/docker-compose.staging.yml config --quiet publish-amd64: @@ -97,6 +132,7 @@ jobs: digest: ${{ steps.build.outputs.digest }} steps: - uses: actions/checkout@v7 + if: "!env.ACT" - uses: docker/setup-buildx-action@v4 - uses: docker/login-action@v4 with: @@ -113,6 +149,11 @@ jobs: outputs: type=image,"name=ghcr.io/homarr-labs/workshop",push-by-digest=true,name-canonical=true,push=true cache-from: type=gha,scope=workshop-linux-amd64 cache-to: type=gha,scope=workshop-linux-amd64,mode=max + secrets: | + TURBO_API=${{ secrets.TURBO_API }} + TURBO_TEAM=${{ secrets.TURBO_TEAM }} + TURBO_TOKEN=${{ secrets.TURBO_TOKEN }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY=${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} publish-arm64: if: github.event_name == 'push' && (github.ref_name == 'v2' || github.ref_name == 'release/v2' || github.ref_name == 'main') @@ -126,6 +167,7 @@ jobs: digest: ${{ steps.build.outputs.digest }} steps: - uses: actions/checkout@v7 + if: "!env.ACT" - uses: docker/setup-buildx-action@v4 - uses: docker/login-action@v4 with: @@ -142,6 +184,11 @@ jobs: outputs: type=image,"name=ghcr.io/homarr-labs/workshop",push-by-digest=true,name-canonical=true,push=true cache-from: type=gha,scope=workshop-linux-arm64 cache-to: type=gha,scope=workshop-linux-arm64,mode=max + secrets: | + TURBO_API=${{ secrets.TURBO_API }} + TURBO_TEAM=${{ secrets.TURBO_TEAM }} + TURBO_TOKEN=${{ secrets.TURBO_TOKEN }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY=${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} publish: if: github.event_name == 'push' && (github.ref_name == 'v2' || github.ref_name == 'release/v2' || github.ref_name == 'main') diff --git a/.gitignore b/.gitignore index 8c4d8f8df..d53892e35 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ # dependencies node_modules -.pnpm-store/ +.bun-cache/ .pnp .pnp.js .idea/ @@ -36,7 +36,7 @@ tools/homarr-dev/homarr-dev npm-debug.log* yarn-debug.log* yarn-error.log* -.pnpm-debug.log* +bun-debug.log* # local env files .env @@ -81,7 +81,7 @@ skills-lock.json # docusaurus apps/docs/.docusaurus apps/docs/build -.pnpm-store +.bun-cache benchmark-results # local performance investigation (never ship benchmark data or restored backups) diff --git a/.mcp.json b/.mcp.json index 730f3c96a..47abfd7b4 100644 --- a/.mcp.json +++ b/.mcp.json @@ -1,8 +1,8 @@ { "mcpServers": { "mantine": { - "command": "npx", - "args": ["-y", "@mantine/mcp-server@9.6.0"] + "command": "bun", + "args": ["x", "@mantine/mcp-server@9.6.0"] } } } diff --git a/.mise.toml b/.mise.toml deleted file mode 100644 index d6bd41fc8..000000000 --- a/.mise.toml +++ /dev/null @@ -1,2 +0,0 @@ -[tools] -node = "24.18.0" diff --git a/.npmrc b/.npmrc deleted file mode 100644 index c5e4cd466..000000000 --- a/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -# pnpm v11: non-auth settings moved to pnpm-workspace.yaml -# Keep this file for any future registry/auth configuration diff --git a/.releaserc.json b/.releaserc.json index 0f2b07b43..0ee572754 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -26,16 +26,11 @@ "changelogFile": "CHANGELOG.md" } ], - [ - "@semantic-release/npm", - { - "npmPublish": false - } - ], + "./scripts/release-version.mjs", [ "@semantic-release/git", { - "assets": ["package.json", "CHANGELOG.md"], + "assets": ["package.json", "bun.lock", "CHANGELOG.md"], "message": "chore(release): ${nextRelease.version} [skip ci]" } ], diff --git a/.run/db_migration_postgresql_generate.run copy.xml b/.run/db_migration_postgresql_generate.run copy.xml index 4bc02bdba..002a74fef 100644 --- a/.run/db_migration_postgresql_generate.run copy.xml +++ b/.run/db_migration_postgresql_generate.run copy.xml @@ -6,7 +6,7 @@