From 5ee43d2676123e4707e329835d4b6b58e4f45b14 Mon Sep 17 00:00:00 2001 From: Carter Francis Date: Sun, 26 Jul 2026 20:32:41 -0500 Subject: [PATCH] fix(ci): serialise docs deploys so release tags stop racing main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The concurrency guard was keyed on github.ref with the comment "Only one docs deployment should run at a time to avoid race conditions on the gh-pages branch". A push to main and a push to its v* tag are different refs, so they landed in different groups and ran concurrently — the guard never applied to the case it was written for. Both runs push to gh-pages. The second lost: ! [remote rejected] gh-pages -> gh-pages (cannot lock ref 'refs/heads/gh-pages': is at 38726cd but expected 0f190b2) The build itself succeeded, so the failure looks cosmetic in the Actions tab, but the versioned directory never gets published while prepare_release has already added the version to switcher.json — so the switcher offers a 404. v0.4.2 and v0.5.0 are both missing from gh-pages for this reason. Split the grouping: the workflow keeps a per-ref group so a new push still supersedes an in-flight build of the same ref (PR iterations), and the deploy job takes a ref-independent "docs-deploy" group with cancel-in-progress: false so deploys queue. Cancelling would drop a version directory just as surely as the race did. Does not backfill the two missing directories — re-running those Docs runs publishes them, since keep_files: true makes deploys additive. Assisted-by: Claude Opus 5 (1M context) --- .github/workflows/docs.yml | 20 ++++++++++++++++--- upcoming_changes/+docs-deploy-race.bugfix.rst | 6 ++++++ upcoming_changes/.gitkeep | 3 +++ 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 upcoming_changes/+docs-deploy-race.bugfix.rst create mode 100644 upcoming_changes/.gitkeep diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 17a97dab..861d01c3 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -11,10 +11,13 @@ on: # Allow manual re-builds from the Actions tab. workflow_dispatch: -# Only one docs deployment should run at a time to avoid race conditions on -# the gh-pages branch. +# Per-ref grouping so a new push supersedes an in-flight BUILD of the same +# ref (PR iterations, repeated pushes to main). This deliberately does NOT +# serialise deployments: a push to main and its release tag are different +# refs, so they land in different groups. The deploy job carries its own +# ref-independent group for that — see below. concurrency: - group: docs-${{ github.ref }} + group: docs-build-${{ github.ref }} cancel-in-progress: true permissions: @@ -91,6 +94,17 @@ jobs: # Skip deployment for pull requests. if: github.event_name != 'pull_request' + # Every deploy pushes to the SAME branch (gh-pages), so they must be + # serialised across refs, not per-ref. Releasing tags main and v* almost + # simultaneously, which previously raced: whichever run pushed second was + # rejected with "cannot lock ref 'refs/heads/gh-pages'" and its version + # directory never appeared, while switcher.json still advertised it. + # cancel-in-progress is false because these runs must QUEUE — cancelling + # one would drop a version directory just as surely as the race did. + concurrency: + group: docs-deploy + cancel-in-progress: false + steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/upcoming_changes/+docs-deploy-race.bugfix.rst b/upcoming_changes/+docs-deploy-race.bugfix.rst new file mode 100644 index 00000000..9a5fc788 --- /dev/null +++ b/upcoming_changes/+docs-deploy-race.bugfix.rst @@ -0,0 +1,6 @@ +Fixed the docs deployment racing itself on release. A push to ``main`` and its +release tag are different refs, so the ``docs-${{ github.ref }}`` concurrency +group put them in separate groups and both pushed to ``gh-pages`` at once; the +loser was rejected and its versioned directory never appeared, while +``switcher.json`` still advertised the version. The deploy job now uses a +ref-independent group so deployments queue instead. diff --git a/upcoming_changes/.gitkeep b/upcoming_changes/.gitkeep new file mode 100644 index 00000000..061573b3 --- /dev/null +++ b/upcoming_changes/.gitkeep @@ -0,0 +1,3 @@ +# This file keeps the upcoming_changes/ directory tracked by git. +# Replace it with real fragment files (e.g. 42.new_feature.rst) as PRs land. +