From dd96d4b9f4ca52aa007ac280ab8852e8e10d2f40 Mon Sep 17 00:00:00 2001 From: Benjamin Mwalimu Date: Tue, 14 Apr 2026 14:32:52 +0300 Subject: [PATCH 1/4] Add automated maven central pubslishing --- .github/workflows/publish.yml | 104 ++++++++++++++++++++++++++++++++++ README.md | 36 ++++++++++++ pom.xml | 68 ++++++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..49744bd2 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,104 @@ +name: Release + +on: + push: + tags: + - 'v*' # e.g., v1.0.4, v1.0.4-SNAPSHOT + +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: true + +jobs: + release: + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: recursive + + - name: Remove any pre-existing Maven settings.xml + run: rm -f "$HOME/.m2/settings.xml" || true + + - name: Set up Temurin JDK 17 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: "17" + cache: maven + + - name: Import GPG key + uses: crazy-max/ghaction-import-gpg@v6 + with: + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.GPG_PASSPHRASE }} + git_user_signingkey: false + + - name: Configure Maven settings for Sonatype OSSRH + run: | + mkdir -p "$HOME/.m2" + cat > "$HOME/.m2/settings.xml" <<'XML' + + /home/runner/.m2/repository + false + + + central + __CENTRAL_USERNAME__ + __CENTRAL_PASSWORD__ + + + gpg.passphrase + __GPG_PASSPHRASE__ + + + + XML + sed -i "s#__CENTRAL_USERNAME__#${{ secrets.CENTRAL_USERNAME }}#g" "$HOME/.m2/settings.xml" + sed -i "s#__CENTRAL_PASSWORD__#${{ secrets.CENTRAL_PASSWORD }}#g" "$HOME/.m2/settings.xml" + sed -i "s#__GPG_PASSPHRASE__#${{ secrets.GPG_PASSPHRASE }}#g" "$HOME/.m2/settings.xml" + + - name: Extract version from tag + id: version + run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT" + + - name: Determine release type (snapshot vs production) + id: reltype + run: | + if [[ "${GITHUB_REF}" == *"-SNAPSHOT" ]]; then + echo "TYPE=snapshot" >> "$GITHUB_OUTPUT" + else + echo "TYPE=production" >> "$GITHUB_OUTPUT" + fi + + - name: Set project version from tag + run: | + mvn -B -ntp versions:set -DnewVersion="${{ steps.version.outputs.VERSION }}" + mvn -B -ntp versions:commit + + - name: Build & Test (signs at verify) + run: mvn -B -ntp clean verify + env: + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + + - name: Deploy to Sonatype OSSRH + run: mvn -B -ntp deploy -DskipTests + env: + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ github.ref_name }} + draft: false + prerelease: ${{ steps.reltype.outputs.TYPE == 'snapshot' || contains(github.ref, 'RC') || contains(github.ref, 'alpha') || contains(github.ref, 'beta') }} + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index 6d550ac5..e6800d8b 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,42 @@ public class Test { This is the hello world of Easy Rules. You can find other examples like the [Shop](https://github.com/opensrp/easy-rules/wiki/shop), [Airco](https://github.com/opensrp/easy-rules/wiki/air-conditioning) or [WebApp](https://github.com/opensrp/easy-rules/wiki/web-app) tutorials in the wiki. +## Publishing + +Artifacts are published to [Maven Central](https://central.sonatype.com/) automatically when a tag is pushed to the repository. + +### Tag conventions + +| Type | Pattern | Example | Behaviour | +|------|---------|---------|-----------| +| Release | `v..` | `v4.1.1` | Published to Maven Central; GitHub Release created | +| Snapshot | `v..-SNAPSHOT` | `v4.1.2-SNAPSHOT` | Published to the snapshots repository; GitHub Release marked as pre-release | + +```bash +# cut a release +git tag v4.1.1 && git push origin v4.1.1 + +# cut a snapshot +git tag v4.1.2-SNAPSHOT && git push origin v4.1.2-SNAPSHOT +``` + +The workflow (`publish.yml`) will: +1. Set the project version from the tag (strips the `v` prefix) +2. Run `mvn clean verify` — compiles, tests, and GPG-signs all artifacts +3. Run `mvn deploy` — uploads to Sonatype OSSRH (releases are promoted to Maven Central) +4. Create a GitHub Release automatically + +### Required repository secrets + +The following secrets must be configured in **Settings → Secrets and variables → Actions**: + +| Secret | Description | +|--------|-------------| +| `CENTRAL_USERNAME` | Sonatype Central portal username | +| `CENTRAL_PASSWORD` | Sonatype Central portal token | +| `GPG_PRIVATE_KEY` | Armored GPG private key (`gpg --armor --export-secret-keys `) | +| `GPG_PASSPHRASE` | Passphrase for the GPG key | + ## Contribution You are welcome to contribute to the project with pull requests on GitHub. diff --git a/pom.xml b/pom.xml index e4a62983..450c5f25 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,8 @@ 3.13.0 3.2.5 3.6.3 + 3.3.1 + 3.2.7 4.5 3.4.1 @@ -72,6 +74,12 @@ Lead developer + + Ona Systems + info@opensrp.io + Ona Systems + https://ona.io + @@ -212,4 +220,64 @@ + + + release + + + + org.apache.maven.plugins + maven-source-plugin + ${maven.source.plugin.version} + + + attach-sources + package + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin.version} + + + attach-javadocs + + jar + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + ${maven.gpg.plugin.version} + + + sign-artifacts + verify + + sign + + + + + + ${env.GPG_PASSPHRASE} + + --pinentry-mode + loopback + + + + + + + + From 10aea8fad7001057b471448a7e20e4c1858f9c8a Mon Sep 17 00:00:00 2001 From: Benjamin Mwalimu Date: Tue, 14 Apr 2026 14:38:58 +0300 Subject: [PATCH 2/4] Update README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e6800d8b..f9454c11 100644 --- a/README.md +++ b/README.md @@ -146,8 +146,8 @@ git tag v4.1.2-SNAPSHOT && git push origin v4.1.2-SNAPSHOT The workflow (`publish.yml`) will: 1. Set the project version from the tag (strips the `v` prefix) -2. Run `mvn clean verify` — compiles, tests, and GPG-signs all artifacts -3. Run `mvn deploy` — uploads to Sonatype OSSRH (releases are promoted to Maven Central) +2. Run `mvn clean verify` — compiles and tests the project +3. Run `mvn deploy` — uploads artifacts to Sonatype OSSRH (with release promotion/asset signing handled by the workflow's Maven configuration) 4. Create a GitHub Release automatically ### Required repository secrets From 524aa335edbed0bf20d9b144efc6bf0e5f106e48 Mon Sep 17 00:00:00 2001 From: Benjamin Mwalimu Date: Tue, 14 Apr 2026 14:46:45 +0300 Subject: [PATCH 3/4] Set the pass phrase correctly --- .github/workflows/publish.yml | 18 ++++++++---------- pom.xml | 3 +-- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 49744bd2..96c8b594 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -54,16 +54,11 @@ jobs: __CENTRAL_USERNAME__ __CENTRAL_PASSWORD__ - - gpg.passphrase - __GPG_PASSPHRASE__ - XML sed -i "s#__CENTRAL_USERNAME__#${{ secrets.CENTRAL_USERNAME }}#g" "$HOME/.m2/settings.xml" - sed -i "s#__CENTRAL_PASSWORD__#${{ secrets.CENTRAL_PASSWORD }}#g" "$HOME/.m2/settings.xml" - sed -i "s#__GPG_PASSPHRASE__#${{ secrets.GPG_PASSPHRASE }}#g" "$HOME/.m2/settings.xml" + sed -i "s#__CENTRAL_PASSWORD__#${{ secrets.CENTRAL_PASSWORD }}#g" "$HOME/.m2/settings.xml" - name: Extract version from tag id: version @@ -74,22 +69,25 @@ jobs: run: | if [[ "${GITHUB_REF}" == *"-SNAPSHOT" ]]; then echo "TYPE=snapshot" >> "$GITHUB_OUTPUT" - else + elif [[ "${GITHUB_REF}" =~ ^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "TYPE=production" >> "$GITHUB_OUTPUT" + else + echo "ERROR: unexpected tag format '${GITHUB_REF}'. Expected vX.Y.Z or vX.Y.Z-SNAPSHOT." >&2 + exit 1 fi - name: Set project version from tag run: | - mvn -B -ntp versions:set -DnewVersion="${{ steps.version.outputs.VERSION }}" + mvn -B -ntp versions:set -DnewVersion="${{ steps.version.outputs.VERSION }}" -DprocessAllModules=true mvn -B -ntp versions:commit - name: Build & Test (signs at verify) - run: mvn -B -ntp clean verify + run: mvn -B -ntp clean verify -P release env: MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} - name: Deploy to Sonatype OSSRH - run: mvn -B -ntp deploy -DskipTests + run: mvn -B -ntp deploy -DskipTests -P release env: MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} diff --git a/pom.xml b/pom.xml index 450c5f25..9b1d8475 100644 --- a/pom.xml +++ b/pom.xml @@ -267,8 +267,7 @@ - - ${env.GPG_PASSPHRASE} + --pinentry-mode loopback From aec1634cbbb7103191c2940e0c418070d90121ca Mon Sep 17 00:00:00 2001 From: Benjamin Mwalimu Date: Tue, 14 Apr 2026 14:53:26 +0300 Subject: [PATCH 4/4] Updating how the secrets are provided --- .github/workflows/publish.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 96c8b594..1252ae4a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -51,14 +51,12 @@ jobs: central - __CENTRAL_USERNAME__ - __CENTRAL_PASSWORD__ + ${env.CENTRAL_USERNAME} + ${env.CENTRAL_PASSWORD} XML - sed -i "s#__CENTRAL_USERNAME__#${{ secrets.CENTRAL_USERNAME }}#g" "$HOME/.m2/settings.xml" - sed -i "s#__CENTRAL_PASSWORD__#${{ secrets.CENTRAL_PASSWORD }}#g" "$HOME/.m2/settings.xml" - name: Extract version from tag id: version @@ -89,6 +87,8 @@ jobs: - name: Deploy to Sonatype OSSRH run: mvn -B -ntp deploy -DskipTests -P release env: + CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }} + CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }} MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} - name: Create GitHub Release @@ -96,7 +96,7 @@ jobs: with: tag_name: ${{ github.ref_name }} draft: false - prerelease: ${{ steps.reltype.outputs.TYPE == 'snapshot' || contains(github.ref, 'RC') || contains(github.ref, 'alpha') || contains(github.ref, 'beta') }} + prerelease: ${{ steps.reltype.outputs.TYPE == 'snapshot' }} generate_release_notes: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}