fix(ci): changelog job creates release, eliminating race with build jobs #56
No reviewers
Labels
No Label
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: sarman/tftsr-devops_investigation#56
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "fix/auto-tag-changelog-race"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
changelogandbuild-*jobs all fan out fromautotagin parallelPOST /releases) — butchangelogwas trying toGET /releases/tags/$TAGat the same moment, before any build had runCould not find release for tag vX.Y.Zon every runFix:
changelogjob now owns release creation. It creates the release with the git-cliff changelog body if it does not exist, or patches the body on a re-run. Build jobs continue using their existingcreate || true+ upload artifact pattern unchanged.Test plan
changelogjob with the proper bodychangelogAutomated PR Review (qwen3-coder-next via liteLLM):\n\nSummary
The PR aims to eliminate race conditions in CI by creating the release in the changelog job before build jobs proceed. However, the job lacks proper dependency declaration on
autotag, and thegit-cliffstep references a tag that may not be available due to missingneeds.autotag.outputs.release_tagpropagation in the workflow structure implied by the code.Findings
[BLOCKER] .gitea/workflows/auto-tag.yml:112-122 - The job that creates the release does not declare
needs: [autotag], yet it references${{ needs.autotag.outputs.release_tag }}. Without this dependency, the job may run beforeautotagproduces the output, leading to undefined behavior or failure.Evidence:
RELEASE_TAG: ${{ needs.autotag.outputs.release_tag }}appears inside a job that is not shown to declareneeds: autotagin the full file excerpt — only the previous job (autotag) is implied to produce the output. In Gitea Actions (like GitHub Actions), downstream jobs must explicitly declareneedsto consume outputs.Fix: Add
needs: autotagat the job level for the changelog-generating job.[WARNING] .gitea/workflows/auto-tag.yml:146 - The
UPDATE Gitea release bodylogic (renamed to "Create or update Gitea release") assumes the release tag exists in the remote repository before creating the release, but thegit-cliffstep usesgit tag --sort=-version:refnameto findPREV_TAG. If no previous tag exists locally,PREV_TAGmay be empty andgit-cliffmay fall back togit log, but no guarantee that tags were fully fetched before this point.Evidence:
PREV_TAG=$(git tag --sort=-version:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | grep -v "^${CURRENT_TAG}$" | head -1 || echo "")runs before verifying thatCURRENT_TAGexists locally or on remote —git fetch --tags originis done, but there's no check that the tag is actually present after checkout.Fix: Add explicit validation that
git rev-parse "refs/tags/${CURRENT_TAG}" >/dev/null 2>&1after fetching and before proceeding.Verdict: REQUEST CHANGES
Automated PR Review (qwen3-coder-next via liteLLM):\n\nSummary
The PR aims to fix a race condition by having the changelog job create the release instead of relying on a separate release job, and adds validation for the tag before generating the changelog. However, a critical bug is introduced: the release creation logic uses
jq -n --rawfileinside a shell command, which will fail if the release body contains special characters like%or unescaped newlines, causing JSON parsing errors or shell injection.Findings
[BLOCKER] .gitea/workflows/auto-tag.yml:137-145 - Unsafe use of
jq -n --rawfilewith unescaped content; if/tmp/release_body.mdcontains unescaped quotes, backslashes, or control characters, the resulting JSON is malformed, causing the release creation to fail silently or incorrectly.Evidence:
jq -n \--arg tag "$TAG" \--arg name "TFTSR $TAG" \--rawfile body /tmp/release_body.md \'{tag_name: $tag, name: $name, body: $body, draft: false}' \Fix: Replace
--rawfilewith--slurpfileor pre-process body to escape JSON characters, e.g.,body_escaped=$(jq -Rs . /tmp/release_body.md)and use--arg body "$body_escaped".[WARNING] .gitea/workflows/auto-tag.yml:110-115 - Tag existence validation uses
git rev-parse, butgit fetch --tagsmay not fetch all tags reliably; if the tag exists on remote but not locally yet, the check passes falsely due toFETCH_HEADcheckout. Also, the checkout step may be stale ifFETCH_HEADis not updated after the tag fetch.Evidence:
git checkout "$GITHUB_SHA" 2>/dev/null || git checkout FETCH_HEADFix: Explicitly fetch the tag before checking:
git fetch origin "refs/tags/${CURRENT_TAG}:refs/tags/${CURRENT_TAG}"then verify.[SUGGESTION] .gitea/workflows/auto-tag.yml:160-166 - Release asset upload re-fetches release info after creation/update, but could race if another job also updates the release concurrently. The download URL may change mid-execution if multiple assets are uploaded simultaneously.
Evidence:
RELEASE_ID=$(curl -sf "$API/releases/tags/$TAG" ... | jq -r '.id')is called again in upload asset step.Fix: Store
RELEASE_IDinGITHUB_OUTPUTfrom the creation/update step and pass it to subsequent steps instead of re-fetching.[SUGGESTION] .gitea/workflows/auto-tag.yml:84-85 — The
autotagjob’s output usesrelease_tag=$NEXTbut the changelog job expects${{ needs.autotag.outputs.release_tag }}. IfNEXTis empty or malformed,GITHUB_OUTPUTwill set an invalid value; no validation occurs.Evidence:
echo "release_tag=$NEXT" >> "$GITHUB_OUTPUT"Fix: Validate
$NEXTbefore writing toGITHUB_OUTPUT(e.g.,[[ $NEXT =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "Invalid tag"; exit 1; }).