diff --git a/.github/workflows/publish-versioned-docs.yml b/.github/workflows/publish-versioned-docs.yml index c5f946502..56a9f9102 100644 --- a/.github/workflows/publish-versioned-docs.yml +++ b/.github/workflows/publish-versioned-docs.yml @@ -24,16 +24,18 @@ on: permissions: contents: write -# Every run rewrites gh-pages and then uploads the whole tree, so run them -# one at a time to avoid racing mike or publishing a stale snapshot. -concurrency: - group: publish-versioned-docs - cancel-in-progress: false - jobs: publish: runs-on: ubuntu-latest + # One group per branch. GitHub keeps at most one pending run per group + # and cancels older pending ones, which is harmless here: the newest + # push to a branch already contains the older ones. Different branches + # publish in parallel and retry if another one updates gh-pages first. + concurrency: + group: publish-versioned-docs-${{ github.ref_name }} + cancel-in-progress: false + steps: - name: Check out source uses: actions/checkout@v7 @@ -98,17 +100,45 @@ jobs: env: # "Edit this page" should open the branch this version is built from. DOCS_EDIT_URI: edit/${{ github.ref_name }}/website/md-docs/ - run: uv run mike deploy --push --update-aliases --title "${{ steps.version.outputs.title }}" ${{ steps.version.outputs.aliases }} + IS_LATEST: ${{ steps.version.outputs.is_latest }} + run: | + # Other branches may push to gh-pages while this one builds. mike's + # push is then rejected as non-fast-forward, so rebuild on top of + # the new tip and try again. + for attempt in 1 2 3 4 5; do + git fetch origin gh-pages + git branch -f gh-pages origin/gh-pages + if uv run mike deploy --push --update-aliases --title "${{ steps.version.outputs.title }}" ${{ steps.version.outputs.aliases }} \ + && { [[ "${IS_LATEST}" != "true" ]] || uv run mike set-default --push latest; }; then + exit 0 + fi + echo "gh-pages push failed (attempt ${attempt}), retrying" >&2 + sleep $((attempt * 10)) + done + exit 1 + + deploy: + needs: publish + runs-on: ubuntu-latest - - name: Set default docs version - if: steps.version.outputs.is_latest == 'true' - run: uv run mike set-default --push latest + # One group across all branches, so uploads never overlap. If several + # are queued, GitHub keeps only the newest; that's fine because it + # exports gh-pages when it starts, which already includes every + # earlier publish. The last upload is therefore always the newest tree. + concurrency: + group: publish-versioned-docs-cloudflare + cancel-in-progress: false + + steps: + - name: Check out source + uses: actions/checkout@v7 - name: Export gh-pages tree for Cloudflare run: | + git fetch --depth 1 origin gh-pages rm -rf .site-publish mkdir .site-publish - git archive gh-pages | tar -x -C .site-publish + git archive FETCH_HEAD | tar -x -C .site-publish - name: Deploy to Cloudflare Workers uses: cloudflare/wrangler-action@v4