test(guards): hold the open changelog entry to the version in the poms - #521
Merged
Conversation
The post-release step opens the next development line by incrementing the patch unconditionally, so a minor release leaves the poms naming a different version than the changelog for the whole cycle. While the two disagree, an @SInCE written in between has two answers available, and that is a public API contract: across the 31 commits where the poms said 2.0.1-SNAPSHOT and the changelog said v2.1.0, nine wrote @SInCE 2.1.0 and four wrote @SInCE 2.0.0. An entry counts as open because it carries no date, not because of the word after the version. The 2.1.0 line was opened as "in progress", which a check keyed on "Planned" would have watched go past. The wording is then asserted separately, since cut-release.ps1 dates an entry by replacing that literal and leaves anything else undated. The comparison is a pure function over (changelog, pomVersion), so its failing branches are driven from strings instead of only ever being observed on the repository's own files.
…ut matches Three shapes got past the check or tripped it wrongly. A version stopped at X.Y.Z, so "## v2.2.0-rc.1 - 2026-09-01" parsed as version 2.2.0 on a line beginning "rc.1" — neither dated nor open in any useful sense. A shipped pre-release therefore counted as a second open entry and would have held the build red against a consistent changelog. The qualifier is part of the version now, and both sides are compared by release line. The wording check normalised the separator away, so "## v2.1.3 - Planned" with an ASCII hyphen passed — the likeliest thing to type by hand, and the one shape the cut cannot see, since it replaces the em-dash literal. It is now held to what the cut actually matches, and "Planned (target)" is accepted rather than rejected, because the cut does date it. A "##" heading naming no release left the check with nothing to compare and therefore green: "## Unreleased" and "## v2.2 - Planned" both passed. The topmost one must now be a readable entry. The drift is reported ahead of the wording, so a commit that gets both wrong names the release the two sources disagree about rather than only the marker. Getting the wording wrong does not ship an entry undated, as the note claimed: Step 2b stops the cut on the missing date. It stops the release instead of the commit that caused it, which is the smaller thing this actually buys.
Both read as oversights from the code alone: a mistyped heading level slips through, and an entry and a pom that agree on the wrong release are accepted. Closing the first by widening the entry pattern would start reading subsection headings as releases, and the second is not closeable from these two sources at all. The note says so where whoever edits the method will see it, rather than in a pull request nobody reads twice.
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.
Why
The post-release step opens the next development line by incrementing the patch,
unconditionally (
Get-NextSnapshotVersion).A GA of
X.Y.Ztherefore always lands the train onX.Y.(Z+1)-SNAPSHOT— right when thenext release is a patch, wrong from the first commit of the cycle when it is a minor.
While the poms and the changelog name different releases, an
@sincewritten in betweenhas two answers available, and that is a contract with the consumer rather than a
bookkeeping detail. The split is measurable. Across
70c8016b..e7a54958— the 31 commitswhere the poms said
2.0.1-SNAPSHOTand the changelog saidv2.1.0— nine commits wrote@since 2.1.0and four wrote@since 2.0.0, and #436 had to retag the latter when theline was corrected. No commit ever wrote
@since 2.0.1.Nothing was red for any of it.
VersionConsistencyGuardTestheld the train poms againsteach other and against the README, and both states are internally consistent, so it passed
either way.
What changed
theOpenChangelogEntryNamesTheVersionUnderDevelopmentfails the build when the entryleft open in
CHANGELOG.mdand the working pom version name different releases. The openentry is where the next version gets recorded first, so the poms are held to it from that
commit rather than at the next cut.
version. The 2.1.0 line was opened as
## v2.1.0 — in progress; a check keyed onPlannedwould have watched that whole line go past — the drift this exists to catch, inthe wording that hides it. Four spellings appear in this repository's history:
Planned,in progress,Unreleased,unreleased.##heading that names no release is reported, not skipped.## Unreleasedand## v2.2 — Plannedwould otherwise leave the check with nothing to compare, which passesfor the wrong reason. Silence and success must not look alike.
X.Y.Zreads## v2.2.0-rc.1 — 2026-09-01as version2.2.0on a line beginningrc.1— neitherdated nor open in any useful sense — so a shipped pre-release would count as a second
open entry and hold the build red against a consistent changelog. Both sides are compared
by release line, so an
-rc.Npom agrees with the line it targets.Step 2
replaces the literal
— Planned, em dash included, so an ASCII hyphen is as invisible toit as another word. Getting this wrong does not ship an entry undated — Step 2b stops the
cut on the missing date — but it stops the release rather than the commit that caused
it.
Planned (target)is accepted, since the replacement does date it.release the two sources disagree about rather than only the marker.
-PostReleaseOnlybumps the train at Step 3 and runs thisvery test at Step 3b before committing at Step 4, without writing a heading; requiring one
would fail the commit that opens the window.
versionDriftProblem(changelog, pomVersion)rather than assertionsinline in the test, so its failing branches can be driven from strings. A guard whose red
path never executes is present, not tested.
Verification
./mvnw -B -ntp clean verify -pl :graph-compose-core,…,:graph-compose-coverage -am→BUILD SUCCESS, 1557 tests across the eight modules (476 / 144 / 18 / 5 / 90 / 104 / 720),
0 failures, 0 errors. The engine module goes 451 → 476.
New
ChangelogVersionParsingTest, 25 tests, driving the check from strings:in progress,Unreleased, no marker at all, adecorated marker, CRLF, a heading naming no version, and a date further along the line;
-rc.N/-beta.Nreads as shipped, an open one keeps itsqualifier, and an
-rc.Npom agrees with the line it cuts;Planned (target);wording the cut cannot date, a leftover below a shipped release, and a topmost heading
naming no release.
Held against real history rather than invented strings alone: with
git show 70c8016b:CHANGELOG.mdin the tree the gate goes BUILD FAILURE, and the post-release commit
bdb8d8aeleaves noundated entry, so Step 3b stays green.
Known limits
Two heading shapes stay invisible: a level typo (
### v2.2.0 — Planned) and an indented##. Neither has occurred in this repository, and covering them means matching headings theformat does not produce — the check stops where the evidence does.
It also cannot catch a changelog entry and a pom that were wrong together from the start:
both are internally consistent, and nothing in the tree distinguishes them. It catches one
being corrected without the other, which is the shape the correction actually takes.
Lane: test — build/docs guard. No production code, no public API change.
Relates to #457. That issue also asks for the next line to be chosen deliberately rather than
guessed; the script still increments the patch, so this holds the drift rather than preventing it.