From 8d78817827b769c847471cbf8f1cdc7306646f39 Mon Sep 17 00:00:00 2001 From: giswqs Date: Sat, 24 Oct 2026 22:18:24 -0400 Subject: [PATCH 1/3] CI: keep skipped runs from cancelling the downloads mirror sync The mirror's concurrency group sat on the workflow with cancel-in-progress, so every workflow_run joined it, even one whose job the if skips. For v0.4.0 a pull request's Python package build cancelled the release's own sync two minutes in, and downloads.rustgis.app kept only the wheels. Move the group onto the job, where a skipped job never joins it, and queue runs instead of cancelling them: each run reads the release afresh, so the last to finish mirrors every asset. --- .github/workflows/downloads-mirror.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/downloads-mirror.yml b/.github/workflows/downloads-mirror.yml index c6857b207..05236379b 100644 --- a/.github/workflows/downloads-mirror.yml +++ b/.github/workflows/downloads-mirror.yml @@ -26,10 +26,6 @@ on: permissions: contents: read -concurrency: - group: downloads-mirror - cancel-in-progress: true - jobs: sync: name: Publish the latest release @@ -39,6 +35,13 @@ jobs: (github.event_name != 'workflow_run' || (github.event.workflow_run.event == 'release' && github.event.workflow_run.conclusion == 'success')) + # On the job, not the workflow: a run whose job the `if` skips (a pull request's Python + # package build, say) must not join the group, or it cancels the release's own sync in + # progress, as it did for v0.4.0. Queue instead of cancelling: each run reads the release's + # assets afresh, so the last one to finish mirrors them all. + concurrency: + group: downloads-mirror + cancel-in-progress: false runs-on: ubuntu-latest timeout-minutes: 30 env: From 4e6d8a4e8713ca0a5978d3ed391c43ebe9dfea5d Mon Sep 17 00:00:00 2001 From: giswqs Date: Sat, 24 Oct 2026 22:30:39 -0400 Subject: [PATCH 2/3] CI: mirror the latest release on automatic downloads syncs A late workflow_run from an older release can replace a newer release's pending sync in the concurrency group, and it published the tag of the run that triggered it. Read the latest release once the job holds the slot instead; only a manual run names its tag. --- .github/workflows/downloads-mirror.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/downloads-mirror.yml b/.github/workflows/downloads-mirror.yml index 05236379b..d1d12c107 100644 --- a/.github/workflows/downloads-mirror.yml +++ b/.github/workflows/downloads-mirror.yml @@ -56,9 +56,11 @@ jobs: id: release env: REQUESTED_TAG: ${{ inputs.tag }} - WORKFLOW_TAG: ${{ github.event.workflow_run.head_branch }} + # Only a manual run names its tag. A release's build or the schedule mirrors the latest + # release, read now that the job holds the concurrency slot: a late event from an older + # release can replace a newer one's pending run, and must not publish its own tag. run: | - tag="${REQUESTED_TAG:-${WORKFLOW_TAG:-}}" + tag="${REQUESTED_TAG:-}" if [ -z "$tag" ]; then if ! tag="$(gh api "repos/$GITHUB_REPOSITORY/releases/latest" --jq '.tag_name' 2>/dev/null)"; then echo "::notice::No release yet: nothing to mirror." From 97a4024bdbfa5facce4213f5932f734e75da34ec Mon Sep 17 00:00:00 2001 From: giswqs Date: Sat, 24 Oct 2026 22:43:44 -0400 Subject: [PATCH 3/3] CI: retry the latest-release lookup, fail when it keeps failing Only a 404 means no release; other API errors are retried and then fail the sync, so a stale mirror is never reported as up to date. --- .github/workflows/downloads-mirror.yml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/downloads-mirror.yml b/.github/workflows/downloads-mirror.yml index d1d12c107..90bc4f91f 100644 --- a/.github/workflows/downloads-mirror.yml +++ b/.github/workflows/downloads-mirror.yml @@ -62,10 +62,22 @@ jobs: run: | tag="${REQUESTED_TAG:-}" if [ -z "$tag" ]; then - if ! tag="$(gh api "repos/$GITHUB_REPOSITORY/releases/latest" --jq '.tag_name' 2>/dev/null)"; then - echo "::notice::No release yet: nothing to mirror." - exit 0 - fi + # A 404 means no release yet; any other error is retried, then fails the sync so a + # stale mirror never passes for an up-to-date one. + for attempt in 1 2 3; do + if tag="$(gh api "repos/$GITHUB_REPOSITORY/releases/latest" --jq '.tag_name' 2> err.txt)"; then + break + fi + if grep -q 'HTTP 404' err.txt; then + echo "::notice::No release yet: nothing to mirror." + exit 0 + fi + if [ "$attempt" = 3 ]; then + echo "::error::Could not read the latest release: $(cat err.txt)" + exit 1 + fi + sleep $((attempt * 10)) + done fi echo "tag=$tag" >> "$GITHUB_OUTPUT"