From 68e2016ae14f24498a2f62630b011fe5cc9c6b83 Mon Sep 17 00:00:00 2001 From: Felix Griesau <165886603+Felix-Griesau-SAP@users.noreply.github.com> Date: Mon, 14 Sep 2026 17:36:06 +0200 Subject: [PATCH 1/2] Github Action to Build and Publish Releases --- .github/workflows/RELEASE.md | 19 ++++++++++++++ .github/workflows/release.yml | 47 +++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 .github/workflows/RELEASE.md create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/RELEASE.md b/.github/workflows/RELEASE.md new file mode 100644 index 00000000..89b270ee --- /dev/null +++ b/.github/workflows/RELEASE.md @@ -0,0 +1,19 @@ +# Release workflow + +`release.yml` publishes to Maven Central (Sonatype Central Portal) via the `central` Maven profile. It runs on a published GitHub Release or a manual `workflow_dispatch`; it doesn't create releases. + +## Flow +1. Cut a GitHub Release (or dispatch the workflow, which won't create a github release). +2. A maintainer approves the `maven-central` environment prompt. +3. The job builds, signs, and uploads to the Portal, where it's staged. +4. A maintainer has to Publish the version in the Portal to release to Central. This could be automated if deemed useful (https://central.sonatype.org/publish/publish-portal-maven/#autopublish). + +## Secrets +Kept on the `maven-central` GitHub Environment, not repo or org secrets. This is essential for security, if you ever need to set this up yourself (https://docs.github.com/en/actions/how-tos/deploy/configure-and-manage-deployments/manage-environments): + +- `MAVEN_CENTRAL_USERNAME` / `MAVEN_CENTRAL_PASSWORD` +- `MAVEN_GPG_PRIVATE_KEY` + +They only inject after the environment rules pass: review, and allowed refs limited to `main`. Other runs are not able to retrieve the credentials. + +The signing key has no passphrase on purpose: gpg then signs non-interactively on the runner. A passphrase would make gpg open a pinentry prompt, which a headless CI can't answer, and the build fails. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..2fd4f5d4 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,47 @@ +name: Release to Maven Central + +# Publishes to Maven Central (Sonatype Central Portal) via the `central` profile +# in pom.xml. Uses signing/publishing secrets; see RELEASE.md before +# changing triggers, permissions or the environment. + +on: + release: + types: [published] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: release-maven-central + cancel-in-progress: false + +jobs: + publish: + runs-on: ubuntu-latest + timeout-minutes: 30 + environment: maven-central # secrets live here, gated by required reviewers + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + persist-credentials: false + + - name: Set up JDK, Maven settings, GPG + uses: actions/setup-java@cf277c60eb25467037889841efdb72551f06f6c3 # v4.9.1 + with: + distribution: temurin + java-version: '17' + server-id: central + # username/password are env-var NAMES: setup-java writes them into + # settings.xml and Maven resolves them from env at runtime (never on disk). + # gpg-private-key is the actual key value: setup-java imports it here. + # The key has no passphrase, so gpg signs non-interactively (no pinentry). + server-username: MAVEN_CENTRAL_USERNAME + server-password: MAVEN_CENTRAL_PASSWORD + gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} + + - name: Deploy (uploads and stages; Publish is a manual click in the Portal) + run: mvn -B -ntp -P central deploy + env: + MAVEN_CENTRAL_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }} + MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} From 32b2ef1d7ce5263509de2b3f236caf9e50fec8f9 Mon Sep 17 00:00:00 2001 From: Felix Griesau <165886603+Felix-Griesau-SAP@users.noreply.github.com> Date: Tue, 15 Sep 2026 10:12:52 +0200 Subject: [PATCH 2/2] Adapt to review Feedback - Doc wording - GPG passphrase support --- .github/workflows/RELEASE.md | 5 ++--- .github/workflows/release.yml | 7 ++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/RELEASE.md b/.github/workflows/RELEASE.md index 89b270ee..02927346 100644 --- a/.github/workflows/RELEASE.md +++ b/.github/workflows/RELEASE.md @@ -6,14 +6,13 @@ 1. Cut a GitHub Release (or dispatch the workflow, which won't create a github release). 2. A maintainer approves the `maven-central` environment prompt. 3. The job builds, signs, and uploads to the Portal, where it's staged. -4. A maintainer has to Publish the version in the Portal to release to Central. This could be automated if deemed useful (https://central.sonatype.org/publish/publish-portal-maven/#autopublish). +4. Someone with publish access in the Sonatype Portal (org membership on the `com.sap.hcp.cf.logging` namespace) publishes in the Portal to release to Central. This could be automated if deemed useful (https://central.sonatype.org/publish/publish-portal-maven/#autopublish). ## Secrets Kept on the `maven-central` GitHub Environment, not repo or org secrets. This is essential for security, if you ever need to set this up yourself (https://docs.github.com/en/actions/how-tos/deploy/configure-and-manage-deployments/manage-environments): - `MAVEN_CENTRAL_USERNAME` / `MAVEN_CENTRAL_PASSWORD` - `MAVEN_GPG_PRIVATE_KEY` +- `MAVEN_GPG_PASSPHRASE` They only inject after the environment rules pass: review, and allowed refs limited to `main`. Other runs are not able to retrieve the credentials. - -The signing key has no passphrase on purpose: gpg then signs non-interactively on the runner. A passphrase would make gpg open a pinentry prompt, which a headless CI can't answer, and the build fails. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2fd4f5d4..afeb172c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,16 +32,17 @@ jobs: distribution: temurin java-version: '17' server-id: central - # username/password are env-var NAMES: setup-java writes them into - # settings.xml and Maven resolves them from env at runtime (never on disk). + # username/password/passphrase are env-var NAMES: setup-java writes them + # into settings.xml and Maven resolves them from env at runtime (never on disk). # gpg-private-key is the actual key value: setup-java imports it here. - # The key has no passphrase, so gpg signs non-interactively (no pinentry). server-username: MAVEN_CENTRAL_USERNAME server-password: MAVEN_CENTRAL_PASSWORD gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} + gpg-passphrase: MAVEN_GPG_PASSPHRASE - name: Deploy (uploads and stages; Publish is a manual click in the Portal) run: mvn -B -ntp -P central deploy env: MAVEN_CENTRAL_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }} MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}