diff --git a/docs/src/how-to-release.md.in b/docs/src/how-to-release.md.in index 3f89dbafa..94183377c 100644 --- a/docs/src/how-to-release.md.in +++ b/docs/src/how-to-release.md.in @@ -14,8 +14,12 @@ Much of the mechanical work below is automated by `tools/release.sh`, which has `rpmbuild` is mandatory for `pre-release` (the SRPM is a required release artifact); `rpmlint` is optional and is run only if installed. The ReadTheDocs admin steps and the flip from pre-release to public remain manual. Each subcommand is idempotent, so a partial run can be re-invoked safely. +**If you are running `pre-release`, do not also do the version-bump / tarball / SRPM / GitHub-release-and-tag steps below by hand first.** `pre-release` does all of that itself, in the order that makes the tag land correctly (version bump commit pushed *before* the tag is cut). Manually creating the GitHub release/tag before the version-bump commit is pushed reproduces the exact bug called out under "Create the GitHub release tag" below -- the tag gets pinned to whatever commit `main` was at that moment, forever, even though it looks like `--target main`. Worse, `pre-release`'s idempotency check only confirms *a* release exists for the tag; it does not verify the tagged commit actually contains the version bump, so a subsequent `pre-release` run will not notice or fix a bad tag -- it will just keep uploading assets to it. If this happens, the only fix is to delete the GitHub release and the tag (`git push --delete origin vX.Y.Z`, plus the local tag) and recreate it pointing at the correct commit. + ## Manual steps +These are the individual steps `pre-release`/`docs`/`afterwork` automate, kept here as a reference for what each phase actually does (and as a fallback if you need to run a step by hand). Do not run these separately from the script for a release the script is also handling. + * Update version found in `mlr --version` and `man mlr`: * Edit `pkg/version/version.go` from `6.2.0-dev` to `6.3.0`. @@ -38,6 +42,7 @@ Much of the mechanical work below is automated by `tools/release.sh`, which has * Create the GitHub release tag: + * If `pre-release` is handling this release, skip this step -- do not create the release/tag by hand first. See the warning above. * Don't forget the `v` in `v6.3.0` * Write the release notes -- save as a pre-release until below * Be sure the commit being used is the (non-`main`) PR commit containing the new version, or, `main` after that PR is merged back to `main`. (Otherwise, the release will be tagging the commit _before_ the changes, and `mlr version` will not show the new release number.) diff --git a/tools/release.sh b/tools/release.sh index bdb230c2d..612dc9bb4 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -127,6 +127,32 @@ push_if_needed() { run_cmd git push "$@" origin "$branch" } +# verify_release_tag_commit guards against the classic ordering bug: a +# release/tag for $TAG created (by hand, or by anything other than this +# script's own Phase 4) BEFORE the version-bump commit was pushed. Git tags +# don't retroactively follow branch movement, so once cut against the wrong +# commit they stay wrong -- and a same-tag `gh release view` success on a +# resumed run looks identical whether the tag is right or wrong. This checks +# the actual tagged commit's pkg/version/version.go, not just tag existence. +verify_release_tag_commit() { + local tag="$1" + # Read-only (fetch/rev-parse/show), so this runs even under --dry-run -- + # skipping it there would hide exactly the bug it exists to catch. + git fetch --tags origin >/dev/null 2>&1 || true + if ! git rev-parse --verify --quiet "refs/tags/$tag" >/dev/null; then + # Not fetchable yet (e.g. propagation lag right after creation); nothing + # to check against. + return 0 + fi + local tagged_version + tagged_version="$(git show "${tag}:pkg/version/version.go" 2>/dev/null \ + | awk -F'"' '/^var[[:space:]]+STRING/ { print $2; exit }')" + if [ "$tagged_version" != "$VERSION" ]; then + die "tag '$tag' points at a commit where pkg/version/version.go reports '$tagged_version', not '$VERSION' -- it was likely created before the version-bump commit landed (see docs/src/how-to-release.md.in's warning on tag ordering). Delete the release and the tag (locally and on origin) and recreate it pointing at the correct commit before continuing." + fi + note "verified tag '$tag' points at a commit with version.go == '$VERSION'" +} + # ============================================================================ # Argument parsing # ============================================================================ @@ -566,6 +592,8 @@ phase_4_github_release() { --notes-file "$NOTES_FILE" fi + verify_release_tag_commit "$TAG" + banner "PHASE 4: upload assets" # --clobber so that a resumed run can re-upload a replaced artifact. run_cmd gh release upload "$TAG" "$tgz" --clobber