|
| 1 | +# Releasing Turicum |
| 2 | + |
| 3 | +*Process record, written 2026-07-18. Companion documents: `BREW.md` (Homebrew |
| 4 | +packaging, updated per release) and `homebrew/README.md`.* |
| 5 | + |
| 6 | +This document describes how to publish a Turicum release from source to Maven |
| 7 | +Central, and the follow-up steps afterwards. |
| 8 | + |
| 9 | +## 1. How the version machinery works |
| 10 | + |
| 11 | +There is a **single version source**: |
| 12 | + |
| 13 | + core/src/main/resources/turi/version.turi |
| 14 | + |
| 15 | +`turicum_versions.turi` (project root) imports it as `VERSION`; `pom.turi` |
| 16 | +consumes that; and the `turicum-maven-extension` — pinned in |
| 17 | +`.mvn/extensions.xml` — regenerates every module's `pom.xml` from `pom.turi` |
| 18 | +at the start of any `mvn` run. **Never edit a `pom.xml` by hand**; after |
| 19 | +changing `version.turi`, the next Maven invocation rewrites all poms (they are |
| 20 | +generated files but checked into git, so expect them in `git status`). |
| 21 | + |
| 22 | +The `release` profile (defined in `pom.turi`) adds two things on top of the |
| 23 | +normal build: |
| 24 | + |
| 25 | +- `maven-gpg-plugin` — signs every artifact in the `verify` phase; |
| 26 | +- `central-publishing-maven-plugin` (`org.sonatype.central`) with |
| 27 | + `publishingServerId: central` and `autoPublish: true` — uploads the bundle |
| 28 | + to the Central Portal, which validates and **releases automatically**; there |
| 29 | + is no manual "publish" click. |
| 30 | + |
| 31 | +All seven modules deploy: `core` (the `turicum` artifact), `maven`, |
| 32 | +`maven4` (the maven extensions), `cli` (including the |
| 33 | +`turicum-cli-<v>-distribution.zip` that the Homebrew formula consumes), |
| 34 | +`clifx`, `lsp`, and `testjar`. |
| 35 | + |
| 36 | +## 2. Prerequisites (one-time per machine) |
| 37 | + |
| 38 | +- `~/.m2/settings.xml` contains a `<server><id>central</id>…</server>` entry |
| 39 | + with the Central Portal user token. |
| 40 | +- A GPG secret key usable by `maven-gpg-plugin` (agent-based pinentry |
| 41 | + configured so signing works non-interactively enough for a long build). |
| 42 | +- `jamal` on the PATH (for regenerating `REFERENCE.adoc`). |
| 43 | + |
| 44 | +## 3. Release steps |
| 45 | + |
| 46 | +1. **Set the version.** Edit `core/src/main/resources/turi/version.turi`: |
| 47 | + |
| 48 | + ``` |
| 49 | + let `turicum.version` = "2.0.0"; |
| 50 | + ``` |
| 51 | + |
| 52 | + Semantic versioning: breaking language or embedding-API changes bump the |
| 53 | + major (e.g. the `bin` return-type change of `str.bytes()` and the |
| 54 | + `IMPORT`/`FILE_READ` capability split → 2.0.0). |
| 55 | + |
| 56 | +2. **Regenerate the version-carrying documentation.** |
| 57 | + |
| 58 | + - `REFERENCE.adoc` — regenerate with Jamal (the default `{`/`}` delimiters |
| 59 | + collide with sample code, hence the explicit markers): |
| 60 | + |
| 61 | + ```sh |
| 62 | + jamal --open='{%' --close='%}' REFERENCE.adoc.jam REFERENCE.adoc |
| 63 | + ``` |
| 64 | + |
| 65 | + Do this *after* a build, so sample outputs (e.g. `-version`) show the new |
| 66 | + version. The regeneration also rewrites nondeterministic sample outputs |
| 67 | + (timings, thread interleavings) — that churn is normal and committed. |
| 68 | + |
| 69 | + - `EMBEDDING.md` — the Maven dependency snippet in §1.1 is **hand-written** |
| 70 | + (outside the mdship-managed blocks) and must be bumped manually: |
| 71 | + |
| 72 | + ```xml |
| 73 | + <version>2.0.0</version> |
| 74 | + ``` |
| 75 | + |
| 76 | +3. **Verification build** — everything the release does except the upload: |
| 77 | + |
| 78 | + ```sh |
| 79 | + mvn clean verify -Prelease |
| 80 | + ``` |
| 81 | + |
| 82 | + Regenerates the poms to the new version, runs the full test suite, builds |
| 83 | + the source/javadoc jars and the CLI distribution zip, and GPG-signs it all. |
| 84 | + Javadoc errors and signing problems surface here, not mid-deploy. |
| 85 | + |
| 86 | +4. **Commit and tag.** Commit everything, including the regenerated poms and |
| 87 | + reference outputs. Tag with the bare version number — the repository's tag |
| 88 | + pattern is `1.4.0`-style, no `v` prefix: |
| 89 | +
|
| 90 | + ```sh |
| 91 | + git tag 2.0.0 |
| 92 | + git push origin main 2.0.0 |
| 93 | + ``` |
| 94 | +
|
| 95 | + (1.4.1 and 1.4.2 were released without tags; better to keep tagging.) |
| 96 | +
|
| 97 | +5. **Deploy:** |
| 98 | +
|
| 99 | + ```sh |
| 100 | + mvn clean deploy -Prelease |
| 101 | + ``` |
| 102 | +
|
| 103 | + With `autoPublish: true` the Central Portal publishes without further |
| 104 | + interaction. The artifacts appear on `repo1.maven.org` typically within |
| 105 | + 15–60 minutes; check: |
| 106 | +
|
| 107 | + ```sh |
| 108 | + curl -s https://repo1.maven.org/maven2/ch/turic/turicum-cli/maven-metadata.xml | grep release |
| 109 | + ``` |
| 110 | +
|
| 111 | +## 4. Post-release follow-ups |
| 112 | +
|
| 113 | +Once the artifacts are visible on Maven Central: |
| 114 | +
|
| 115 | +1. **Homebrew** (details in `BREW.md` §6): |
| 116 | +
|
| 117 | + ```sh |
| 118 | + homebrew/update-formula.sh # snapshots turicum@<old>.rb, bumps turicum.rb |
| 119 | + brew style homebrew/*.rb |
| 120 | + cp homebrew/turicum.rb homebrew/turicum@*.rb \ |
| 121 | + "$(brew --repository)/Library/Taps/verhas/homebrew-tap/Formula/" |
| 122 | + brew reinstall turicum && brew test turicum |
| 123 | + cd "$(brew --repository)/Library/Taps/verhas/homebrew-tap" |
| 124 | + git add Formula && git commit -m "turicum <version>" && git push |
| 125 | + ``` |
| 126 | +
|
| 127 | + Commit the changed formulae in this repository as well. |
| 128 | +
|
| 129 | +2. **Bootstrap bump.** `.mvn/extensions.xml` pins the *previous released* |
| 130 | + `turicum-maven-extension`, which is what the build bootstraps with. After |
| 131 | + the release is on Central, bump it to the new version in a follow-up |
| 132 | + commit, so the next cycle builds with the freshly released extension. |
| 133 | +
|
| 134 | +3. **GitHub release** (optional): |
| 135 | +
|
| 136 | + ```sh |
| 137 | + gh release create 2.0.0 --title "Turicum 2.0.0" --notes "..." |
| 138 | + ``` |
| 139 | +
|
| 140 | + optionally attaching `cli/target/turicum-cli-<v>-distribution.zip` for a |
| 141 | + non-Maven download. |
| 142 | +
|
| 143 | +## 5. Cautions |
| 144 | +
|
| 145 | +- **A released version cannot be re-deployed — but a deployment that fails |
| 146 | + Central's validation is discarded** and the version number stays free, so a |
| 147 | + validation failure can be retried with the same version. |
| 148 | +- **Known failure: "Invalid signature for file: ….pom.asc".** The maven |
| 149 | + extension's `TuricumModelParser.locatePom()` regenerates `pom.xml` (with a |
| 150 | + fresh `Generated on:` timestamp and `<time>` property) every time Maven |
| 151 | + resolves a project mid-build — also *after* `maven-gpg-plugin` signed the |
| 152 | + pom, so the staged pom can be newer than its signature (observed on the |
| 153 | + 2.0.0 release for `turicum` and `turicum-maven-extension`). Repair without |
| 154 | + a re-deploy: |
| 155 | +
|
| 156 | + ```sh |
| 157 | + # re-sign the staged poms whose signature is stale |
| 158 | + gpg --batch --yes -ab target/central-staging/ch/turic/<artifact>/<v>/<artifact>-<v>.pom |
| 159 | + # verify every signature in the staging tree |
| 160 | + find target/central-staging -name '*.asc' | while read a; do |
| 161 | + gpg --verify "$a" "${a%.asc}" 2>&1 | grep -q "Good" || echo "BAD $a"; done |
| 162 | + # rebuild the bundle (same layout: the ch/ tree, no directory entries) |
| 163 | + ( cd target/central-staging && zip -qrD ../central-publishing/central-bundle-fixed.zip ch ) |
| 164 | + ``` |
| 165 | +
|
| 166 | + then upload the bundle manually on central.sonatype.com ("Publish" → |
| 167 | + upload bundle) or via the Publisher API. The pom checksums need no repair: |
| 168 | + they are computed at bundle time over the staged (already-rewritten) poms. |
| 169 | + The structural fix shipped with the 2.0.0 extension: `PomXmlCreator` |
| 170 | + generates each pom **once per Maven session**, emits **no timestamp** (the |
| 171 | + output is deterministic), and skips the write entirely when the content is |
| 172 | + unchanged. The 2.0.0 release itself was built with the extension |
| 173 | + temporarily downgraded to 1.4.0 (which never wrote timestamps) and with the |
| 174 | + unused `time` property removed from `pom.turi`/`maven/pom.turi`; from the |
| 175 | + post-release bootstrap bump onward, `.mvn/extensions.xml` uses the fixed |
| 176 | + extension and the problem class is gone. |
| 177 | +- `deploy` runs the whole test suite again; the reference tests rewrite |
| 178 | + `core/src/test/resources/references_output/*.txt` with nondeterministic |
| 179 | + content — commit or discard that churn deliberately, don't be surprised |
| 180 | + by it. |
| 181 | +- The generated poms carry a generation timestamp comment, so every build |
| 182 | + touches them; this is expected. |
0 commit comments