diff --git a/.github/workflows/release-skills.yml b/.github/workflows/release-skills.yml index 902f3d21..5374df04 100644 --- a/.github/workflows/release-skills.yml +++ b/.github/workflows/release-skills.yml @@ -43,15 +43,20 @@ concurrency: jobs: publish: - name: Pack & publish FS.GG.Rendering.Skills + name: Pack & publish FS.GG.Rendering.Skills [org-publication-writer] if: github.repository == 'FS-GG/FS.GG.Rendering' runs-on: ubuntu-latest - timeout-minutes: 20 + timeout-minutes: 50 permissions: contents: read packages: write id-token: write # ADR-0013: mint the GitHub OIDC token for nuget.org Trusted Publishing steps: + - name: Acquire org publication writer lock + uses: FS-GG/.github/.github/actions/publication-writer-lock@c799a9f9b21d52eb9766cf0950722e3e55145d39 # ADR-0097 + with: + max-wait-minutes: 30 + timeout-minutes: 32 - uses: actions/checkout@v7 - uses: actions/setup-dotnet@v6 diff --git a/.github/workflows/release-tags.yml b/.github/workflows/release-tags.yml index 45108b1c..35d6e76c 100644 --- a/.github/workflows/release-tags.yml +++ b/.github/workflows/release-tags.yml @@ -123,11 +123,11 @@ jobs: if-no-files-found: error selected-tag-cut: - name: Cut only selected producer tags + name: Cut only selected producer tags [org-publication-writer] needs: selected-tag-plan if: github.repository == 'FS-GG/FS.GG.Rendering' && github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest - timeout-minutes: 6 + timeout-minutes: 36 permissions: contents: write env: @@ -135,6 +135,11 @@ jobs: SELECTED_SOURCE_SHA: ${{ inputs.source-sha }} SELECTED_VERSION: ${{ inputs.version }} steps: + - name: Acquire org publication writer lock + uses: FS-GG/.github/.github/actions/publication-writer-lock@c799a9f9b21d52eb9766cf0950722e3e55145d39 # ADR-0097 + with: + max-wait-minutes: 30 + timeout-minutes: 32 - uses: actions/checkout@v7 with: ref: ${{ github.sha }} @@ -426,13 +431,18 @@ jobs: # #681 — THE PUSH, and nothing else. Reachable only after `validate` went green. cut: - name: Cut the pending release tags + name: Cut the pending release tags [org-publication-writer] needs: [plan, validate] if: needs.plan.outputs.has-pending == 'true' runs-on: ubuntu-latest permissions: contents: write # push the tag triple steps: + - name: Acquire org publication writer lock + uses: FS-GG/.github/.github/actions/publication-writer-lock@c799a9f9b21d52eb9766cf0950722e3e55145d39 # ADR-0097 + with: + max-wait-minutes: 30 + timeout-minutes: 32 - uses: actions/checkout@v7 with: # `persist-credentials` (default true) leaves the GITHUB_TOKEN on `origin`, so the pushes below diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c99f04bb..9582bc3d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -571,7 +571,7 @@ jobs: publication-preflight: needs: release-source-guard - name: Protected publication preflight (no mutation) + name: Protected publication preflight (no mutation) [org-publication-writer] runs-on: ubuntu-latest if: >- github.repository == 'FS-GG/FS.GG.Rendering' && @@ -585,6 +585,11 @@ jobs: RELEASE_PLAN: ${{ inputs.font-disposal-attempt && 'eng/release/font-disposal-0.32.3.json' || inputs.bound-attempt && 'eng/release/svg-export-prefix-0.32.1.json' || 'eng/release/external-authority-recovery-0.32.2.json' }} RELEASE_BASELINE: ${{ inputs.bound-attempt && '0.32.0' || '0.32.1' }} steps: + - name: Acquire org publication writer lock + uses: FS-GG/.github/.github/actions/publication-writer-lock@c799a9f9b21d52eb9766cf0950722e3e55145d39 # ADR-0097 + with: + max-wait-minutes: 30 + timeout-minutes: 32 - uses: actions/checkout@v7 with: ref: ${{ github.sha }} @@ -734,7 +739,7 @@ jobs: retention-days: 90 publish-packages: - name: Publish FS.GG.UI.* to org GitHub Packages (release-only) + name: Publish FS.GG.UI.* to org GitHub Packages (release-only) [org-publication-writer] runs-on: ubuntu-latest # `!inputs.validate-only` — #681. On `release-tags.yml`'s PRE-CUT call this workflow runs its # validators and ships nothing; the publish happens on the second call, after the tags are cut. @@ -759,6 +764,11 @@ jobs: FSGG_RELEASE_ATTEMPT: ${{ inputs.font-disposal-attempt && '0323' || inputs.successor-attempt && '0322' || '0321' }} PRODUCER_PLAN: artifacts/attempt/producer-plan.json steps: + - name: Acquire org publication writer lock + uses: FS-GG/.github/.github/actions/publication-writer-lock@c799a9f9b21d52eb9766cf0950722e3e55145d39 # ADR-0097 + with: + max-wait-minutes: 30 + timeout-minutes: 32 - uses: actions/checkout@v7 with: ref: ${{ github.sha }} diff --git a/eng/release/font-disposal-0.32.3-workflow-fences.json b/eng/release/font-disposal-0.32.3-workflow-fences.json index 8a4c8fa3..bea37d23 100644 --- a/eng/release/font-disposal-0.32.3-workflow-fences.json +++ b/eng/release/font-disposal-0.32.3-workflow-fences.json @@ -33,11 +33,11 @@ ".github/workflows/lockfile-sync.yml": "9a6a854ce84e70c0e210c6853346fe065c33befe56afb652da088297d6b7a9eb", ".github/workflows/packaged-consumer.yml": "a2806612621530bdc74e12a5480e6f595827f4a7129d6c337ed8c65c89f692b8", ".github/workflows/pending-tests.yml": "b5b7ae6ce10f2a740a5da0482968413bebf9833f1fd0d58ec15346357349ad3c", - ".github/workflows/release-skills.yml": "b6841ac925773e17b4fb8de03d18a9370f4ab42a53363e799c84a70c902b0dc7", + ".github/workflows/release-skills.yml": "db203f13659157cf4695d5c428ec38204b0b8944999f760ea6f392452042f150", ".github/workflows/release-tag-capability.yml": "a00a2fe22f5142832330cc0567ab426028e5da8f838fa57a6adbc081d3b43099", ".github/workflows/release-tag-settlement.yml": "e2fa3e91c948b8aba78485d174b5cf60c1efd7655e35468ec70931a6cd877928", - ".github/workflows/release-tags.yml": "f15afc2c70b15f89beb3d3111f05d1c299a7f89b7aca993319f1c5525f90f071", - ".github/workflows/release.yml": "18c0a3b8963d511ac3f3cea3c2ee6d83eb5594cc92930c1aa2997a9530494d47", + ".github/workflows/release-tags.yml": "2681e23ff541317ef2aa08c0115195b41623adc4884471944ef0c50a85ee8dba", + ".github/workflows/release.yml": "85658aec8cb75dc1773daf0bca17b1e7ea7a07ccbe143106b90aed38b489d872", ".github/workflows/routine-eligibility.yml": "c5ce8b1b019a4a6dd0a48332664b60cdccee59725b12284bd3dfac3295c7b72d", ".github/workflows/skill-refs-sweep.yml": "9ae0fbcc9a707f7c031aa92088210519918a4c58db784a9e34b7ef80e0484f48", ".github/workflows/skill-view-check.yml": "dea53e33bfd056facb8007b073390894e0a61b037378bed292246e88d847962f", diff --git a/scripts/test-selected-producer-tags.py b/scripts/test-selected-producer-tags.py index 230959e1..ec915d6c 100644 --- a/scripts/test-selected-producer-tags.py +++ b/scripts/test-selected-producer-tags.py @@ -73,13 +73,16 @@ def need(condition, message): for job in ('selected-tag-plan', 'selected-tag-cut'): block = jobs[job] need(re.findall(r'^ if: (.+)$', block, re.M) == [dispatch_if], f'{job}: dispatch-only condition differs') - need(' timeout-minutes: 6\n' in block, f'{job}: missing finite job bound') + # The tag-cutting job takes the org publication writer lock (ADR-0097): its 6 minute working + # budget is unchanged and its bound rises by exactly the declared 30 minute wait. + need((' timeout-minutes: 36\n' if job == 'selected-tag-cut' else ' timeout-minutes: 6\n') in block, f'{job}: missing finite job bound') need('ref: ${{ github.sha }}' in block, f'{job}: checkout must use event SHA') need('FSGG_EXPECTED_EXECUTOR_SHA: ${{ inputs.expected-executor-sha }}' in block, f'{job}: missing executor input') need('SELECTED_SOURCE_SHA: ${{ inputs.source-sha }}' in block and 'SELECTED_VERSION: ${{ inputs.version }}' in block, f'{job}: missing subject inputs') uses = re.findall(r'^\s+(?:- )?uses: (.+)$', block, re.M) - need(uses == ['actions/checkout@v7', 'actions/upload-artifact@v7'], + lock = ['FS-GG/.github/.github/actions/publication-writer-lock@c799a9f9b21d52eb9766cf0950722e3e55145d39 # ADR-0097'] if job == 'selected-tag-cut' else [] + need(uses == lock + ['actions/checkout@v7', 'actions/upload-artifact@v7'], f'{job}: unexpected action outside checkout and evidence upload') need(not re.search(r'\b(dotnet|gh|curl|git push|secrets\.|id-token|packages:|create-github-app-token)\b', block), f'{job}: unexpected authority/native command')