Release preparation: repair the release path and document publishing - #514
Release preparation: repair the release path and document publishing#514milyin wants to merge 6 commits into
Conversation
The release path on this branch was dead, not merely dated. bump-and-tag wrote to zenoh-jni/Cargo.toml, publish-jvm cross-built it and publish-android installed Rust Android targets - and zenoh-jni/ was removed when the SDK moved onto the generated bindings. The first job of a release would have failed. - settings.gradle.kts included ../zenoh-flat-jni unconditionally, so a release would have been built against whatever sat on the builder's disk. Now opt-in via -PuseLocalFlatJni=true; CI passes it explicitly because it checks the sibling out, and a release does not. - The dependency version moves to gradle.properties, so the release can bump it and a rehearsal can point at a snapshot without editing tracked source. - bump-and-tag bumps version.txt and that property, and refuses a -SNAPSHOT dependency outright: consumers do not configure the snapshot repository, and snapshots mutate and expire, so a release that depended on one would be broken for everyone but us. - The zenoh-version input becomes zenoh-flat-jni-version, which is the only upstream version this repository now chooses. - Both publish workflows drop their native toolchains; the libraries arrive inside the zenoh-flat-jni artifact. The unapplied rust-android-gradle plugin goes with them. Verified: the build fails to resolve without the flag (as a release should), succeeds with it, and the bump script rejects a snapshot and rewrites both files otherwise.
Mirrors zenoh-flat-jni's guide in structure and intent, but the pipeline here is much smaller and the document says why: this repository builds no native code, so there is no matrix, no cross-compilation and no artifact to inspect - the libraries arrive inside the zenoh-flat-jni dependency. The concepts that guide already explains once - coordinates, staging, signing - are linked rather than restated. What is specific here is the ordering constraint, which is the question the transition keeps raising: zenoh-java cannot be released until the zenoh-flat-jni version it depends on is really on Central, because consumers do not configure the snapshot repository and snapshots mutate and expire. Rehearsals have no such constraint, and the document gives the ladder - local composite, snapshot dependency, snapshot publication - with what each one actually proves. Known gaps are stated rather than implied: the repaired release path has never run, there is no consumer test, and the Android NDK configuration is retained unverified.
The guide told the reader to add the snapshot repository 'for the
duration of a rehearsal' - editing tracked source, which is the thing
the rest of this change removes. That was not a procedure, it was a
gap.
The Central snapshot repository is now declared conditionally: present
only when zenohFlatJniVersion ends in -SNAPSHOT, and content-filtered to
that single module. A rehearsal names the version on the command line
and nothing is edited; a release version never ends in -SNAPSHOT, so a
release build cannot reach a mutable artifact even if someone tried. The
guarantee is structural rather than procedural.
Verified against the snapshot the zenoh-flat-jni rehearsal actually
published:
-PzenohFlatJniVersion=1.9.0-rc4-SNAPSHOT -> 112 tests pass, no
composite build
default (1.9.0) -> unresolvable, and the
snapshot repository is
absent from the searched
locations
|
Re-reviewed the complete PR at The new conditional snapshot repository does fix direct snapshot consumption:
Additional checks: the generated JVM and Android POM tasks passed, all workflow YAML parses, and — Codex (GPT-5) |
Three defects the review found in the release script and workflows, all of which would have stopped a release or a rehearsal outright. The snapshot rejection was unconditional, so the rehearsal this PR documents - pass the snapshot as zenoh-flat-jni-version - was refused before Gradle ran. It now applies only to live runs, which is where the reasoning actually holds: a release may not depend on a snapshot, a rehearsal is how the SDK is exercised before the binding exists at all. git commit on an unchanged gradle.properties exits non-zero, so supplying the version already configured aborted the release under set -e before tagging. It commits only when the file moved. Neither publish workflow ran Gradle at all unless maven_publish was on, so an unchecked rehearsal proved nothing while the guide claimed it proved the artifact assembles. Both now assemble and generate the POM unconditionally; only the upload is gated. The guide also claimed one binding artifact carries both desktop and Android natives. It does not - they are separate coordinates, and the Android publication currently depends on the desktop one, so Android consumers get no jni/<abi>/ libraries. Recorded as a defect with the release blocked on it rather than described as working.
The README described the build that was removed: publishing 'triggers the compilation of Zenoh-JNI in release', the Android section required an NDK and four Rust targets, and a warning said the result was tied to the builder's rustup target. None of that is true now - the libraries arrive inside the zenoh-flat-jni artifacts, cross-compiled elsewhere, which is precisely why the result is *not* machine-specific. Also fixes coordinates that were wrong independently of this work: the Android dependency example named zenoh-kotlin-android in the zenoh-java README, and the JVM examples used zenoh-java-jvm, which is not what this repository publishes.
|
All six confirmed. Four fixed here; two are real defects I have recorded as release blockers rather than half-fixed, with reasons below. Fixed[P1] The snapshot rejection blocked the rehearsal this PR documents. Exactly right, and self-contradictory — I wrote both the guard and the instruction to pass a snapshot as [P1] A no-op version input aborted the release. Correct — [P2] [P2] The README described the removed build. All of it: "triggers the compilation of Zenoh-JNI in release", the NDK and four Rust targets, and the warning that the artifact is tied to the builder's rustup target — which is now the opposite of true. Also corrected coordinates that were wrong independently of this work: Recorded as blockers, not fixed[P1] The Android publication depends on the desktop binding. Confirmed, and worse than a documentation error — I checked the snapshot repository and I have not fixed it because it is not a one-line change: The claim that one artifact carries both desktop and Android natives is removed from the guide, replaced with the two-coordinate table and the defect note. [P2] JVM and Android are not released atomically. Also correct, and the same problem zenoh-flat-jni had — one coordinate can go public while the other job fails. The fix is the one that worked there: publish both from a single Gradle invocation into one staging repository, followed by one close/release. It is coupled to the item above, because it requires an Android-enabled build to produce both publications, so both are recorded together. Neither is a regression from this PR; both predate it and are now visible instead of implied. |
|
Re-reviewed the changes through The fixes for prior findings 1, 3, and 4 are correct. In isolated Git repositories with local-only remotes I verified that:
The new JVM The following issues remain.
Validation notes: the full PR passes — Codex (GPT-5) |
The Android POM named the desktop coordinate, so an Android consumer received an artifact with six desktop libraries and no jni/<abi>/ - it could not load anything. The build now selects zenoh-flat-jni-android when -Pandroid=true and zenoh-flat-jni otherwise, and the conditional snapshot repository serves both modules. Verified by generating both POMs, which turns out not to need an Android SDK even though building the AAR does: jvm/pom-default.xml -> zenoh-flat-jni androidRelease/pom-default.xml -> zenoh-flat-jni-android The selection is build-wide rather than per source set because commonMain references the generated classes, and Kotlin Multiplatform cannot see a dependency declared only in platform source sets. That is also the reason the two publications cannot come from one Gradle invocation, so the atomicity gap stays - now with its cause recorded and the upstream fix named: variant-aware module metadata in zenoh-flat-jni would collapse the two coordinates into one. Also fixes the javadoc JAR, which shipped empty: it packaged build/dokka/html, which Dokka never writes. Pointed at dokka/javadoc, with a check that fails the build rather than publishing 25 bytes again - now 780 KB across 172 files. README: Rust is no longer a prerequisite, the Android section no longer claims to build an NDK library, jvmTest no longer 'compiles the native library in debug mode', and the examples use 1.9.0, which resolves, instead of 1.1.1, which 404s.
|
Three fixed in [P1] The Android artifact now depends on the Android bindingYou were right that documenting it was not enough, and right that a live release launches the Android publication regardless. Fixed: val flatJniArtifact = if (androidEnabled) "zenoh-flat-jni-android" else "zenoh-flat-jni"
implementation("org.eclipse.zenoh:$flatJniArtifact:$zenohFlatJniVersion")I had assumed this needed an Android SDK to validate. It does not — POM generation configures without one, even though building the AAR does not: So both published POMs are now correct, and the conditional snapshot repository serves both modules. The README statement you flagged as aspirational is now simply true. [P2] The javadoc JAR was empty — fixedVerified exactly as you described: [P2] README — finishedRust removed from the prerequisites, the Android section no longer claims to build an NDK library or to contain the native binaries, and [P2] Atomicity — still open, and now with its causeNot fixed, but no longer just an entry in a list. Fixing the Android dependency entrenches it, and it is worth being explicit about why: the two publications need different binding coordinates, and the choice is a build-wide flag rather than a per-source-set dependency — because The real fix is upstream: if |
Part of #482. The release path on
zenoh-flat-transitionis dead, not merely dated — every job would fail on the first step — because it still operates on thezenoh-jnicrate that was removed when the SDK moved onto the generated bindings.What was broken
ci/scripts/bump-and-tag.bashzenoh-jni/Cargo.toml— gone, so thetagjob fails immediatelypublish-jvm.ymlzenoh-jni/Cargo.tomlacross six targets — gonepublish-android.ymlsettings.gradle.ktsincludeBuild("../zenoh-flat-jni")unconditionallyThat last one is the dangerous one. A release built with the composite active is
built against whatever sits on the builder's disk, while the POM claims the
resolved version.
What this changes
-PuseLocalFlatJni=true, off by default. CIpasses it explicitly because it checks the sibling out; a release does not, so
it resolves from Maven Central like any consumer.
gradle.properties(zenohFlatJniVersion),so the release can bump it and a rehearsal can point at a snapshot without
editing tracked source.
bump-and-tag.bashis rewritten for a repository with no Cargo manifest: itbumps
version.txtand that property, and refuses a-SNAPSHOTbindingversion outright.
zenoh-versionbecomeszenoh-flat-jni-version— the only upstream versionthis repository now chooses.
rust-android-gradleplugin that was declared but never applied.Why a release may not depend on a snapshot
Not a Sonatype validation rule — I checked Central's requirements page and it does
not say so. The binding reasons are simpler:
dependency fails to resolve for them;
So the ordering
zenoh-flat-jni→zenoh-javais a constraint, and the bumpscript enforces it rather than trusting the operator.
PUBLISHING.md
Mirrors zenoh-flat-jni's guide in structure, links to it for the concepts it
already explains once (coordinates, staging, signing), and covers what is
specific here — above all how to rehearse before zenoh-flat-jni is released,
which is the question the transition keeps raising:
-PuseLocalFlatJni=truezenoh-flat-jni:<v>-SNAPSHOTzenoh-flat-jni:<v>on CentralA snapshot may depend on a snapshot, so only the live release is blocked.
Verified
zenoh-flat-jni:1.9.0— correct,since it is not on Central; with
-PuseLocalFlatJni=trueit compiles.bump-and-tag.bashrun against a scratch repository: rejectsFLAT_JNI_VERSION=1.9.1-SNAPSHOT, and otherwise rewritesversion.txtandgradle.propertiesin two separate commits.resolves.
Not verified, and stated in
Known gaps: the repaired release path has neverrun, there is no consumer test for the published artifact, and the Android
ndkVersionand NDK setup step are retained without confirming AGP still needsthem.