diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..5a032e0 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,110 @@ +# Publishing to Maven Central. +# +# A tag is the trigger, and the tag is the version: v0.11.0 publishes +# 0.11.0. The pom on main stays a snapshot, because a repository whose +# version has to be bumped in a commit before every release is a +# repository where the version in a checkout is a lie between the bump +# and the tag. +# +# The engine and this client move on one version number, so the same tag +# names the engine release the libraries are downloaded from. If that +# release does not exist yet, this job fails at the staging step rather +# than publishing a client with no engine in it. +# +# Nothing is published without a human: autoPublish is off, so this puts +# a deployment in the portal and stops. Dropping it there is how a +# mistake is undone, and there is no undoing a version that went out. +name: Release + +on: + push: + tags: ["v*"] + workflow_dispatch: + inputs: + tag: + description: The engine release to take libraries from, for example v0.11.0 + required: true + publish: + description: Upload to Central, rather than only building what would be uploaded + type: boolean + default: false + +env: + MAVEN_ARGS: -B -ntp + +jobs: + release: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v5 + + - uses: actions/setup-java@v5 + with: + distribution: temurin + java-version: "25" + cache: maven + # Writes a settings.xml whose `central` server credentials come + # from these two, which is the id the publishing plugin is + # configured with. + server-id: central + server-username: CENTRAL_USERNAME + server-password: CENTRAL_PASSWORD + gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} + gpg-passphrase: GPG_PASSPHRASE + + - name: Which version this is + run: | + set -eu + tag="${{ inputs.tag || github.ref_name }}" + case "$tag" in + v*) ;; + *) echo "$tag is not a version tag"; exit 1 ;; + esac + echo "TAG=$tag" >> "$GITHUB_ENV" + echo "VERSION=${tag#v}" >> "$GITHUB_ENV" + + # The version lives in the tag rather than in the pom, so it is set + # here and never committed. + - name: Set the version + run: mvn $MAVEN_ARGS versions:set -DnewVersion="$VERSION" -DgenerateBackupPoms=false + + - name: Stage the libraries + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: ./scripts/stage-natives.sh "$TAG" + + # The suite needs an engine, and one of the seven that was just + # staged is the platform this runner is, so it runs against the + # library that is about to be published rather than against a build + # of main. A release that cannot answer a query does not go out. + - name: The library that is about to be published answers + run: | + set -eu + echo "ZU_LIBRARY=$PWD/zudb-native/lib/linux-amd64/libzu.so" >> "$GITHUB_ENV" + + - run: mvn $MAVEN_ARGS -Pnatives test + + - name: Build, sign and upload + if: github.event_name == 'push' || inputs.publish + env: + CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }} + CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + run: mvn $MAVEN_ARGS -Prelease,natives -DskipTests deploy + + # What a dispatch with publish off is for: everything up to the + # upload, so that a change to the packaging can be checked without + # a version being spent on it. + - name: Build what would have been uploaded + if: github.event_name != 'push' && !inputs.publish + run: mvn $MAVEN_ARGS -Prelease,natives -DskipTests -Dgpg.skip=true package + + - uses: actions/upload-artifact@v4 + with: + name: artifacts + path: | + */target/*.jar + */target/*.pom + if-no-files-found: error diff --git a/README.md b/README.md index 24d8478..4b39b1b 100644 --- a/README.md +++ b/README.md @@ -277,6 +277,8 @@ ZU_LIBRARY=/path/to/libzu.dylib java -jar zudb-bench/target/benchmarks.jar `ZU_LIBRARY` rather than `-Dzu.library` there, because JMH forks a JVM of its own and a fork inherits the environment rather than the system properties. +A release is a tag. `v0.11.0` builds `0.11.0`, takes its libraries from the engine release of the same name, runs the suite against the very library it is about to publish, and puts one signed deployment of the whole reactor in the Central portal. The version is never committed: a pom that has to be bumped before a release is a pom that is wrong between the bump and the tag. Nothing is published without a human pressing the button, and dropping a deployment in the portal is the only way a mistake is undone, because a version that went out cannot be taken back. + ## Beyond Java - **Kotlin** (`dev.zudb:zudb-kotlin`, tier 2), a thin extension layer, not a second binding. `use`, `Sequence`, `Flow` with cancellation wired to `interrupt()`, and an inline `transaction { }`. diff --git a/pom.xml b/pom.xml index 0e4b882..fec4ff0 100644 --- a/pom.xml +++ b/pom.xml @@ -171,8 +171,47 @@ and a local build has no use for. --> release + + + --pinentry-mode=loopback + + + org.apache.maven.plugins + maven-gpg-plugin + ${maven.gpg.plugin.version} + + + sign-artifacts + verify + sign + + + + + + org.sonatype.central + central-publishing-maven-plugin + ${central.publishing.plugin.version} + true + + central + false + validated + + zudb-bench + + + org.apache.maven.plugins maven-source-plugin diff --git a/zudb-native/pom.xml b/zudb-native/pom.xml index ede9232..28c272e 100644 --- a/zudb-native/pom.xml +++ b/zudb-native/pom.xml @@ -160,4 +160,43 @@ + + + + + release + + + + org.apache.maven.plugins + maven-jar-plugin + + + sources + jar + + sources + ${project.basedir}/src/empty + + + + javadoc + jar + + javadoc + ${project.basedir}/src/empty + + + + + + + + diff --git a/zudb-native/src/empty/README.md b/zudb-native/src/empty/README.md new file mode 100644 index 0000000..74a1eaf --- /dev/null +++ b/zudb-native/src/empty/README.md @@ -0,0 +1,7 @@ +# There is no source here, and no documentation either + +`zudb-native` is a jar of shared libraries. Nothing in it is compiled from Java and nothing in it has an API, so a sources jar and a javadoc jar have nothing to hold. + +Maven Central requires both of them beside every published jar, and there is no way to say that one of them is meaningless for an artifact. So both are published and both contain this file, which is at least an answer to whoever opens one looking for something. + +The source for the libraries is the engine, at https://github.com/tamnd/zu. The API this artifact serves is `dev.zudb`, whose javadoc is published beside the `zudb` artifact.