ref:main
#!/usr/bin/env bash
set -euo pipefail
# Finalize the release: fan in the four binaries the per-ISA build jobs uploaded
# to the draft, compute the combined SHA256SUMS, and publish.
#
# Runs after build-arm64 and build-amd64 (depends_on), so all four assets are
# present on the draft. Because the runner can't pull another job's *workspace*,
# fan-in goes through the release-asset API: `release download` retrieves each
# binary from the draft. Publishing last keeps the release invisible to
# `anvil update` (which filters drafts) until it is complete — the #40 property.
git config --global --add safe.directory /workspace
# Only main publishes. On a PR this job is a no-op, so the pipeline still
# exercises the parallel per-ISA builds without cutting a release.
if [ "${ANVIL_BRANCH:-}" != "main" ] && [ "${ANVIL_BRANCH:-}" != "refs/heads/main" ]; then
echo "Not on main — nothing to publish."
exit 0
fi
if [ -z "${ANVIL_TOKEN:-}" ]; then
echo "ERROR: ANVIL_TOKEN secret not set." >&2
exit 1
fi
# Same version the build jobs used: latest published release + 1 (drafts
# excluded), so this resolves to the tag they created the draft under.
VERSION=$(bash ci/release.sh)
if [ -z "$VERSION" ]; then
echo "ERROR: ci/release.sh returned empty version" >&2
exit 1
fi
SERVER="${ANVIL_SERVER_URL:-https://anvil.fangorn.io}"
REPO="fangorn/anvil-cli"
AUTH=(-H "Authorization: Bearer ${ANVIL_TOKEN}")
# Roll the draft back if anything below fails, so a broken run leaves nothing —
# not even a draft — behind. Uses curl, not the anvil CLI, so it works even if
# the CLI bootstrap below fails.
cleanup_release() {
echo "==> Publish failed — rolling back draft $VERSION" >&2
curl -sf -X DELETE "${AUTH[@]}" "${SERVER}/api/v1/${REPO}/releases/${VERSION}" >&2 || true
}
trap cleanup_release ERR
# The release commands need an anvil CLI. Rather than compile one, bootstrap the
# Linux binary the build jobs *already built* and uploaded to the draft — this
# job runs on some Linux worker, so the matching-arch binary runs natively.
case "$(uname -m)" in
aarch64 | arm64) NATIVE="anvil_linux_arm64_${VERSION}" ;;
x86_64 | amd64) NATIVE="anvil_linux_amd64_${VERSION}" ;;
*) echo "ERROR: unsupported runner arch $(uname -m)" >&2; exit 1 ;;
esac
echo "==> Bootstrapping anvil CLI from draft asset $NATIVE..."
ASSET_ID=$(curl -sf "${AUTH[@]}" "${SERVER}/api/v1/${REPO}/releases/${VERSION}/assets" \
| jq -r --arg f "$NATIVE" '.assets[] | select(.filename == $f) | .id' | head -1)
if [ -z "$ASSET_ID" ]; then
echo "ERROR: $NATIVE not present on draft $VERSION (did a build job fail to upload?)" >&2
exit 1
fi
curl -sf "${AUTH[@]}" \
"${SERVER}/api/v1/${REPO}/releases/${VERSION}/assets/${ASSET_ID}/download" -o ./anvil
chmod +x ./anvil
ANVIL="$PWD/anvil"
ASSETS="anvil_linux_arm64 anvil_linux_amd64 anvil_macos_arm64 anvil_macos_amd64 anvil_windows_amd64"
# Pull the four binaries the build jobs uploaded. A missing one fails the
# download and trips the rollback — so an incomplete draft never gets published.
echo "==> Downloading built binaries from draft $VERSION..."
mkdir -p dist
FILES=""
for name in $ASSETS; do
asset="${name}_${VERSION}"
"$ANVIL" release download "$VERSION" "$asset" --output "dist/${asset}" --repo fangorn/anvil-cli
FILES="$FILES ${asset}"
done
# Combined SHA256SUMS across all four (format matches `sha256sum`).
echo "==> Computing SHA256 checksums..."
(
cd dist
sha256sum $FILES > "SHA256SUMS_${VERSION}"
)
cat "dist/SHA256SUMS_${VERSION}"
"$ANVIL" release upload "$VERSION" "dist/SHA256SUMS_${VERSION}" --repo fangorn/anvil-cli
# Everything is present — flip the draft to published.
"$ANVIL" release publish "$VERSION" --repo fangorn/anvil-cli
trap - ERR
echo "==> Published release $VERSION"