Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 33 additions & 16 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,28 +63,45 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ inputs.version }}
# Detect whether main already carries the release commit (we're
# resuming after a mid-flight failure) or whether this is a fresh
# release attempt. The downstream steps gate themselves on `resume`.
# Tag existence is the source of truth for "release in progress":
# main HEAD may have moved past the release commit (a follow-up fix
# merged on top), so the commit-message check on HEAD is too narrow.
# If v<version> exists, resume from the commit it points at;
# otherwise it's a fresh attempt and tags must not exist.
run: |
set -euo pipefail
main_sha=$(gh api "repos/${GITHUB_REPOSITORY}/git/refs/heads/main" -q .object.sha)
first_line=$(gh api "repos/${GITHUB_REPOSITORY}/git/commits/${main_sha}" -q .message | head -n1)
expected="chore: prepare release ${VERSION} [skip ci]"
if [[ "${first_line}" == "${expected}" ]]; then
echo "Resuming: release commit already at ${main_sha}"
err=$(mktemp)
trap 'rm -f "${err}"' EXIT
# Capture stderr so we can distinguish a real 404 (tag absent → fresh
# attempt) from any other failure (rate limit, 5xx, auth) which must
# not be silently treated as "tag missing".
if ref=$(gh api "repos/${GITHUB_REPOSITORY}/git/refs/tags/v${VERSION}" 2>"${err}"); then
sha=$(jq -r .object.sha <<<"${ref}")
Comment thread
dunglas marked this conversation as resolved.
Comment thread
dunglas marked this conversation as resolved.
type=$(jq -r .object.type <<<"${ref}")
if [[ "${type}" == "tag" ]]; then
sha=$(gh api "repos/${GITHUB_REPOSITORY}/git/tags/${sha}" -q .object.sha)
Comment thread
dunglas marked this conversation as resolved.
fi
# Refuse to resume against a tag that isn't reachable from main:
# protects against an orphan tag created on a side branch.
if ! git merge-base --is-ancestor "${sha}" HEAD; then
echo "::error::Tag v${VERSION} (${sha}) is not reachable from main; refusing to resume."
exit 1
fi
echo "Resuming: v${VERSION} exists at ${sha}"
{
echo "resume=true"
echo "release_commit=${main_sha}"
echo "release_commit=${sha}"
} >> "${GITHUB_OUTPUT}"
else
elif grep -qF "(HTTP 404)" "${err}"; then
echo "resume=false" >> "${GITHUB_OUTPUT}"
for tag in "v${VERSION}" "caddy/v${VERSION}"; do
if gh api "repos/${GITHUB_REPOSITORY}/git/refs/tags/${tag}" --silent 2>/dev/null; then
echo "::error::Tag ${tag} exists but main HEAD is not the release commit; refusing to release."
exit 1
fi
done
if gh api "repos/${GITHUB_REPOSITORY}/git/refs/tags/caddy/v${VERSION}" --silent 2>/dev/null; then
echo "::error::caddy/v${VERSION} exists but v${VERSION} does not; refusing to release into a split state."
exit 1
fi
else
echo "::error::GitHub API call for tag v${VERSION} failed:"
cat "${err}" >&2
exit 1
fi
- if: steps.state.outputs.resume != 'true'
uses: ./.github/actions/setup-go
Expand Down
Loading