Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions .github/workflows/publish-dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,21 @@ on:
description: External fork PR number to approve (pins its head SHA) and preview. Leave empty to just re-deploy.
required: false
default: ""
retry-until:
description: >-
Internal — epoch-seconds deadline for auto-retrying a wedged Pages origin.
Don't set manually.
required: false
default: ""

jobs:
publish:
uses: ./.github/workflows/publish.yml
with:
version-name: ${{ inputs.version-name }} # "" on dispatch → pure durable gather
pr: ${{ inputs.pr }} # set (dispatch only) → pin that fork head SHA
dispatch-workflow: publish-dispatch.yml # the file the tag re-dispatch re-fires
version-name: ${{ inputs.version-name }} # "" on dispatch → pure durable gather
pr: ${{ inputs.pr }} # set (dispatch only) → pin that fork head SHA
dispatch-workflow: publish-dispatch.yml # the file the tag re-dispatch re-fires
retry-until: ${{ inputs.retry-until }} # "" on workflow_call/no-retry dispatch → no auto-retry
permissions:
contents: read
actions: write # publish.yml's re-dispatch job re-fires this shim via gh
Expand Down
51 changes: 47 additions & 4 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ on:
required: false
default: publish-dispatch.yml
type: string
retry-until:
description: >-
Internal — epoch-seconds deadline for auto-retrying a wedged Pages origin.
Empty means no retry budget (set only by the tag re-dispatch job, from the
release's publish time); carried unchanged through any retries. Don't set manually.
required: false
default: ""
type: string

jobs:
# Fork PR: read-only token, never deploys — surface the manual-opt-in hint on the PR.
Expand Down Expand Up @@ -79,7 +87,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read # checkout + read release assets
actions: read # gh run download (this run's + cross-run docs artifacts)
actions: write # gather cross-run docs artifacts (read) + retry-dispatch on a wedged origin (write)
pages: write # deploy to Pages
id-token: write # deploy-pages OIDC
statuses: write # set the preview-approved status on a fork PR head SHA
Expand Down Expand Up @@ -310,6 +318,7 @@ jobs:
# so a fast/first-of-SHA deploy isn't slowed. On failure, dump the origin headers
# (a frozen etag/last-modified is the wedge signature).
- name: Verify the deployed origin matches what we assembled
id: verify
env:
PAGE_URL: ${{ steps.deployment.outputs.page_url }}
SITE_DIR: ${{ runner.temp }}/site
Expand Down Expand Up @@ -343,6 +352,34 @@ jobs:
sleep 5
done

# A verify failure means the origin is wedged (see comment above) — and per
# observed external evidence (actions/deploy-pages#383: waiting longer does NOT
# recover a wedged origin, only a genuinely NEW deploy attempt does), the fix is a
# fresh workflow_dispatch, not a longer timeout. This must be a fresh dispatch and
# NOT a job rerun — rerunning would stack a second `github-pages` artifact under
# this same run and break deploy-pages' artifact lookup ("Multiple artifacts named
# github-pages"). Only tag/release deploys carry a retry-until budget (set by the
# re-dispatch job below, from the release's publish time, carried unchanged through
# each retry) — that's the same-SHA dedup wedge this targets, which a push/PR/manual
# deploy can't hit (those are always first-of-SHA). No budget → no auto-retry, just
# the red check.
- name: Retry via a fresh dispatch if the origin is wedged
if: failure() && steps.verify.outcome == 'failure' && inputs.retry-until != ''
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
WF: ${{ inputs.dispatch-workflow }}
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
RETRY_UNTIL: ${{ inputs.retry-until }}
run: |
set -euo pipefail
if [ "$(date +%s)" -ge "$RETRY_UNTIL" ]; then
echo "::error::origin still wedged past the retry deadline ($(date -d "@$RETRY_UNTIL" -Is)) — giving up, manual re-dispatch needed"
exit 0
fi
gh workflow run "$WF" --repo "$REPO" --ref "$DEFAULT_BRANCH" -f retry-until="$RETRY_UNTIL"
echo "::notice::origin wedged — dispatched a fresh retry (budget until $(date -d "@$RETRY_UNTIL" -Is))"

# A tag can't deploy inline (same SHA as the default-branch push → Pages drops it
# unless the event is workflow_dispatch). Wait for the release, then re-dispatch the
# shim so the deploy runs on a workflow_dispatch event and re-serves.
Expand All @@ -364,10 +401,16 @@ jobs:
set -euo pipefail
# ci.yml's release job attaches the tag's docs.zip in parallel; the dispatched
# run gathers the tag from that asset, so don't dispatch until it exists.
published_at=""
for _ in $(seq 1 36); do
gh release view "$TAG" --repo "$REPO" >/dev/null 2>&1 && break
published_at=$(gh release view "$TAG" --repo "$REPO" --json publishedAt -q .publishedAt 2>/dev/null) && break
sleep 5
done
gh release view "$TAG" --repo "$REPO" >/dev/null 2>&1 \
[ -n "$published_at" ] \
|| { echo "::error::release $TAG not found after 3 min — did the release job fail?"; exit 1; }
gh workflow run "$WF" --repo "$REPO" --ref "$DEFAULT_BRANCH"
# Retry budget anchored on the release's publish time, not the commit's — a tag
# can be cut long after its commit was merged (this repo's own release flow
# allows it), so the commit's own timestamp would wrongly disqualify the exact
# same-SHA dedup wedge (deploy-pages#383) this budget exists to retry through.
retry_until=$(( $(date -d "$published_at" +%s) + 900 ))
gh workflow run "$WF" --repo "$REPO" --ref "$DEFAULT_BRANCH" -f retry-until="$retry_until"