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;