From b51f745f66073b936a0dece38ddbc7524433c23e Mon Sep 17 00:00:00 2001 From: Francisco Solla Date: Mon, 17 Aug 2026 04:17:56 -0300 Subject: [PATCH] =?UTF-8?q?fix(ci=20OPS50):=20matrix=20est=C3=A1tica=20[1,?= =?UTF-8?q?2]=20no=20e2e=20(Forgejo=20n=C3=A3o=20passa=20job=20results=20?= =?UTF-8?q?=C3=A0=20expans=C3=A3o=20de=20matrix=20=E2=80=94=20fromJson(nee?= =?UTF-8?q?ds.*)=20vira=20shard=20vazio)=20e=20VITEST=5FMAX=5FWORKERS=3D4?= =?UTF-8?q?=20no=20int=20(8=20CPUs=20do=20runner=20=C3=97=20pool-10=20esto?= =?UTF-8?q?ura=20os=20100=20clients=20do=20Postgres=20do=20servi=C3=A7o)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .forgejo/workflows/ci-pr.yml | 22 ++++++++++++++++++---- vitest.config.mts | 12 ++++++++++-- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/.forgejo/workflows/ci-pr.yml b/.forgejo/workflows/ci-pr.yml index ab6e72ac..72137d16 100644 --- a/.forgejo/workflows/ci-pr.yml +++ b/.forgejo/workflows/ci-pr.yml @@ -179,6 +179,12 @@ jobs: && (needs.knip.result == 'success' || needs.knip.result == 'skipped') && (needs.cycles.result == 'success' || needs.cycles.result == 'skipped') && (needs.unit.result == 'success' || needs.unit.result == 'skipped') + env: + # Self-hosted runner has 8 CPUs; vitest forks ≈ CPUs and each fork holds + # a Payload pool (max 10) → overflows the service Postgres' 100 clients + # ("too many clients already", CI run 180). 4 forks stay well under. + # GitHub's 2–4 vCPU runners keep the CPU-relative default (no env). + VITEST_MAX_WORKERS: 4 services: postgres: image: postgres:17-alpine @@ -281,12 +287,16 @@ jobs: && (needs.knip.result == 'success' || needs.knip.result == 'skipped') && (needs.cycles.result == 'success' || needs.cycles.result == 'skipped') && (needs.unit.result == 'success' || needs.unit.result == 'skipped') - # OPS34: full mode splits across 2 runners (matrix from the scope job); - # selected mode stays on one. fail-fast: false keeps both shards' logs. + # OPS34: full mode splits across 2 runners; selected mode stays on shard 1 + # (shard 2 skips build+test via step `if`). Static [1, 2] — Forgejo 1.22 + # does not pass job results into matrix expansion, so fromJson(needs.*) + # yields an empty shard. Keep the literal in sync with e2eShardConfig in + # scripts/lib/test-affected-core.mjs (ci.yml pins the same [1, 2] / 2). + # fail-fast: false keeps both shards' logs. strategy: fail-fast: false matrix: - shard: ${{ fromJson(needs.scope.outputs.e2e_matrix) }} + shard: [1, 2] env: # Explicit CI workers; the local default stays 2 (playwright.config.ts). PLAYWRIGHT_WORKERS: 2 @@ -336,6 +346,9 @@ jobs: - run: pnpm migrate - run: pnpm db:seed:minimal - name: Build for e2e + # Selected mode only needs shard 1 (a second build for a handful of + # specs is waste). + if: needs.scope.outputs.e2e_mode == 'full' || matrix.shard == 1 run: pnpm build env: NEXT_DIST_DIR: .next/e2e @@ -347,7 +360,8 @@ jobs: run: pnpm test:e2e --shard=${{ matrix.shard }}/${{ needs.scope.outputs.e2e_shards }} - name: E2E tests (manifest-selected specs) - if: needs.scope.outputs.e2e_mode == 'selected' + # Selected specs run once, on shard 1; shard 2 skips (no test step). + if: needs.scope.outputs.e2e_mode == 'selected' && matrix.shard == 1 run: pnpm test:e2e -- ${{ needs.scope.outputs.e2e_specs }} docs-guards: diff --git a/vitest.config.mts b/vitest.config.mts index 6e879666..b7a6e89f 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -10,8 +10,16 @@ import { defineConfig } from 'vitest/config' // 160 clients → "too many clients already"). Do NOT set a literal // `maxWorkers: 8` on CI: Vitest treats that as "use up to 8" even on 2–4 // vCPU runners, which starves shared advisory leases (invite/consent) and -// times out at 15s. Leave CI on Vitest's CPU-relative default. -const maxWorkers = process.env.CI ? undefined : Math.min(8, os.availableParallelism()) +// times out at 15s. Leave CI on Vitest's CPU-relative default — except on +// self-hosted high-core runners (Forgejo homeserver: 8 CPUs → 8 forks × +// pool-10 already overflows the service Postgres' 100 clients), where the +// workflow pins VITEST_MAX_WORKERS=4 (the "too many clients" failure mode +// landed there in CI run 180). +const maxWorkers = process.env.VITEST_MAX_WORKERS + ? Number(process.env.VITEST_MAX_WORKERS) + : process.env.CI + ? undefined + : Math.min(8, os.availableParallelism()) export default defineConfig({ resolve: {