diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..1252ae4a --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,102 @@ +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 + ${env.CENTRAL_USERNAME} + ${env.CENTRAL_PASSWORD} + + + + 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" + 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 }}" -DprocessAllModules=true + mvn -B -ntp versions:commit + + - name: Build & Test (signs at 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 -P release + env: + CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }} + CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }} + 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' }} + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index 6d550ac5..f9454c11 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 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 + +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..9b1d8475 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,63 @@ + + + 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 + + + + + + + --pinentry-mode + loopback + + + + + + + +