diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9f7614e5..63cb9b38 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,19 +4,21 @@ on: push: branches: [main] pull_request: + types: [opened, synchronize, reopened, ready_for_review, converted_to_draft, closed] permissions: contents: read concurrency: - group: ${{ github.workflow }}-${{ github.repository }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.repository }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true jobs: build-and-test: + if: ${{ github.event_name != 'pull_request' || (!github.event.pull_request.draft && github.event.action != 'closed') }} runs-on: ubuntu-24.04 timeout-minutes: 30 steps: @@ -51,6 +53,7 @@ jobs: run: pnpm build:demo browser-release-evidence: + if: ${{ github.event_name != 'pull_request' || (!github.event.pull_request.draft && github.event.action != 'closed') }} name: Cross-engine Clipboard / Playwright 1.62.0 runs-on: ubuntu-24.04 timeout-minutes: 60 @@ -84,6 +87,7 @@ jobs: run: pnpm --dir tests/browser exec playwright test --config playwright.config.ts office: + if: ${{ github.event_name != 'pull_request' || (!github.event.pull_request.draft && github.event.action != 'closed') }} name: Office / Python ${{ matrix.python-version }} runs-on: ubuntu-24.04 timeout-minutes: 30 diff --git a/src/workflowExactHead.test.ts b/src/workflowExactHead.test.ts index 828c2828..4718bf47 100644 --- a/src/workflowExactHead.test.ts +++ b/src/workflowExactHead.test.ts @@ -70,9 +70,11 @@ const officeJob = workflowJob(workflow, 'office'); describe('exact-head CI workflow contract', () => { it('cancels only superseded runs for the same repository and PR while keeping full main compatibility coverage', () => { expect(workflow).toContain( - "group: ${{ github.workflow }}-${{ github.repository }}-${{ github.event.pull_request.number || github.ref }}", + "group: ${{ github.workflow }}-${{ github.repository }}-${{ github.event.pull_request.number || github.run_id }}", + ); + expect(workflow).toContain( + "cancel-in-progress: ${{ github.event_name == 'pull_request' }}", ); - expect(workflow).toContain('cancel-in-progress: true'); expect(officeJob).toContain( "python-version: ${{ github.event_name == 'pull_request' && fromJSON('[\"3.14\"]') || fromJSON('[\"3.11\", \"3.12\", \"3.13\", \"3.14\"]') }}", ); @@ -82,6 +84,16 @@ describe('exact-head CI workflow contract', () => { expect(releaseWorkflow).toContain('cancel-in-progress: false'); }); + it('cancels stale PR work and skips inactive pull requests', () => { + expect(workflow).toContain( + 'types: [opened, synchronize, reopened, ready_for_review, converted_to_draft, closed]', + ); + for (const job of [buildJob, browserJob, officeJob]) { + expect(job).toContain('!github.event.pull_request.draft'); + expect(job).toContain("github.event.action != 'closed'"); + } + }); + it('uses a fixed runner and checks out the immutable current PR head in every job', () => { expect(workflow).not.toContain('ubuntu-latest'); for (const job of [buildJob, browserJob, officeJob]) {