Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/release-script-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,29 @@ jobs:
./scripts/cut-release.ps1 -PostReleaseOnly -Branch develop -DryRun
if ($LASTEXITCODE -ne 0) { throw "PostReleaseOnly dry-run exited $LASTEXITCODE" }

- name: The asset version follows the tag, and only a final tag
shell: pwsh
run: |
# <graphcompose.examples.assetVersion> records the version the committed previews
# were rendered at, and ExampleVersion accepts a released X.Y.Z and nothing else.
# So it must move on a final cut and stay put everywhere else: carried into a
# -SNAPSHOT by the post-release bump it would throw before a single preview was
# compared, and carried into an -rc it would have the previews advertise a release
# that does not exist. Assert the branch that ran, not the file it would write:
# -DryRun mutates nothing, so the notice is the only evidence either way.
$final = ./scripts/cut-release.ps1 -Version 9.9.9 -Branch develop -DryRun -SkipShowcase *>&1 | Out-String
if ($LASTEXITCODE -ne 0) { throw "final dry-run exited $LASTEXITCODE" }
if ($final -notmatch 'asset version -> 9\.9\.9') { throw 'a final cut must move the asset version' }
if ($final -notmatch 'Re-render the README assets') { throw 'a final cut must re-render the previews' }

$rc = ./scripts/cut-release.ps1 -Version 2.1.0-rc.1 -Branch develop -DryRun -SkipShowcase *>&1 | Out-String
if ($rc -match 'asset version ->') { throw 'a pre-release cut must NOT move the asset version' }
if ($rc -notmatch 'Skipped the README assets') { throw 'a pre-release cut must leave the previews alone' }

$post = ./scripts/cut-release.ps1 -PostReleaseOnly -Branch develop -DryRun *>&1 | Out-String
if ($post -match 'asset version ->') { throw 'the post-release bump must NOT move the asset version' }
Write-Host 'asset version: moves on a final cut, stays put on a pre-release and post-release.'

- name: Dry-run a pre-release (RC) cut
shell: pwsh
run: |
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ follow semantic versioning; release dates are ISO 8601.

### Build

- **A release re-renders the previews it publishes.** The committed previews record
the version they were rendered at, and until now nothing moved it: a cut bumped
every pom, regenerated the showcase site at the new version, and left
`assets/readme/**` on the release before — with the drift gate comparing both
sides at the old version and staying green through it. The cut now bumps that
property with the tag and re-renders the previews from the same catalogue the
site is built from, before the verify step that checks them. `-SkipShowcase`
skips the published site under `web/` and no longer skips these, since they ship
in the repository; `-PostReleaseOnly` leaves them alone, because they belong to
the tag rather than to the branch it opens.
- **A committed preview cannot fall behind the code that renders it.** README and
the showcase site read files under `assets/readme/**` rather than rendering
anything, and nothing held those files to the catalogue: a change to an example,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package com.demcha.documentation;

import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Keeps the release script's asset step joined to the commit it has to land in.
*
* <p>A cut re-renders the previews under {@code assets/readme} at the version it is tagging, and
* commits them with everything else it bumped. The two halves sit in different parts of the
* script and neither fails without the other: a refresh that is not staged leaves the release
* carrying previews from the version before, and a staged path nothing refreshes commits
* whatever happened to be in the working tree. Both come back as the same symptom — a release
* publishing figures that do not match the code — which is what the drift gate was written to
* end, and what this keeps it from being reintroduced beneath.</p>
*
* <p>The order matters as much as the presence. The verify step runs the drift gate, so a
* refresh scheduled after it fails the cut on the previews it was about to fix.</p>
*/
class ReleaseAssetStepGuardTest {

private static final Path SCRIPT = RepoRoot.get().resolve("scripts/cut-release.ps1");

@Test
void theReleaseScriptRefreshesTheCommittedPreviewsAndCommitsThem() throws IOException {
String script = Files.readString(SCRIPT);

assertThat(script)
.describedAs("cut-release.ps1 no longer refreshes the committed previews: a cut "
+ "would tag a release whose figures are the previous one's")
.contains("Refresh-CommittedPreviews");
assertThat(script)
.describedAs("cut-release.ps1 no longer stages assets/readme/examples, so a refresh "
+ "would happen and never reach the release commit")
.contains("'assets/readme/examples'");
assertThat(script)
.describedAs("cut-release.ps1 no longer moves the version the previews record; the "
+ "drift gate would then compare a release's previews at the version before "
+ "it, and pass")
.contains("function Update-AssetVersion");
}

/**
* The version the previews record moves on a final cut and on nothing else.
*
* <p>{@code ExampleVersion} accepts a released {@code X.Y.Z} and rejects everything else, so
* the property cannot ride along with the generic pom bump: the post-release step carries the
* train to {@code X.Y.(Z+1)-SNAPSHOT}, which would throw before a single preview was compared,
* and a pre-release cut carries {@code X.Y.Z-rc.N}, whose qualifier-stripped form names a
* release that does not exist yet — the previews would advertise it.</p>
*
* <p>The three modes are exercised for real in {@code release-script-check.yml}. What this
* pins is the wiring that makes those outcomes structural rather than incidental: the generic
* bump does not touch the property, and the step that does sits inside the final-release
* branch.</p>
*/
@Test
void onlyAFinalCutMovesTheVersionThePreviewsRecord() throws IOException {
String script = Files.readString(SCRIPT);

int genericBump = script.indexOf("function Update-PomVersion");
int assetBump = script.indexOf("function Update-AssetVersion");
assertThat(genericBump).describedAs("Update-PomVersion is gone").isNotNegative();
assertThat(assetBump).describedAs("Update-AssetVersion is gone").isNotNegative();
assertThat(script.substring(genericBump, assetBump))
.describedAs("the generic pom bump touches the asset version again — it runs for "
+ "the post-release SNAPSHOT and for a pre-release, and both values are "
+ "ones the examples module refuses")
.doesNotContain("assetVersion");

int finalBranch = script.indexOf("if ($isFinalRelease) {", script.indexOf("Step 4 "));
int call = script.indexOf("Update-AssetVersion (Join-Path");
assertThat(finalBranch).describedAs("the final-release branch around Step 4 is gone")
.isNotNegative();
assertThat(call)
.describedAs("the asset version is moved outside the final-release branch, so a "
+ "pre-release cut would move it too")
.isGreaterThan(finalBranch);
}

@Test
void thePreviewsAreRefreshedBeforeTheStepThatChecksThem() throws IOException {
String script = Files.readString(SCRIPT);

int refresh = script.indexOf(" Refresh-CommittedPreviews");
int verify = script.indexOf("Run mvnw clean verify");
assertThat(refresh).describedAs("the refresh call is gone").isNotNegative();
assertThat(verify).describedAs("the verify step is gone").isNotNegative();

assertThat(refresh)
.describedAs("the previews are refreshed after the verify step that compares them, "
+ "so a cut fails on exactly the files it was about to bring up to date")
.isLessThan(verify);
}
}
10 changes: 4 additions & 6 deletions examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,10 @@
only compare like with like because the surefire configuration below
pins the display version to this value.

Nothing moves it yet. Until cut-release.ps1 re-renders the previews and
bumps this in the same commit as the tag, a release leaves the previews
at the version below while the showcase site goes out at the new one —
and the drift gate, comparing both sides at this value, stays green
through it. That step is the reason this property exists; it is not
written yet.
cut-release.ps1 moves it on a final cut, in the same commit as the tag and
next to the step that re-renders the previews at that version. A
pre-release cut leaves both alone: the version they would carry is this
one's qualifier stripped, which names a release that does not exist yet.
-->
<graphcompose.examples.assetVersion>2.1.0</graphcompose.examples.assetVersion>

Expand Down
Loading
Loading