mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 18:36:15 -08:00
ci(release): close review-bot race windows in draft release flow
- Move concurrency from workflow level to job level: cancelling a whole run could interrupt action-gh-release mid-asset-replacement and leave the rolling draft incomplete. Build slots still cancel superseded PR work (matrix-aware groups); the release job gets its own serializing, never-cancelling group. - Re-check the live PR state in the release job right before touching the draft, so a build that outlives its PR cannot recreate the draft after cleanup deleted it. - In the cleanup workflow, cancel still-running builds of the closed PR (dead work anyway) and wait for them to settle before deleting. - Emit an explicit empty `body=` output for tag builds instead of a blank-line heredoc. Addresses Codex and Greptile review feedback on #1202. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a7ce9b1a62
commit
4d793485a7
2 files changed
+67
-7
No files matched your search
@@ -11,15 +11,18 @@ on:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build on ${{ matrix.os }} ${{ matrix.arch }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 120
|
||||
# Concurrency lives on the jobs, not the workflow: cancelling a whole
|
||||
# run could interrupt action-gh-release mid-update and leave the
|
||||
# rolling draft with missing assets. Build slots cancel superseded PR
|
||||
# work; the release job below only serializes and is never cancelled.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-build-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.linux_profile }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
@@ -669,6 +672,9 @@ jobs:
|
||||
needs: build
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
|
||||
runs-on: ubuntu-latest
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-release-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: false
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
@@ -848,12 +854,33 @@ jobs:
|
||||
echo "name=${NAME}"
|
||||
echo "tag=${TAG}"
|
||||
echo "commitish=${HEAD_SHA}"
|
||||
echo "body<<RELEASE_BODY_EOF"
|
||||
echo "${BODY}"
|
||||
echo "RELEASE_BODY_EOF"
|
||||
} >> "${GITHUB_OUTPUT}"
|
||||
|
||||
if [ -n "${BODY}" ]; then
|
||||
{
|
||||
echo "body<<RELEASE_BODY_EOF"
|
||||
echo "${BODY}"
|
||||
echo "RELEASE_BODY_EOF"
|
||||
} >> "${GITHUB_OUTPUT}"
|
||||
else
|
||||
echo "body=" >> "${GITHUB_OUTPUT}"
|
||||
fi
|
||||
|
||||
# A PR can be closed while this workflow is still running; the
|
||||
# cleanup workflow deletes the PR draft on close. Re-check the live
|
||||
# PR state right before touching the draft so a late-finishing run
|
||||
# cannot recreate a draft for a closed PR.
|
||||
- name: Check PR is still open
|
||||
if: github.event_name == 'pull_request'
|
||||
id: pr-state
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "state=$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${{ github.event.pull_request.number }}" --jq '.state')" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
- name: Create Draft Release
|
||||
if: github.event_name != 'pull_request' || steps.pr-state.outputs.state == 'open'
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
draft: true
|
||||
|
||||
@@ -12,6 +12,39 @@ jobs:
|
||||
name: Delete PR draft release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# A build for this PR may still be running and would recreate the
|
||||
# rolling draft after we delete it. Cancel those runs (dead work
|
||||
# for a closed PR anyway) and wait for them to wind down. The
|
||||
# release job additionally re-checks the live PR state, so this
|
||||
# wait is defense in depth, not the only guard.
|
||||
- name: Cancel in-progress builds for the closed PR
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
HEAD_BRANCH: ${{ github.event.pull_request.head.ref }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
list_active_runs() {
|
||||
gh run list --repo "${GITHUB_REPOSITORY}" \
|
||||
--workflow 'Build and Make Electron App' \
|
||||
--branch "${HEAD_BRANCH}" \
|
||||
--json databaseId,status \
|
||||
--jq '.[] | select(.status == "queued" or .status == "in_progress" or .status == "waiting" or .status == "requested" or .status == "pending") | .databaseId'
|
||||
}
|
||||
|
||||
for run_id in $(list_active_runs); do
|
||||
echo "Cancelling run ${run_id}"
|
||||
gh run cancel "${run_id}" --repo "${GITHUB_REPOSITORY}" || true
|
||||
done
|
||||
|
||||
# Cancellation is asynchronous; poll until the runs settle.
|
||||
for _ in $(seq 1 18); do
|
||||
if [ -z "$(list_active_runs)" ]; then
|
||||
break
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
|
||||
# Draft releases have no real git tag, so a lookup via
|
||||
# releases/tags/<tag> returns 404. List releases and match the
|
||||
# draft by its stored tag_name (test-pr-<n>) instead.
|
||||
|
||||
Reference in new issue
Block a user