--- name: prepare-minor-release description: Prepare an Axelix minor lockstep release — the pre-release housekeeping changes, a hand-editable release-notes draft, and the post-release bump to the next -SNAPSHOT. Use this skill whenever the user says they are cutting, preparing, or shipping a release ("we're releasing 1.1.0", "prepare the minor release", "release housekeeping"), asks to draft or write release notes for a version, or asks to move master to the next snapshot / development version after a release. Also use it for the docs part alone ("swap the upcoming notices for released notices") — that swap is a post-release-housekeeping step. --- # Prepare a minor release Axelix minors are **lockstep** releases: every component (starters, plugins, Master JAR/Docker/Helm) ships together under one `X.Y.0` version, marked by a `vX.Y.0` tag on `master`. The authoritative procedure lives in `docs/docs/more/development/releases.mdx` — read it before starting; if it disagrees with this skill, the docs win and this skill should be updated. This skill covers three phases. Figure out from the conversation which one the user is in; if the target version is not stated, derive it from `axelixVersion` in the root `gradle.properties` (strip `-SNAPSHOT`) and confirm it with the user before editing anything. 1. **Pre-release housekeeping** — version, playgrounds. 2. **Release notes draft & docs truth audit** — diff against the previous minor tag, and verify the docs still tell the truth for the new version. 3. **Post-release housekeeping** — move `master` to the next minor's `-SNAPSHOT`, swap the docs notices. ## Hard boundaries The point of these boundaries is that a release is a deliberate, human-triggered act — the skill prepares, the developer pulls the trigger. - **Never commit and never push.** Housekeeping must land as a *single commit on `master`* so the release can be reset or cherry-picked cleanly — the developer reviews the staged diff and makes that commit themselves. Leave every change in the working tree and show a summary. - **Never create tags.** The release pipeline creates `vX.Y.0` after its pre-release checks pass; a hand-made tag bypasses those checks. - **Never launch the pipeline.** `.github/workflows/release-lockstep.yaml` is a `workflow_dispatch` the developer triggers manually. Do not run it via `gh workflow run` or otherwise. ## Phase 1 — Pre-release housekeeping All of the following becomes one commit (made by the user). Two groups of edits: ### 1. Fleet version In the **root** `gradle.properties`, set `axelixVersion` to the exact release version — `1.1.0-SNAPSHOT` → `1.1.0`. This is the value the pipeline reads and what the tag is named after. The root `gradle.properties` is the **only** place the version lives — every component inherits it from there. Subproject `gradle.properties` files never contain `axelixVersion`; do not touch them. ### 2. Playgrounds The example apps under `playgrounds/` are deliberately separate projects: they do **not** inherit `axelixVersion` and pin the Axelix starter and plugin versions they consume explicitly. Bump **every** Axelix pin — starters *and* plugins — to the release version. Find the pins by searching rather than trusting a memorized list (playgrounds get added): ```bash grep -rn "com.axelixlabs" playgrounds/ --include="build.gradle*" --include="pom.xml" ``` - Gradle apps: the `id("com.axelixlabs.axelix") version "..."` plugin line and the `com.axelixlabs:axelix-spring-boot-N-starter:...` dependency string in `build.gradle.kts`. - Maven apps: the `` of every `com.axelixlabs` artifact (starter dependency and `axelix-maven-plugin`) in `pom.xml`. Afterwards verify no Axelix `-SNAPSHOT` or stale pin survived: `grep -rn "com.axelixlabs" playgrounds/ --include="build.gradle*" --include="pom.xml" | grep -v "X.Y.0"` should only return lines that carry no version at all (e.g. Maven `` lines). ### Wrap-up Show `git status` and a short per-group summary of what changed, plus the verification grep results. Remind the user this is meant to be a **single housekeeping commit on `master`**, and that after it lands they launch `release-lockstep.yaml` themselves. ## Phase 2 — Release notes draft The pipeline creates the tag but not the notes — the developer writes them by hand against the tag. Draft them so the developer edits instead of starting from scratch. 1. **Find the previous minor tag**: the highest `vX.Y.0` tag. Ignore pre-releases (`v1.0.0-M1`) and patch tags (`vX.Y.Z` with a non-zero patch, e.g. `v1.0.2` — fleet tags too, but cut from a patch branch) — the comparison base is the previous *minor* cut from `master`. 2. **Collect the changes**: `git log vPREV..master` (merge commits and PR references are usually the best unit of meaning; `gh pr view` for detail when a commit message is thin). 3. **Categorize** into exactly these sections: - **New features** - **Bug fixes** - **Noteworthy changes** — not breaking, but users should know (behavior changes, defaults within the contract, deprecations, notable dependency upgrades). - **Breaking changes** — defined by the compatibility contract in `docs/docs/more/compatibility-and-versioning.mdx`, *not* by Java-level API diffs. Breaking means: changes to Master's **configuration contract** (property names, default values, types — for both the Helm chart and the standalone JAR; the contract promises these change only in majors, so finding one in a minor is a red flag to raise with the user), or revisited **interaction protocols** between components (Master ↔ starter, plugin ↔ starter — these force the fleet-wide `major.minor` upgrade). Public Java API changes of Master or the starters are explicitly **internal** and are *not* breaking. 4. **Write the draft** to `release-notes-vX.Y.0.md` in the repository root. It is a working file for the developer: it stays **untracked** and must not slip into the housekeeping commit — say so explicitly, and never `git add` it. The developer publishes the final text against the `vX.Y.0` tag manually. ### Docs truth audit — mandatory, never skip The same `vPREV..master` diff that feeds the notes also invalidates documentation: a behavior change makes some pages describe how Axelix *used to* work. Shipping the release with those pages untouched misinforms users, so this audit is a **required** part of every release preparation. Run it every time Phase 2 runs — even when the user only asked for release notes, and even when the diff looks trivially small. 1. Go through **every** change collected in step 2, not only the ones that made it into the notes. **Noteworthy changes** and **Breaking changes** are the prime suspects, but a **New feature** can also supersede a documented manual procedure. 2. For each change, hunt `docs/docs/` for statements the change invalidates: grep for the affected property names, endpoints, class names, and UI wording, and skim the pages of the affected component. You are looking for text that was true on `vPREV` but is no longer true on `master`. 3. For every stale spot found, you **must** propose a treatment — silently leaving it is not an option: - If a whole section describes behavior that from `X.Y.0` on is no longer required or was replaced (e.g. a manual step the release now automates), keep the section for users on older versions and mark it with `` directly under its heading (imported from `@site/src/components`, sibling of the Released/Upcoming notices). `X.Y.0` is the release being cut — the first version where the section stops applying. - If the text is simply wrong going forward (changed default, renamed property, different behavior), propose a rewrite of the text itself so it correctly informs users about the change. - Every touched English page has a Russian mirror under `docs/i18n/ru/docusaurus-plugin-content-docs/current/` — treat both, or the docs CI build fails on the `ru` locale. 4. Report the findings as a list (code change → affected page/section → suggested treatment), get the user's agreement, and apply the edits as working-tree changes only — like everything else in this skill, the user commits. If the audit finds nothing stale, say explicitly that it ran and came back clean; never leave it implicit. ## Phase 3 — Post-release housekeeping After the pipeline has published the fleet and created `vX.Y.0`, development on `master` moves to the next minor. One commit (again: stage only, the user commits). Two groups of edits: ### 1. Snapshot bump - Root `gradle.properties`: `axelixVersion` → `X.(Y+1).0-SNAPSHOT`. - Playgrounds: **all** Axelix pins — starters *and* plugins — → `X.(Y+1).0-SNAPSHOT`, found with the same grep as in Phase 1. ### 2. Docs notices While a minor is in development, docs sections shipping with it carry an `` (components in `docs/src/components/`). Now that the minor is cut, each of those becomes a `` — where `X.Y.0` is the version **just released**, not the new snapshot. - Find every usage: `grep -rn "UpcomingReleaseNotice" docs/`. - In each page, replace the JSX usage **and** swap the import (`UpcomingReleaseNotice` → `ReleasedInNotice`, both come from `@site/src/components`). - Every English page under `docs/docs/` has a mirrored Russian copy under `docs/i18n/ru/docusaurus-plugin-content-docs/current/` — update both, or the docs CI build fails on the `ru` locale. - All existing notices should belong to the release just cut (they were added for it); if a notice looks like it belongs to a *future* release, stop and ask the user instead of converting it. - Verify: the grep above must come back empty for `docs/docs/` and the ru mirror when done. Verify with the same greps as Phase 1, show the summary, let the user commit.