diff --git a/.github/workflows/publish-playwright-report.yml b/.github/workflows/publish-playwright-report.yml index 4d3dc4c..95b0aeb 100644 --- a/.github/workflows/publish-playwright-report.yml +++ b/.github/workflows/publish-playwright-report.yml @@ -44,9 +44,11 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} RUN_ID: ${{ github.event.workflow_run.id }} + RUN_ATTEMPT: ${{ github.event.workflow_run.run_attempt }} shell: bash run: | - result="$(gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}/jobs?per_page=100" \ + # Read the attempt that finished: a re-run already in progress has no conclusion yet. + result="$(gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}/attempts/${RUN_ATTEMPT}/jobs?per_page=100" \ --jq '[.jobs[] | select(.name == "Web E2E / Web E2E") | .conclusion] | unique | if length == 1 then .[0] else error("expected exactly one Playwright job") end')" case "$result" in success|failure) ;; diff --git a/.github/workflows/publish-server-image.yml b/.github/workflows/publish-server-image.yml index 0be2989..bded3e7 100644 --- a/.github/workflows/publish-server-image.yml +++ b/.github/workflows/publish-server-image.yml @@ -174,7 +174,7 @@ jobs: runs-on: ${{ matrix.runner }} timeout-minutes: 90 concurrency: - group: publish-server-image-build-${{ github.ref }} + group: publish-server-image-build-${{ github.ref }}-${{ matrix.name }}-${{ matrix.arch }} cancel-in-progress: ${{ github.ref == 'refs/heads/main' }} permissions: contents: read @@ -261,7 +261,7 @@ jobs: runs-on: [self-hosted, evoo-ci, Linux] timeout-minutes: 15 concurrency: - group: publish-server-image-publish-${{ github.ref == 'refs/heads/main' && 'main' || github.ref }} + group: publish-server-image-publish-${{ github.ref == 'refs/heads/main' && 'main' || github.ref }}-${{ matrix.name }} cancel-in-progress: false permissions: contents: read diff --git a/infra/updater/src/publish-workflow.test.ts b/infra/updater/src/publish-workflow.test.ts index 779dcd8..4f32905 100644 --- a/infra/updater/src/publish-workflow.test.ts +++ b/infra/updater/src/publish-workflow.test.ts @@ -9,6 +9,7 @@ const workflowText = readFileSync( ); interface WorkflowJob { if?: string; + concurrency?: { group?: string }; needs?: string; "runs-on"?: string; strategy?: { matrix?: { arch?: string[]; include?: Array> } }; @@ -106,9 +107,13 @@ describe("server image publish workflow", () => { expect(workflowText).toContain( "cancel-in-progress: ${{ github.event_name == 'pull_request' }}", ); - expect(workflowText).toContain("publish-server-image-build-${{ github.ref }}"); - expect(workflowText).toContain( - "publish-server-image-publish-${{ github.ref == 'refs/heads/main' && 'main' || github.ref }}", + // Matrix legs share a job-level concurrency group unless it names the leg, and a shared + // group cancels sibling legs, so no image is published. + expect(build.concurrency?.group).toBe( + "publish-server-image-build-${{ github.ref }}-${{ matrix.name }}-${{ matrix.arch }}", + ); + expect(publish.concurrency?.group).toBe( + "publish-server-image-publish-${{ github.ref == 'refs/heads/main' && 'main' || github.ref }}-${{ matrix.name }}", ); expect(workflowText).toContain("push: false"); for (const match of workflowText.matchAll(/uses:\s+([^\s#]+)/g)) {