diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 09afec3..89b6fa3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,6 +49,9 @@ jobs: exit 1 fi + # actions/checkout resolves a tag event to its commit. Fetch the tag ref + # explicitly so annotated-tag validation examines the remote tag object. + git fetch origin "refs/tags/${TAG}:refs/tags/${TAG}" --force TAG_TYPE="$(git cat-file -t "refs/tags/${TAG}" 2>/dev/null || true)" if [[ "${TAG_TYPE}" != "tag" ]]; then echo "Release tag ${TAG} must be an annotated tag object. Found: ${TAG_TYPE:-missing}" >&2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 9da4eae..4c93c1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Panely follows sparse milestone releases. GitHub Releases are created from semve ## [Unreleased] - Keep upcoming milestone changes here until the release PR adds a versioned section below. +- Fixed release reruns to refetch and validate the remote annotated tag object after GitHub checkout dereferences it. ## [v0.7.0] - 2026-07-15 - Frontier Provider Parity diff --git a/scripts/release-policy.test.mjs b/scripts/release-policy.test.mjs index 29ce31c..d2b8e8c 100644 --- a/scripts/release-policy.test.mjs +++ b/scripts/release-policy.test.mjs @@ -59,3 +59,11 @@ test("manual release input reaches Bash only through the environment", () => { assert.match(workflow, /TAG="\$\{INPUT_TAG\}"/); assert.doesNotMatch(workflow, /TAG="\$\{\{\s*inputs\.tag\s*\}\}"/); }); + +test("release validation explicitly fetches the annotated tag object", () => { + const workflow = fs.readFileSync(".github/workflows/release.yml", "utf8"); + const fetchIndex = workflow.indexOf('git fetch origin "refs/tags/${TAG}:refs/tags/${TAG}" --force'); + const typeIndex = workflow.indexOf('git cat-file -t "refs/tags/${TAG}"'); + assert.ok(fetchIndex >= 0, "expected an explicit tag-ref fetch"); + assert.ok(typeIndex > fetchIndex, "annotated-tag validation must run after the explicit fetch"); +});