Name the vote-passed versions explicitly and validate them before use - #822
Merged
Conversation
wu-sheng
force-pushed
the
fix/release-vote-passed-prompts
branch
from
August 14, 2026 02:01
62c440b to
9a3b90f
Compare
`vote-passed <old_version>` published the version resolved from the tag and
deleted the version passed as the argument. Two versions that do opposite things,
and only one of them positional - the deleted one. Reading `vote-passed 9.7.0` as
"release 9.7.0" is the natural interpretation, and it would have promoted 9.7.0
into dist/release and then immediately svn rm'd it.
Take them by name, or ask for them:
vote-passed --release 9.7.0 --old_version 9.6.0
vote-passed --release 9.7.0 --no-cleanup
vote-passed # asks for both
Anything not named is prompted for, each prompt saying what will happen to that
version. Positional arguments are now an error pointing at the named form, so
existing muscle memory fails loudly rather than quietly meaning something else.
Equal versions are refused and the release version must already be tagged.
RELEASE_VERSION and OLD_VERSION still work, with the flags winning over them.
Versions are validated by one anchored regex, shared with cleanup. A glob such as
[0-9]*.[0-9]*.[0-9]* accepts "9.7.0/", which is textually different from "9.7.0"
and so slips past the equality guard, yet SVN canonicalises the trailing slash -
cleanup would have deleted the release promote had just published. Anchoring also
rejects whitespace, v-prefixes, traversal and command characters before any of it
reaches an svn path.
The defaults behind the prompts were wrong too. The release version came from the
highest version tag, but releases are not monotonic: a 9.6.1 patch cut from the
9.6.0 line after 9.7.0 has shipped is newer in time but lower in version, so the
suggestion would have been the already-released 9.7.0. Order by tag creation date
instead - maven-release-plugin writes annotated tags, so that timestamp belongs to
the tag and survives fetches. The old version now comes from dist/release, the
only place that knows what this release actually replaces, with the version being
released filtered out so re-running after a partial failure cannot offer to delete
it.
Both detectors are genuinely best effort. Under `set -euo pipefail` a failed
svn ls, or a grep matching nothing - which is exactly the state after a partial
failure, when only the new release remains - aborted the release instead of
yielding no suggestion, leaving the "could not read dist/release" branch
unreachable. They now return success with empty output.
Testing the flags uncovered a bug that predates them and reached every command.
error() wrote to stdout, and resolve_version is always called as
`version=$(resolve_version ...)`, so its message was captured into the variable
instead of shown: releasing an untagged version aborted, correctly, but printed
nothing about why. info/warn/error now write to stderr. The email templates use
plain echo, so they stay on stdout and remain pipeable.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
wu-sheng
force-pushed
the
fix/release-vote-passed-prompts
branch
from
August 14, 2026 03:33
9a3b90f to
10982b3
Compare
hanahmily
approved these changes
Aug 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
vote-passed <old_version>published the version resolved from the tag and deleted theversion passed as the argument:
Two versions that do opposite things, and only one of them positional — the deleted one.
Reading
vote-passed 9.7.0as "release 9.7.0" is the natural interpretation, and it wouldhave promoted 9.7.0 into
dist/releaseand then immediately removed it.Fix
Take them by name, or ask for them:
./tools/releasing/release.sh vote-passed --release 9.7.0 --old_version 9.6.0 ./tools/releasing/release.sh vote-passed --release 9.7.0 --no-cleanup ./tools/releasing/release.sh vote-passed # asks for bothAnything not named is prompted for, each prompt saying what happens to that version:
memory fails loudly instead of quietly meaning something else.
x.y.z, and the release versionmust already be tagged.
RELEASE_VERSION/OLD_VERSIONstill work; flags win over them.The defaults behind those prompts were wrong too
The release version came from the highest version tag, but releases are not monotonic.
A
9.6.1patch cut from the9.6.0line after9.7.0has shipped is newer in time butlower in version:
Ordered by tag creation date now —
maven-release-pluginwrites annotated tags, so thattimestamp belongs to the tag and survives fetches. The old version comes from
dist/release, the only place that knows what this release actually replaces, excludingthe version being released so re-running after a partial failure cannot offer to delete it.
A pre-existing bug this uncovered
error()wrote to stdout, andresolve_versionis always called asversion=$(resolve_version ...). Its message was captured into the variable rather thanshown — releasing an untagged version aborted correctly but printed nothing about why, and
this reached every command, not just
vote-passed.info/warn/errornow write to stderr. The email templates use plainecho, so theystay on stdout and remain pipeable.
The old version was also unvalidated, so a typo like
--old_version 9.6would have beenhanded to
svn rmas a path.Testing
Against the live repository and Apache SVN:
--release 9.7.0 --old_version 9.6.0--old-version(kebab alias)--release 9.7.0 --no-cleanupdist/releaseuntouchedRELEASE_VERSION/OLD_VERSIONvote-passed 9.6.0--release 9.9.9(untagged)--old_version 9.6--releasewith no value /--bogusv9.6.1on the 9.6.0 lineemail announcepiped🤖 Generated with Claude Code