Skip to content

test(guards): hold the open changelog entry to the version in the poms - #521

Merged
DemchaAV merged 3 commits into
developfrom
test/changelog-version-guard
Aug 8, 2026
Merged

test(guards): hold the open changelog entry to the version in the poms#521
DemchaAV merged 3 commits into
developfrom
test/changelog-version-guard

Conversation

@DemchaAV

@DemchaAV DemchaAV commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Why

The post-release step opens the next development line by incrementing the patch,
unconditionally (Get-NextSnapshotVersion).
A GA of X.Y.Z therefore always lands the train on X.Y.(Z+1)-SNAPSHOT — right when the
next 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 @since written in between
has 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 commits
where the poms said 2.0.1-SNAPSHOT and the changelog said v2.1.0 — nine commits wrote
@since 2.1.0 and four wrote @since 2.0.0, and #436 had to retag the latter when the
line was corrected. No commit ever wrote @since 2.0.1.

Nothing was red for any of it. VersionConsistencyGuardTest held the train poms against
each other and against the README, and both states are internally consistent, so it passed
either way.

What changed

  • theOpenChangelogEntryNamesTheVersionUnderDevelopment fails the build when the entry
    left open in CHANGELOG.md and the working pom version name different releases. The open
    entry is where the next version gets recorded first, so the poms are held to it from that
    commit rather than at the next cut.
  • 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 ## v2.1.0 — in progress; a check keyed on
    Planned would have watched that whole line go past — the drift this exists to catch, in
    the wording that hides it. Four spellings appear in this repository's history: Planned,
    in progress, Unreleased, unreleased.
  • A ## heading that names no release is reported, not skipped. ## Unreleased and
    ## v2.2 — Planned would otherwise leave the check with nothing to compare, which passes
    for the wrong reason. Silence and success must not look alike.
  • A version keeps its pre-release qualifier. Stopping at X.Y.Z reads
    ## v2.2.0-rc.1 — 2026-09-01 as version 2.2.0 on a line beginning rc.1 — neither
    dated 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.N pom agrees with the line it targets.
  • The wording is held to what the cut actually matches.
    Step 2
    replaces the literal — Planned, em dash included, so an ASCII hyphen is as invisible to
    it 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.
  • 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.
  • Having no open entry passes. -PostReleaseOnly bumps the train at Step 3 and runs this
    very test at Step 3b before committing at Step 4, without writing a heading; requiring one
    would fail the commit that opens the window.
  • The comparison is a pure versionDriftProblem(changelog, pomVersion) rather than assertions
    inline 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:

  • which entries are open — undated, dated, in progress, Unreleased, no marker at all, a
    decorated marker, CRLF, a heading naming no version, and a date further along the line;
  • pre-release entries — a dated -rc.N / -beta.N reads as shipped, an open one keeps its
    qualifier, and an -rc.N pom agrees with the line it cuts;
  • what it accepts — agreement, no open entry at all, and Planned (target);
  • what it reports — a different release than the pom, a second open entry, an ASCII hyphen,
    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.md
in the tree the gate goes BUILD FAILURE, and the post-release commit bdb8d8ae leaves no
undated 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 the
format 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.

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.
@DemchaAV
DemchaAV merged commit 61fbdef into develop Aug 8, 2026
12 checks passed
@DemchaAV
DemchaAV deleted the test/changelog-version-guard branch August 8, 2026 10:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant