From 79f88dc3b8dba559d9795472630fca3f9f9c165f Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 21 May 2026 14:11:27 +0200 Subject: [PATCH] ci: add --affected filtering and fix Turbo cache invalidation (#5740) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ci: add --affected filtering and fix Turbo cache invalidation - Remove globalDependencies **/.env which invalidated all caches on any .env change - Move 40+ env vars from globalEnv to build-specific env (lint/format/typecheck don't need DB_URL etc.) - Add per-task inputs with test file exclusions so test changes don't trigger build/typecheck - Enable affectedUsingTaskInputs for task-level --affected detection - Add --affected to all turbo commands in CI (lint, format, typecheck, build) - Add fetch-depth: 0 for proper git history comparison - Add Docker Buildx + GHA layer caching for E2E builds * ci: add Cloudflare remote cache for Turborepo Configure turborepo-remote-cache-cloudflare as the remote cache backend. This commit can be reverted independently to disable remote caching. * fix(ci): set TURBO_SCM_BASE for --affected to work in PRs Turbo defaults to comparing against `main`, but PRs target `dev`. Without explicit base/head refs, --affected falls back to running all tasks. Use the PR base SHA for pull_requests, the before SHA for pushes, and HEAD~1 as a last resort. * perf(typecheck): exclude bundled .cjs/.css from tsc websocket (835K lines) and tasks (755K lines) had bundled output files being typechecked due to `include: ["."]` in their tsconfig. Full typecheck drops from ~70s to ~26s. * perf(turbo): scope topo task inputs to package.json only The topo virtual task had no explicit inputs, defaulting to all files. This caused any source change to cascade cache invalidation through all dependent packages via ^topo. Since topo is only for dependency ordering, its hash should only change when dependencies change. * fix(turbo): disable remote cache signature verification The cache lives on a private CF worker, signature verification just adds noise without security benefit. * fix(turbo): remove runtime env vars from build cache key These env vars (DB_*, AUTH_*, DOCKER_*, etc.) are all runtime configuration provided by users when running the Docker container. They don't influence the build output since Next.js standalone mode reads process.env at runtime and SKIP_ENV_VALIDATION=true skips validation during build. Listing them in build.env caused unnecessary cache busting in local dev. Also restores coverage report comments per review feedback. * fix(turbo): include test files in typecheck cache inputs Test files must be typechecked — excluding them from typecheck inputs caused changed tests to skip type validation. --- .env.example | 8 +++++ .github/workflows/code-quality.yml | 29 ++++++++++++--- apps/tasks/tsconfig.json | 2 +- apps/websocket/tsconfig.json | 2 +- turbo.json | 57 ++++++------------------------ 5 files changed, 45 insertions(+), 53 deletions(-) diff --git a/.env.example b/.env.example index a11cff63f..318b171e1 100644 --- a/.env.example +++ b/.env.example @@ -41,6 +41,14 @@ DB_URL='FULL_PATH_TO_YOUR_SQLITE_DB_FILE' TURBO_TELEMETRY_DISABLED=1 +# Turborepo remote cache (optional, for faster CI/local builds) +# Uncomment and fill in to enable remote caching locally. +# CI uses GitHub secrets for these values automatically. +# TURBO_API=https://your-cache-worker.workers.dev +# TURBO_TEAM=team_your_team +# TURBO_TOKEN=your-turbo-token +# TURBO_REMOTE_CACHE_SIGNATURE_KEY=your-signature-key + # Comma-separated paths to Docker-compatible Unix sockets. # Useful for connecting to multiple runtimes (Docker + Podman) simultaneously. # When unset and no TCP hosts configured, defaults to /var/run/docker.sock. diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 5dc6df825..e972a1b0c 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -15,6 +15,13 @@ concurrency: env: FORCE_COLOR: 3 + 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 }} + TURBO_SCM_BASE: ${{ github.event.pull_request.base.sha || github.event.before || 'HEAD~1' }} + TURBO_SCM_HEAD: ${{ github.sha }} jobs: lint: @@ -22,6 +29,8 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@v6 + with: + fetch-depth: 0 - name: Setup uses: ./tooling/github/setup @@ -31,31 +40,35 @@ jobs: run: cp .env.example .env - name: Lint - run: pnpm lint && pnpm lint:ws + run: pnpm turbo lint --affected && pnpm lint:ws format: runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v6 + with: + fetch-depth: 0 - name: Setup uses: ./tooling/github/setup - name: Format - run: pnpm format + run: pnpm turbo format --affected --continue -- --cache --cache-location node_modules/.cache/.prettiercache typecheck: runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v6 + with: + fetch-depth: 0 - name: Setup uses: ./tooling/github/setup - name: Typecheck - run: pnpm typecheck + run: pnpm turbo typecheck --affected test: runs-on: ubuntu-latest @@ -78,11 +91,12 @@ jobs: e2e: runs-on: ubuntu-latest timeout-minutes: 15 - steps: - uses: actions/checkout@v6 - name: Setup uses: ./tooling/github/setup + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 - name: Build docker image id: build-docker-image uses: docker/build-push-action@v7 @@ -90,8 +104,11 @@ jobs: platforms: linux/amd64 context: . push: false + load: true tags: homarr-e2e network: host + cache-from: type=gha + cache-to: type=gha,mode=max env: SKIP_ENV_VALIDATION: true - name: Install playwright browsers @@ -105,10 +122,12 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@v6 + with: + fetch-depth: 0 - name: Setup uses: ./tooling/github/setup - name: Copy env shell: bash run: cp .env.example .env - name: Build - run: pnpm build + run: pnpm turbo build --affected diff --git a/apps/tasks/tsconfig.json b/apps/tasks/tsconfig.json index 51e14eb17..a7d26c2c3 100644 --- a/apps/tasks/tsconfig.json +++ b/apps/tasks/tsconfig.json @@ -9,5 +9,5 @@ "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" }, "include": ["."], - "exclude": ["node_modules"] + "exclude": ["node_modules", "*.cjs", "*.css"] } diff --git a/apps/websocket/tsconfig.json b/apps/websocket/tsconfig.json index 51e14eb17..a7d26c2c3 100644 --- a/apps/websocket/tsconfig.json +++ b/apps/websocket/tsconfig.json @@ -9,5 +9,5 @@ "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" }, "include": ["."], - "exclude": ["node_modules"] + "exclude": ["node_modules", "*.cjs", "*.css"] } diff --git a/turbo.json b/turbo.json index 33b661f69..b43619d8d 100644 --- a/turbo.json +++ b/turbo.json @@ -1,57 +1,19 @@ { "$schema": "https://turborepo.org/schema.json", - "globalDependencies": ["**/.env"], - "globalEnv": [ - "AUTH_LDAP_BASE", - "AUTH_LDAP_BIND_DN", - "AUTH_LDAP_BIND_PASSWORD", - "AUTH_LDAP_GROUP_CLASS", - "AUTH_LDAP_GROUP_FILTER_EXTRA_ARG", - "AUTH_LDAP_GROUP_MEMBER_ATTRIBUTE", - "AUTH_LDAP_GROUP_MEMBER_USER_ATTRIBUTE", - "AUTH_LDAP_SEARCH_SCOPE", - "AUTH_LDAP_URI", - "AUTH_OIDC_CLIENT_ID", - "AUTH_OIDC_CLIENT_NAME", - "AUTH_OIDC_CLIENT_SECRET", - "AUTH_OIDC_FORCE_USERINFO", - "AUTH_OIDC_ISSUER", - "AUTH_OIDC_SCOPE_OVERWRITE", - "AUTH_OIDC_GROUPS_ATTRIBUTE", - "AUTH_OIDC_NAME_ATTRIBUTE_OVERWRITE", - "AUTH_LDAP_USERNAME_ATTRIBUTE", - "AUTH_LDAP_USER_MAIL_ATTRIBUTE", - "AUTH_LDAP_USERNAME_FILTER_EXTRA_ARG", - "AUTH_OIDC_AUTO_LOGIN", - "AUTH_LOGOUT_REDIRECT_URL", - "AUTH_PROVIDERS", - "AUTH_SESSION_EXPIRY_TIME", - "CI", - "DISABLE_REDIS_LOGS", - "DB_URL", - "DB_HOST", - "DB_USER", - "DB_PASSWORD", - "DB_NAME", - "DB_PORT", - "DB_DRIVER", - "DOCKER_HOSTNAMES", - "DOCKER_PORTS", - "DOCKER_SOCKET_PATHS", - "NODE_ENV", - "PORT", - "LOCAL_CERTIFICATE_PATH", - "LOG_LEVEL", - "SECRET_ENCRYPTION_KEY", - "SKIP_ENV_VALIDATION" - ], + "remoteCache": { "signature": false }, + "globalEnv": ["CI", "NODE_ENV", "SKIP_ENV_VALIDATION"], "ui": "stream", + "futureFlags": { + "affectedUsingTaskInputs": true + }, "tasks": { "topo": { - "dependsOn": ["^topo"] + "dependsOn": ["^topo"], + "inputs": ["package.json"] }, "build": { "dependsOn": ["^build"], + "inputs": ["$TURBO_DEFAULT$", "!**/*.test.ts", "!**/*.test.tsx", "!**/*.spec.ts", "!**/__tests__/**"], "outputs": [".next/**", "!.next/cache/**", "next-env.d.ts", ".output/**", ".vercel/output/**"] }, "dev": { @@ -59,15 +21,18 @@ "cache": false }, "format": { + "inputs": ["$TURBO_DEFAULT$"], "outputs": ["node_modules/.cache/.prettiercache"], "outputLogs": "new-only" }, "lint": { "dependsOn": ["^topo"], + "inputs": ["$TURBO_DEFAULT$"], "outputs": ["node_modules/.cache/.eslintcache"] }, "typecheck": { "dependsOn": ["^topo"], + "inputs": ["$TURBO_DEFAULT$"], "outputs": ["node_modules/.cache/tsbuildinfo.json"] }, "clean": {