From 5544ec34ba7499fcc534b0d3ed215e8df72e58a2 Mon Sep 17 00:00:00 2001 From: FerroxLabs Date: Sat, 5 Sep 2026 02:02:40 +0700 Subject: [PATCH] ci(release): move the failed-run retry where the rerun API accepts it The auto-retry job inside Build and Release could never have worked. It slept five minutes and then POSTed .../actions/runs//rerun for its OWN run id, but it was a job of that run, so the run was necessarily still in progress: 403 {"message": "This workflow is already running"} It was skipped on every green run and on every dev build, so it first executed on v0.12.14 and failed exactly as written, five minutes after a transient Azure signing crash had already cost a twenty-minute build. The same class as the four acceptance defects that burned nine version numbers: code no run had reached. Replaced with a workflow_run-triggered workflow, which fires only after the run has finished and is therefore the one moment the rerun API will accept the call. Verified by hand on v0.12.14: once the run reached completed, rerun-failed-jobs was accepted, produced attempt 2, and rebuilt only the one failed target while the five green builds kept their artifacts. That is why this uses rerun-failed-jobs rather than a full rerun. Loop safety is the run_attempt == 1 guard: a run this retries becomes attempt 2 and can never trigger it again. head_branch reaches the shell through env rather than template interpolation, so a crafted branch name cannot inject. --- .github/workflows/build-and-release.yml | 58 ------------------------ .github/workflows/release-auto-retry.yml | 53 ++++++++++++++++++++++ 2 files changed, 53 insertions(+), 58 deletions(-) create mode 100644 .github/workflows/release-auto-retry.yml diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index 027033957..b341f434a 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -131,64 +131,6 @@ jobs: ]} secrets: inherit - # 自动重试 workflow(当构建失败时) - auto-retry-workflow: - name: Auto Retry on Build Failure - runs-on: ubuntu-latest - needs: build-pipeline - permissions: - actions: write - contents: read - # 关键:只在首次失败时触发,避免无限循环 - if: | - failure() && - github.run_attempt == 1 && - (github.event_name == 'push' || github.event_name == 'schedule') - - steps: - - name: Log retry information - run: | - echo "==========================================" - echo "🔄 Auto retry triggered (first failure)" - echo "==========================================" - echo "Build failed on first attempt, preparing auto retry..." - echo "Current attempt: ${{ github.run_attempt }}" - echo "Wait strategy: 5 minutes cooldown before retry" - echo "==========================================" - - - name: Wait before retry (5 min cooldown) - run: | - echo "⏳ Waiting 5 minutes before retry..." - echo "Start: $(date)" - sleep 300 - echo "End: $(date)" - echo "Triggering retry..." - - - name: Trigger workflow rerun - run: | - echo "🔄 Triggering full workflow rerun (attempt 2)..." - - # Use re-run API (not rerun-failed-jobs, to avoid loops) - response=$(curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ - -w "\n%{http_code}" \ - https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/rerun) - - http_code=$(echo "$response" | tail -n1) - - if [ "$http_code" = "201" ]; then - echo "" - echo "✅ Retry triggered successfully" - echo "This will be attempt 2" - echo "Details: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - else - echo "" - echo "❌ Retry trigger failed, HTTP status: $http_code" - echo "Response:" - echo "$response" | head -n-1 - exit 1 - fi # 自动创建tag(仅 dev 分支推送时) create-tag: diff --git a/.github/workflows/release-auto-retry.yml b/.github/workflows/release-auto-retry.yml new file mode 100644 index 000000000..535b76f69 --- /dev/null +++ b/.github/workflows/release-auto-retry.yml @@ -0,0 +1,53 @@ +# Re-runs a failed Build and Release once, from OUTSIDE the run. +# +# This replaces an auto-retry job that lived inside Build and Release itself and +# could never have worked. That job slept 5 minutes and then POSTed .../rerun for +# its own run id - but it was a job of that run, so the run was still in progress +# and GitHub answered: +# +# 403 {"message": "This workflow is already running"} +# +# It was skipped on every green run and on every dev build, so it first executed +# on v0.12.14 and failed exactly as constructed. workflow_run fires only after the +# run has finished, which is the one moment the rerun API will accept it. +# +# Loop safety is the run_attempt check: this fires only for attempt 1, so a run it +# retries becomes attempt 2 and can never trigger it again. rerun-failed-jobs is +# used rather than a full rerun so the builds that already passed keep their +# artifacts - a manual rerun of v0.12.14 rebuilt only the one failed target. +name: Release Auto Retry + +on: + workflow_run: + workflows: ['Build and Release'] + types: [completed] + +permissions: + actions: write + contents: read + +jobs: + retry-once: + name: Retry a failed release run once + runs-on: ubuntu-latest + if: | + github.event.workflow_run.conclusion == 'failure' && + github.event.workflow_run.run_attempt == 1 && + github.event.workflow_run.event == 'push' + steps: + - name: Re-run the failed jobs + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RUN_ID: ${{ github.event.workflow_run.id }} + RUN_URL: ${{ github.event.workflow_run.html_url }} + HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} + run: | + set -euo pipefail + echo "Retrying failed jobs for run $RUN_ID ($HEAD_BRANCH)" + echo "$RUN_URL" + if gh api -X POST "repos/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}/rerun-failed-jobs"; then + echo "::notice title=Release auto retry::Re-ran the failed jobs of $HEAD_BRANCH as attempt 2" + else + echo "::error title=Release auto retry failed::Could not re-run $RUN_ID; re-run it by hand at $RUN_URL" >&2 + exit 1 + fi