diff --git a/scripts/release.sh b/scripts/release.sh index 8d1f60b..b18558f 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -43,6 +43,33 @@ done step() { printf '\n\033[1m== %s\033[0m\n' "$1"; } +# The commit the tag must point at, and the check that it is published. +# +# This is not tidiness. Gitea creates the tag for a release at whatever the remote's default-branch HEAD +# is *at the moment the release is created* — and this script does not create tags itself. So publishing +# before pushing puts the tag on the previous commit. Measured: v1.0.2 was published with the 1.0.2 +# binaries (the checksums match a local build of the right commit) but its tag landed on the 1.0.1 +# commit, because that was still origin/main; `v1.0.1` and `v1.0.2` ended up naming the same tree, and +# anyone reading the release's source would get the version before the fix. +# +# So the target is passed explicitly below, and a release whose commit is not pushed is refused: a tag +# that exists only locally would be created against whatever the remote has, which is the same defect +# with a different cause. +HEAD_SHA="$(git rev-parse HEAD)" +if [[ "$DRY_RUN" -eq 0 ]]; then + if [[ -n "$(git status --porcelain)" ]]; then + echo "release: the working tree has uncommitted changes; commit them first. The tag must name the" >&2 + echo " commit the binaries were built from, and an uncommitted build names nothing." >&2 + exit 1 + fi + if ! git branch -r --contains "$HEAD_SHA" 2>/dev/null | grep -q .; then + echo "release: ${HEAD_SHA} is not on any remote branch. Push first: Gitea creates the tag at the" >&2 + echo " remote's default-branch HEAD, so publishing now would tag the previous commit." >&2 + exit 1 + fi +fi +echo "tag ${TAG} will point at ${HEAD_SHA} ($(git log --oneline -1 "$HEAD_SHA" | cut -d' ' -f2-))" + step "building ${TAG}" # VERSION is passed through so the binary reports the tag it was published under, which is what an # operator sees in `msa-agent version` and in the agent's startup log line. @@ -90,11 +117,14 @@ if [[ -n "$EXISTING" ]]; then RELEASE_ID="$(printf '%s' "$EXISTING" | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')" echo "reusing release ${TAG} (id ${RELEASE_ID})" else - BODY="$(python3 - "$TAG" "$VERSION" <<'PY' + BODY="$(python3 - "$TAG" "$VERSION" "$HEAD_SHA" <<'PY' import json, sys -tag, version = sys.argv[1], sys.argv[2] +tag, version, head = sys.argv[1], sys.argv[2], sys.argv[3] print(json.dumps({ "tag_name": tag, + # Pinned, rather than left to the server. Without it Gitea tags the default-branch HEAD as it is + # when the release is created, which is a different commit whenever the push has not happened yet. + "target_commitish": head, "name": f"simadmin-relay agent {version}", "body": ( "Outbound-only node agent for SimAdmin nodes, cross-compiled for the ARM Debian boxes SimAdmin "