How a maintainer cuts a release. Not needed to use the framework — see README.md and docs/ for that.
-
mvn clean packagefrom the root — the whole build, tests included. Since 0.4.1 each server module prunes its owntarget/libsbefore refilling it, so a plain build no longer leaves stale jars behind and dies with "WELD-001409: Ambiguous dependencies";cleanis still the honest choice before a release.package, notinstall. Every module resolves its siblings from the reactor, so nothing is lost — and aninstallhere would write the number you are about to release into the shared local repository, filled with a pre-release build, days before Maven Central has the real one. Everything on this machine would then resolve that scratch build in place of the release, with nothing to notice. That already happened once after 0.8.0 and cost an afternoon of deleting directories; the last section of this page exists because of it. If some step genuinely needs the artifacts installed, install them into a private repository with the shared one behind it as a read-only fallback:-Dmaven.repo.local=<somewhere>/.m2head -Dmaven.repo.local.tail=$HOME/.m2/repository. -
Run the archetype smoke test —
zerozstack-archetype/smoke/README.md. It generates a project from the archetype, builds it, starts it and drives it with a headless browser. The three blockers fixed in 0.4.1 all produced a project that compiled, started and served pages while not working; only an end-to-end run catches that class of defect.Install the browser driver with
npm installinzerozstack-archetype/smoke, which is where the version is pinned and where both scripts look for it. Do not borrow an installation from another project on the machine: everything a run leaves in that folder is ignored by git, so there is no reason left to.Run both scripts.
smoke-test.mjsproves a generated project works;drop-recovery-test.mjsproves it survives losing its server and getting it back, and since 0.8.0 also proves that the bar it puts on the screen says the right sentence rather than a piece of browser jargon — which is what every release before 0.8.0 shipped, unnoticed, because nothing had ever read it. -
Update CHANGELOG.md. If several branches landed in this release, merge their entries into one set of sections first — a release entry is never one block per branch. The rules for what an entry has to do, and why, are in CONTRIBUTING.md. Then read the Breaking section as a user would; that is what people rely on when upgrading.
-
Set the version. This build uses CI-friendly versioning: change
<revision>in the rootpom.xmland every module follows, withflatten-maven-pluginresolving it in the installed POMs. The archetype needs nothing separate: its generated project's version comes from@project.version@inarchetype-metadata.xml, which that module's POM filters at build time, so it follows<revision>too. (Until 0.8.0 there was a step here saying to check it by hand.)There is also nothing temporary to remove, and nothing in the documentation changes on release day. Prose names the three numbers only —
0.9.0, never the same number with a-SNAPSHOTsuffix — andVersionStatementTestcompares on those three, so the same sentence is correct while the line is open, on the day the release is cut, and afterwards. Taking a suffix off sixteen pages and putting it back a day later served no reader and is not done. The one exception is a literal Maven coordinate somebody types, such as the archetype smoke test's-DarchetypeVersion=: that has to be the exact version on the jar,-SNAPSHOTand all, and its page says so. -
Read the four documents an AI coding assistant reads, and correct the version in each.
AGENTS.md,llms.txt,context7.jsonanddocs/AGENT_PROMPTS.mdstate the version in prose, and nothing in${revision}reaches them. This step exists becausellms.txtwas once found two releases stale — naming a version long superseded and still calling the router unimplemented — and nobody had noticed.VersionStatementTestinzerozstack-ui-componentsdoes the finding for you: run it after step 4 and it names every file and line still saying the old number, across the whole checkout and not just those four. Correct only the lines it names. A sentence about what an earlier release did keeps its own number — a previous bump walked the documentation incrementing every version it saw, and left pages claiming that work released in 0.5.0 had arrived in the version being prepared. The check is built around that distinction and will not report a sentence that says when.context7.jsonandllms.txtare also where a rule can go quietly out of date, which no check can catch. Read the rules you changed this cycle. The rule list incontext7.jsonis now copied intozerozstack-shared-api.jarat build time, so it reaches applications as well as the documentation index. -
The text check runs itself —
PublishedArtifactTextTestinzerozstack-store-eclipsestorereads the text of everything this build publishes: the strings baked into compiled classes, the resource files, the generated sources, and the project template inside the archetype. It fails the build if it finds text that was saved as UTF-8 and then read back through a single-byte code page, which is what put nonsense in place of a dash, a play triangle and a block cursor in the component library released in 0.7.0.It also refuses to pass on a partial job. It works out which modules the release publishes by reading the POM files — never from a list written down here, which would drift — and fails, naming the module, if one of them had nothing for it to read. So do not skip tests before a release, and if it says a module was not covered, that is a real gap: build the whole reactor and run it again rather than narrowing the check.
The build is configured. The account steps — Central Portal account, namespace verification and
the signing key — are documented once for the whole family in
ZeroZ DB's RELEASING.md, and the
verified com.zeroz4j namespace covers this repository too, so none of that is repeated here.
mvn clean deploy -PreleaseThe release profile attaches source and javadoc jars, signs everything, and uploads to the
portal. autoPublish is false, so the deployment waits for your approval at
central.sonatype.com/publishing/deployments
rather than going straight out — a published version can never be changed or removed.
Fourteen modules publish: zerozstack-parent, -shared-api, -apt, -client, -server-core,
-server-jaxrs, -server-jakarta, -server-helidon, -auth-oidc, -ui-components,
-store-eclipsestore, -server-test (new in 0.8.0), -bom and -archetype.
This sentence has now been wrong twice. It said nine until 0.7.0, when somebody checked
target/central-staging instead of believing it — the three server bindings and the OIDC provider
had been publishing for some time. It then said thirteen until 0.8.0, when -server-test was added
and the sentence was not. Read target/central-staging after mvn clean verify -Prelease and
count what is actually there. A sentence in a document is not a manifest, and this one has a
record.
The examples do not. They are demonstrations rather than libraries, and
zerozstack-examples/pom.xml sets maven.deploy.skip, skipPublishing, gpg.skip,
maven.source.skip and maven.javadoc.skip, all inherited by every example module. They are still
built and tested by the reactor; they are simply never published, and not signed either, since
signing artifacts nobody consumes only slows the build.
Verify before deploying, which signs everything without uploading:
mvn clean verify -Prelease -DskipTestsgit tag -a v0.9.0 -m "ZeroZ Stack 0.9.0"
git push origin v0.9.0Tag after the release is published, not before — a tag that points at something never released is worse than no tag.
Bump <revision> to the next -SNAPSHOT immediately. Not next week, not when the first feature
lands. The moment the tag is pushed, main is no longer the released version and must stop claiming
to be it.
- Set
<revision>in the rootpom.xmlto the next version with-SNAPSHOTon it. A protocol change or new public API makes it a minor bump, not a patch. - Run
VersionStatementTestand correct every line it names, exactly as at step 5 above — writing the plain number, never the-SNAPSHOT. The documentation always describes the code sitting next to it, which is the development version. - Add a
## [Unreleased]heading to CHANGELOG.md with a compare link from the tag you just pushed toHEAD.
Why this is a numbered step and not a habit. It happened after 0.8.0. The tag was pushed,
<revision> was left at the released number, and ordinary work carried on. Every mvn install from
then on overwrote the genuine published artifacts in the local repository with post-release builds:
the released jar was stamped 11:33, the one on the machine 17:04. Anything resolving those
coordinates was compiling against code that is not what is on Maven Central — silently, with nothing
to notice. Repairing it meant deleting the release's directories under
~/.m2/repository/com/zeroz4j and letting Maven re-fetch the real ones.
A released version number must never again be the version an ordinary build produces.