diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..464f1c8 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,53 @@ +name: Release + +# Publishes to Maven Central when a GitHub Release is published, via the +# Central Publisher Portal (https://central.sonatype.com). +# +# Required repository secrets (see RELEASING.md for setup): +# CENTRAL_USERNAME - Central portal user token name +# CENTRAL_PASSWORD - Central portal user token value +# GPG_PRIVATE_KEY - ASCII-armored GPG private key used to sign artifacts +# GPG_PASSPHRASE - passphrase for that key +# +# To cut a release: bump the version in pom.xml (drop -SNAPSHOT), merge to +# main, then publish a GitHub Release with tag vX.Y.Z — this workflow signs +# and uploads the artifacts. + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + publish: + name: Publish to Maven Central + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: "17" + cache: maven + server-id: central + server-username: CENTRAL_USERNAME + server-password: CENTRAL_PASSWORD + gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} + gpg-passphrase: GPG_PASSPHRASE + - name: Verify tag matches pom version + run: | + POM_VERSION=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.version) + TAG="${GITHUB_REF_NAME#v}" + if [ "$POM_VERSION" != "$TAG" ]; then + echo "pom.xml version ($POM_VERSION) does not match release tag ($GITHUB_REF_NAME)" + exit 1 + fi + - name: Publish + run: mvn -B --no-transfer-progress -Prelease deploy + env: + CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }} + CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} diff --git a/README.md b/README.md index a2f0e64..ac7d876 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Maven: ```xml - com.iopsystems + systems.iop h2histogram 0.1.0 @@ -42,7 +42,7 @@ Maven: Gradle: ```kotlin -implementation("com.iopsystems:h2histogram:0.1.0") +implementation("systems.iop:h2histogram:0.1.0") ``` The library requires Java 17 or later and has no runtime dependencies. @@ -50,9 +50,9 @@ The library requires Java 17 or later and has no runtime dependencies. ## Quick start ```java -import com.iopsystems.h2histogram.Bucket; -import com.iopsystems.h2histogram.Histogram; -import com.iopsystems.h2histogram.SparseHistogram; +import systems.iop.h2histogram.Bucket; +import systems.iop.h2histogram.Histogram; +import systems.iop.h2histogram.SparseHistogram; Histogram h = new Histogram(7, 64); // groupingPower, maxValuePower @@ -79,8 +79,8 @@ For a snapshot you'll query many times, convert to a `CumulativeHistogram` precomputes a midpoint-estimated mean: ```java -import com.iopsystems.h2histogram.BucketWithQuantiles; -import com.iopsystems.h2histogram.CumulativeHistogram; +import systems.iop.h2histogram.BucketWithQuantiles; +import systems.iop.h2histogram.CumulativeHistogram; CumulativeHistogram c = h.toCumulative(); // read-only; also SparseHistogram.toCumulative() Bucket b = c.percentile(0.99).orElseThrow(); // O(log n) binary search (individual count) @@ -139,21 +139,8 @@ mvn verify ## Releasing -Releases are published to Maven Central. To cut a release: - -1. **Land your changes on `main`** via a pull request. -2. **Set the release version** (drop the `-SNAPSHOT` suffix) in - [`pom.xml`](pom.xml), e.g. `0.1.0`, and merge that change. -3. **Tag and push** a `vX.Y.Z` tag on `main`: - - ```bash - git checkout main && git pull - git tag v0.1.0 - git push origin v0.1.0 - ``` - -4. **Deploy** with `mvn -Prelease deploy` using Sonatype (Maven Central) - credentials, then bump `pom.xml` back to the next `-SNAPSHOT` version. +Releases are published to Maven Central automatically via GitHub Actions when +a GitHub Release is published. See [RELEASING.md](RELEASING.md) for the steps. ## License diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..f01ce13 --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,80 @@ +# Releasing + +`h2histogram` is published to Maven Central automatically by the +[`release.yml`](.github/workflows/release.yml) GitHub Actions workflow via the +[Central Publisher Portal](https://central.sonatype.com), whenever a GitHub +Release is published. + +## Cutting a release + +1. **Bump the version.** Edit `` in [`pom.xml`](pom.xml), dropping the + `-SNAPSHOT` suffix (e.g. `0.1.0-SNAPSHOT` → `0.1.0`), following + [semantic versioning](https://semver.org/). Commit and merge to `main` via a + pull request titled `release: vX.Y.Z`. +2. **Publish a GitHub Release.** Go to + [Releases → Draft a new release](https://github.com/iopsystems/h2histogram-java/releases/new): + - **Choose a tag:** type `vX.Y.Z` (matching the `pom.xml` version) and select + *"Create new tag on publish"*, targeting `main`. + - **Title:** `vX.Y.Z`. + - Click **Generate release notes**, then **Publish release**. +3. **Watch the workflow.** Publishing the release triggers `release.yml`, which + verifies the tag matches the pom version, builds the jar plus sources and + javadoc jars, signs everything with GPG, and uploads to Maven Central with + `autoPublish` — no manual portal step. Follow it under the + [Actions tab](https://github.com/iopsystems/h2histogram-java/actions/workflows/release.yml). + Central validation takes a few minutes; sync to search/mirrors can take + longer. +4. **Bump back to a snapshot.** Open a follow-up PR setting `` to the + next development version (e.g. `0.1.1-SNAPSHOT`). + +> **Versions are immutable on Maven Central.** A published version can never be +> replaced or deleted. If you push a bad release, bump the version and cut a +> new one. + +## One-time setup + +### 1. Namespace verification + +The `systems.iop` namespace (the reverse-DNS form of the `iop.systems` +domain) must be verified once in the +[Central portal](https://central.sonatype.com) (log in → **Namespaces** → add +`systems.iop`). Verification is via a DNS TXT record on `iop.systems`; the +portal shows the exact record to create. + +### 2. Portal user token + +In the portal: click your account → **View Account** → **Generate User Token**. +This produces a token *name* and *value* (these are not your portal login +credentials). Store them as repository secrets under +**Settings → Secrets and variables → Actions**: + +| Secret | Value | +|--------|-------| +| `CENTRAL_USERNAME` | the token name | +| `CENTRAL_PASSWORD` | the token value | + +### 3. GPG signing key + +Maven Central requires artifacts to be GPG-signed. + +```bash +gpg --gen-key # if you don't already have a key; RSA, no expiry is fine +gpg --keyserver keyserver.ubuntu.com --send-keys # publish the public key +gpg --armor --export-secret-keys # private key, for the secret below +``` + +Store as repository secrets: + +| Secret | Value | +|--------|-------| +| `GPG_PRIVATE_KEY` | the full ASCII-armored private key block | +| `GPG_PASSPHRASE` | the key's passphrase | + +## Publishing manually (without CI) + +With a verified namespace, a portal token in `~/.m2/settings.xml` (server id +`central`), and a local GPG key: + +```bash +mvn -Prelease deploy +``` diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml index 2455856..229bb29 100644 --- a/benchmarks/pom.xml +++ b/benchmarks/pom.xml @@ -4,9 +4,9 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.iopsystems + systems.iop h2histogram-benchmarks - 0.1.0-SNAPSHOT + 0.1.0 jar h2histogram-benchmarks @@ -20,9 +20,9 @@ - com.iopsystems + systems.iop h2histogram - 0.1.0-SNAPSHOT + 0.1.0 org.hdrhistogram diff --git a/benchmarks/src/main/java/com/iopsystems/h2histogram/bench/RecordBenchmark.java b/benchmarks/src/main/java/systems/iop/h2histogram/bench/RecordBenchmark.java similarity index 96% rename from benchmarks/src/main/java/com/iopsystems/h2histogram/bench/RecordBenchmark.java rename to benchmarks/src/main/java/systems/iop/h2histogram/bench/RecordBenchmark.java index 55570f5..be560f8 100644 --- a/benchmarks/src/main/java/com/iopsystems/h2histogram/bench/RecordBenchmark.java +++ b/benchmarks/src/main/java/systems/iop/h2histogram/bench/RecordBenchmark.java @@ -1,7 +1,7 @@ -package com.iopsystems.h2histogram.bench; +package systems.iop.h2histogram.bench; -import com.iopsystems.h2histogram.Config; -import com.iopsystems.h2histogram.Histogram; +import systems.iop.h2histogram.Config; +import systems.iop.h2histogram.Histogram; import java.util.Random; import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.Benchmark; diff --git a/pom.xml b/pom.xml index fb1dcf4..fbc70bf 100644 --- a/pom.xml +++ b/pom.xml @@ -4,9 +4,9 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.iopsystems + systems.iop h2histogram - 0.1.0-SNAPSHOT + 0.1.0 jar h2histogram @@ -23,6 +23,14 @@ + + + IOP Systems + IOP Systems + https://iop.systems + + + scm:git:https://github.com/iopsystems/h2histogram-java.git scm:git:git@github.com:iopsystems/h2histogram-java.git @@ -84,4 +92,46 @@ + + + + + release + + + + org.apache.maven.plugins + maven-gpg-plugin + 3.2.4 + + + sign-artifacts + verify + + sign + + + + --pinentry-mode + loopback + + + + + + + org.sonatype.central + central-publishing-maven-plugin + 0.7.0 + true + + central + true + published + + + + + + diff --git a/src/main/java/com/iopsystems/h2histogram/Bucket.java b/src/main/java/systems/iop/h2histogram/Bucket.java similarity index 97% rename from src/main/java/com/iopsystems/h2histogram/Bucket.java rename to src/main/java/systems/iop/h2histogram/Bucket.java index d99217f..99e7259 100644 --- a/src/main/java/com/iopsystems/h2histogram/Bucket.java +++ b/src/main/java/systems/iop/h2histogram/Bucket.java @@ -1,4 +1,4 @@ -package com.iopsystems.h2histogram; +package systems.iop.h2histogram; /** * A single histogram bucket: a count and an inclusive value range. diff --git a/src/main/java/com/iopsystems/h2histogram/BucketWithQuantiles.java b/src/main/java/systems/iop/h2histogram/BucketWithQuantiles.java similarity index 94% rename from src/main/java/com/iopsystems/h2histogram/BucketWithQuantiles.java rename to src/main/java/systems/iop/h2histogram/BucketWithQuantiles.java index 18b4acb..32ea46f 100644 --- a/src/main/java/com/iopsystems/h2histogram/BucketWithQuantiles.java +++ b/src/main/java/systems/iop/h2histogram/BucketWithQuantiles.java @@ -1,4 +1,4 @@ -package com.iopsystems.h2histogram; +package systems.iop.h2histogram; /** * Bundles a bucket with its quantile span. diff --git a/src/main/java/com/iopsystems/h2histogram/Config.java b/src/main/java/systems/iop/h2histogram/Config.java similarity index 99% rename from src/main/java/com/iopsystems/h2histogram/Config.java rename to src/main/java/systems/iop/h2histogram/Config.java index ef19272..ff8aeca 100644 --- a/src/main/java/com/iopsystems/h2histogram/Config.java +++ b/src/main/java/systems/iop/h2histogram/Config.java @@ -1,4 +1,4 @@ -package com.iopsystems.h2histogram; +package systems.iop.h2histogram; /** * An immutable bucketing configuration. diff --git a/src/main/java/com/iopsystems/h2histogram/CumulativeHistogram.java b/src/main/java/systems/iop/h2histogram/CumulativeHistogram.java similarity index 99% rename from src/main/java/com/iopsystems/h2histogram/CumulativeHistogram.java rename to src/main/java/systems/iop/h2histogram/CumulativeHistogram.java index 9835b38..5d74cb8 100644 --- a/src/main/java/com/iopsystems/h2histogram/CumulativeHistogram.java +++ b/src/main/java/systems/iop/h2histogram/CumulativeHistogram.java @@ -1,4 +1,4 @@ -package com.iopsystems.h2histogram; +package systems.iop.h2histogram; import java.util.ArrayList; import java.util.Arrays; diff --git a/src/main/java/com/iopsystems/h2histogram/Histogram.java b/src/main/java/systems/iop/h2histogram/Histogram.java similarity index 99% rename from src/main/java/com/iopsystems/h2histogram/Histogram.java rename to src/main/java/systems/iop/h2histogram/Histogram.java index 8046bdd..66895b8 100644 --- a/src/main/java/com/iopsystems/h2histogram/Histogram.java +++ b/src/main/java/systems/iop/h2histogram/Histogram.java @@ -1,4 +1,4 @@ -package com.iopsystems.h2histogram; +package systems.iop.h2histogram; import java.util.ArrayList; import java.util.Arrays; diff --git a/src/main/java/com/iopsystems/h2histogram/PercentileResult.java b/src/main/java/systems/iop/h2histogram/PercentileResult.java similarity index 88% rename from src/main/java/com/iopsystems/h2histogram/PercentileResult.java rename to src/main/java/systems/iop/h2histogram/PercentileResult.java index 2d3693a..1ca0cd5 100644 --- a/src/main/java/com/iopsystems/h2histogram/PercentileResult.java +++ b/src/main/java/systems/iop/h2histogram/PercentileResult.java @@ -1,4 +1,4 @@ -package com.iopsystems.h2histogram; +package systems.iop.h2histogram; /** * Pairs a requested percentile with the {@link Bucket} it resolves to. diff --git a/src/main/java/com/iopsystems/h2histogram/SparseHistogram.java b/src/main/java/systems/iop/h2histogram/SparseHistogram.java similarity index 99% rename from src/main/java/com/iopsystems/h2histogram/SparseHistogram.java rename to src/main/java/systems/iop/h2histogram/SparseHistogram.java index 787bbbd..e8f4652 100644 --- a/src/main/java/com/iopsystems/h2histogram/SparseHistogram.java +++ b/src/main/java/systems/iop/h2histogram/SparseHistogram.java @@ -1,4 +1,4 @@ -package com.iopsystems.h2histogram; +package systems.iop.h2histogram; import java.util.ArrayList; import java.util.Arrays; diff --git a/src/main/java/com/iopsystems/h2histogram/U64.java b/src/main/java/systems/iop/h2histogram/U64.java similarity index 97% rename from src/main/java/com/iopsystems/h2histogram/U64.java rename to src/main/java/systems/iop/h2histogram/U64.java index 90b1f3a..75b3de5 100644 --- a/src/main/java/com/iopsystems/h2histogram/U64.java +++ b/src/main/java/systems/iop/h2histogram/U64.java @@ -1,4 +1,4 @@ -package com.iopsystems.h2histogram; +package systems.iop.h2histogram; /** * Helpers for treating Java {@code long} values as unsigned 64-bit integers diff --git a/src/main/java/com/iopsystems/h2histogram/package-info.java b/src/main/java/systems/iop/h2histogram/package-info.java similarity index 97% rename from src/main/java/com/iopsystems/h2histogram/package-info.java rename to src/main/java/systems/iop/h2histogram/package-info.java index 0d9dc2e..b79d72e 100644 --- a/src/main/java/com/iopsystems/h2histogram/package-info.java +++ b/src/main/java/systems/iop/h2histogram/package-info.java @@ -26,4 +26,4 @@ * Java {@code long}s with unsigned semantics, so the full {@code u64} range is * supported, exactly like the Rust crate. */ -package com.iopsystems.h2histogram; +package systems.iop.h2histogram; diff --git a/src/test/java/com/iopsystems/h2histogram/ConfigTest.java b/src/test/java/systems/iop/h2histogram/ConfigTest.java similarity index 99% rename from src/test/java/com/iopsystems/h2histogram/ConfigTest.java rename to src/test/java/systems/iop/h2histogram/ConfigTest.java index 271b603..a28ddaf 100644 --- a/src/test/java/com/iopsystems/h2histogram/ConfigTest.java +++ b/src/test/java/systems/iop/h2histogram/ConfigTest.java @@ -1,4 +1,4 @@ -package com.iopsystems.h2histogram; +package systems.iop.h2histogram; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/iopsystems/h2histogram/CumulativeHistogramTest.java b/src/test/java/systems/iop/h2histogram/CumulativeHistogramTest.java similarity index 99% rename from src/test/java/com/iopsystems/h2histogram/CumulativeHistogramTest.java rename to src/test/java/systems/iop/h2histogram/CumulativeHistogramTest.java index 3f1eff9..3b04e86 100644 --- a/src/test/java/com/iopsystems/h2histogram/CumulativeHistogramTest.java +++ b/src/test/java/systems/iop/h2histogram/CumulativeHistogramTest.java @@ -1,4 +1,4 @@ -package com.iopsystems.h2histogram; +package systems.iop.h2histogram; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/com/iopsystems/h2histogram/ExampleTest.java b/src/test/java/systems/iop/h2histogram/ExampleTest.java similarity index 97% rename from src/test/java/com/iopsystems/h2histogram/ExampleTest.java rename to src/test/java/systems/iop/h2histogram/ExampleTest.java index e44f185..c489ced 100644 --- a/src/test/java/com/iopsystems/h2histogram/ExampleTest.java +++ b/src/test/java/systems/iop/h2histogram/ExampleTest.java @@ -1,4 +1,4 @@ -package com.iopsystems.h2histogram; +package systems.iop.h2histogram; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/src/test/java/com/iopsystems/h2histogram/HistogramTest.java b/src/test/java/systems/iop/h2histogram/HistogramTest.java similarity index 99% rename from src/test/java/com/iopsystems/h2histogram/HistogramTest.java rename to src/test/java/systems/iop/h2histogram/HistogramTest.java index 618fce2..35228d0 100644 --- a/src/test/java/com/iopsystems/h2histogram/HistogramTest.java +++ b/src/test/java/systems/iop/h2histogram/HistogramTest.java @@ -1,4 +1,4 @@ -package com.iopsystems.h2histogram; +package systems.iop.h2histogram; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows;