From 8d9e4136f1c5ee2b98f9c4ed56afb5ac1318e93b Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 1 Aug 2026 06:25:05 +0000 Subject: [PATCH 1/2] =?UTF-8?q?OPS9=20=E2=80=94=20CI=20fail-fast:=20cancel?= =?UTF-8?q?=20workflow=20when=20any=20parallel=20job=20fails?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add composite action wrapping styfle/cancel-workflow-action@0.12.1 and invoke it with if: failure() on every parallel job in ci-pr.yml and ci.yml. Workflow-level actions: write permission enables cancellation. Document fail-fast behavior in docs/AGENT-OPS.md CI table. Closes #52 Co-authored-by: Francisco Solla --- .../cancel-workflow-on-failure/action.yml | 7 ++++ .github/workflows/ci-pr.yml | 41 +++++++++++++++++-- .github/workflows/ci.yml | 16 ++++++++ docs/AGENT-OPS.md | 4 +- 4 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 .github/actions/cancel-workflow-on-failure/action.yml diff --git a/.github/actions/cancel-workflow-on-failure/action.yml b/.github/actions/cancel-workflow-on-failure/action.yml new file mode 100644 index 00000000..a3fadab8 --- /dev/null +++ b/.github/actions/cancel-workflow-on-failure/action.yml @@ -0,0 +1,7 @@ +name: Cancel workflow on failure +description: Cancels the entire workflow run when invoked after a job failure (fail-fast). +runs: + using: composite + steps: + - name: Cancel workflow run + uses: styfle/cancel-workflow-action@0.12.1 diff --git a/.github/workflows/ci-pr.yml b/.github/workflows/ci-pr.yml index 2b264d42..15024065 100644 --- a/.github/workflows/ci-pr.yml +++ b/.github/workflows/ci-pr.yml @@ -18,6 +18,11 @@ concurrency: group: ci-pr-${{ github.event.pull_request.number }} cancel-in-progress: true +permissions: + contents: read + actions: write + pull-requests: read + env: DATABASE_URL: postgresql://teqo:teqo@localhost:5432/teqo_test PAYLOAD_SECRET: test-only-secret-not-used-in-production @@ -55,6 +60,9 @@ jobs: echo "test_mode=$(echo "$result" | jq -r .test.mode)" >> "$GITHUB_OUTPUT" echo "e2e_mode=$(echo "$result" | jq -r .e2e.mode)" >> "$GITHUB_OUTPUT" echo "e2e_specs=$(echo "$result" | jq -r '[.e2e.specs[] | "tests/e2e/" + . + ".e2e.spec.ts"] | join(" ")')" >> "$GITHUB_OUTPUT" + - name: Cancel workflow on failure + if: failure() + uses: ./.github/actions/cancel-workflow-on-failure lint: runs-on: ubuntu-latest @@ -70,6 +78,9 @@ jobs: - name: Check test file locations run: node scripts/check-test-locations.mjs - run: pnpm lint + - name: Cancel workflow on failure + if: failure() + uses: ./.github/actions/cancel-workflow-on-failure format: runs-on: ubuntu-latest @@ -83,6 +94,9 @@ jobs: cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm format:check + - name: Cancel workflow on failure + if: failure() + uses: ./.github/actions/cancel-workflow-on-failure typecheck: runs-on: ubuntu-latest @@ -98,6 +112,9 @@ jobs: cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm typecheck + - name: Cancel workflow on failure + if: failure() + uses: ./.github/actions/cancel-workflow-on-failure knip: runs-on: ubuntu-latest @@ -113,6 +130,9 @@ jobs: cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm exec knip + - name: Cancel workflow on failure + if: failure() + uses: ./.github/actions/cancel-workflow-on-failure cycles: runs-on: ubuntu-latest @@ -128,6 +148,9 @@ jobs: cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm check:cycles + - name: Cancel workflow on failure + if: failure() + uses: ./.github/actions/cancel-workflow-on-failure unit: runs-on: ubuntu-latest @@ -152,6 +175,9 @@ jobs: - name: Unit tests (changed since PR base) if: needs.scope.outputs.test_mode == 'changed' run: pnpm test:unit -- --changed origin/${{ github.base_ref }} --passWithNoTests + - name: Cancel workflow on failure + if: failure() + uses: ./.github/actions/cancel-workflow-on-failure int: runs-on: ubuntu-latest @@ -201,6 +227,9 @@ jobs: - name: Integration tests (changed since PR base) if: needs.scope.outputs.test_mode == 'changed' run: pnpm test:int -- --changed origin/${{ github.base_ref }} --passWithNoTests + - name: Cancel workflow on failure + if: failure() + uses: ./.github/actions/cancel-workflow-on-failure build: runs-on: ubuntu-latest @@ -240,6 +269,9 @@ jobs: - run: pnpm install --frozen-lockfile - name: Build (against the local service database) run: pnpm build + - name: Cancel workflow on failure + if: failure() + uses: ./.github/actions/cancel-workflow-on-failure e2e: runs-on: ubuntu-latest @@ -295,13 +327,13 @@ jobs: - name: E2E tests (manifest-selected specs) if: needs.scope.outputs.e2e_mode == 'selected' run: pnpm test:e2e -- ${{ needs.scope.outputs.e2e_specs }} + - name: Cancel workflow on failure + if: failure() + uses: ./.github/actions/cancel-workflow-on-failure migration-lock: runs-on: ubuntu-latest timeout-minutes: 5 - permissions: - contents: read - pull-requests: read steps: - uses: actions/checkout@v5 - name: Count open PRs touching schema files @@ -317,6 +349,9 @@ jobs: echo "::error::More than one open PR touches src/migrations/ or payload-types.ts. Merge or close the other first." exit 1 fi + - name: Cancel workflow on failure + if: failure() + uses: ./.github/actions/cancel-workflow-on-failure checks: name: checks diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 34747815..da6d8b2b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,10 @@ concurrency: group: main-verify cancel-in-progress: false +permissions: + contents: read + actions: write + env: DATABASE_URL: postgresql://teqo:teqo@localhost:5432/teqo_test PAYLOAD_SECRET: test-only-secret-not-used-in-production @@ -37,6 +41,9 @@ jobs: - run: pnpm exec knip - run: pnpm check:cycles - run: pnpm test:unit + - name: Cancel workflow on failure + if: failure() + uses: ./.github/actions/cancel-workflow-on-failure int: runs-on: ubuntu-latest @@ -66,6 +73,9 @@ jobs: - run: pnpm migrate - run: pnpm db:seed:minimal - run: pnpm test:int + - name: Cancel workflow on failure + if: failure() + uses: ./.github/actions/cancel-workflow-on-failure build: runs-on: ubuntu-latest @@ -94,6 +104,9 @@ jobs: - run: pnpm install --frozen-lockfile - name: Build (against the local service database) run: pnpm build + - name: Cancel workflow on failure + if: failure() + uses: ./.github/actions/cancel-workflow-on-failure e2e: runs-on: ubuntu-latest @@ -130,6 +143,9 @@ jobs: NEXT_DIST_DIR: .next/e2e - name: E2E tests (full suite) run: pnpm test:e2e + - name: Cancel workflow on failure + if: failure() + uses: ./.github/actions/cancel-workflow-on-failure checks: name: checks diff --git a/docs/AGENT-OPS.md b/docs/AGENT-OPS.md index d7ff20f9..be176801 100644 --- a/docs/AGENT-OPS.md +++ b/docs/AGENT-OPS.md @@ -58,8 +58,8 @@ Labels: `ready|in-progress|blocked|done|in-prod`, `prio:*`, `kind:*`, `needs:*`. | Workflow | Trigger | Banco | Passos | | ------------------------------ | -------------------------------------- | ------------------- | ------------------------------------------------------------------------- | -| `ci-pr.yml` | PR → `main` | service Postgres 17 | Fase 1 barata → fase 2 cara; skips via `ci-scope.mjs`; rollup `checks` | -| `ci.yml` | push / dispatch `main` | service Postgres | Full sempre → `deploy` (`vercel deploy --prod`) → `requeue` se HEAD andou | +| `ci-pr.yml` | PR → `main` | service Postgres 17 | Fase 1 barata → fase 2 cara; skips via `ci-scope.mjs`; fail-fast cancela o run no 1º job vermelho; rollup `checks` | +| `ci.yml` | push / dispatch `main` | service Postgres | Full sempre; fail-fast cancela o run no 1º job vermelho → `deploy` (`vercel deploy --prod`) → `requeue` se HEAD andou | | `issue-done-on-main-merge.yml` | PR merged → `main` | — | `in-progress` → `done` + `in-prod` | | `agent-pr-ready-automerge.yml` | PR `cursor/*` → `main` (open/sync/…) | — | Draft→Ready + `gh pr merge --auto --merge` (safety net; audit incluso) | | `agent-pool.yml` | schedule / PR closed `main` / dispatch | — | Supervisor do pool (`POOL_GITHUB_TOKEN`) | From d5d814e1d946516265e39a3a27efe3e250623fe5 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 1 Aug 2026 06:25:47 +0000 Subject: [PATCH 2/2] =?UTF-8?q?OPS9=20=E2=80=94=20format=20AGENT-OPS.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/AGENT-OPS.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/AGENT-OPS.md b/docs/AGENT-OPS.md index be176801..e86f0a4c 100644 --- a/docs/AGENT-OPS.md +++ b/docs/AGENT-OPS.md @@ -56,13 +56,13 @@ Labels: `ready|in-progress|blocked|done|in-prod`, `prio:*`, `kind:*`, `needs:*`. ## CI por alvo -| Workflow | Trigger | Banco | Passos | -| ------------------------------ | -------------------------------------- | ------------------- | ------------------------------------------------------------------------- | -| `ci-pr.yml` | PR → `main` | service Postgres 17 | Fase 1 barata → fase 2 cara; skips via `ci-scope.mjs`; fail-fast cancela o run no 1º job vermelho; rollup `checks` | +| Workflow | Trigger | Banco | Passos | +| ------------------------------ | -------------------------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------- | +| `ci-pr.yml` | PR → `main` | service Postgres 17 | Fase 1 barata → fase 2 cara; skips via `ci-scope.mjs`; fail-fast cancela o run no 1º job vermelho; rollup `checks` | | `ci.yml` | push / dispatch `main` | service Postgres | Full sempre; fail-fast cancela o run no 1º job vermelho → `deploy` (`vercel deploy --prod`) → `requeue` se HEAD andou | -| `issue-done-on-main-merge.yml` | PR merged → `main` | — | `in-progress` → `done` + `in-prod` | -| `agent-pr-ready-automerge.yml` | PR `cursor/*` → `main` (open/sync/…) | — | Draft→Ready + `gh pr merge --auto --merge` (safety net; audit incluso) | -| `agent-pool.yml` | schedule / PR closed `main` / dispatch | — | Supervisor do pool (`POOL_GITHUB_TOKEN`) | +| `issue-done-on-main-merge.yml` | PR merged → `main` | — | `in-progress` → `done` + `in-prod` | +| `agent-pr-ready-automerge.yml` | PR `cursor/*` → `main` (open/sync/…) | — | Draft→Ready + `gh pr merge --auto --merge` (safety net; audit incluso) | +| `agent-pool.yml` | schedule / PR closed `main` / dispatch | — | Supervisor do pool (`POOL_GITHUB_TOKEN`) | Fast gate: `pnpm gate:fast`. Push: `pnpm push`.