From 7820e312c71603132108c36f5d7a6f852f8cbbf7 Mon Sep 17 00:00:00 2001 From: Jeff Jensen Date: Mon, 22 Jun 2026 17:25:50 -0500 Subject: [PATCH 1/2] ci(release): Add tag-triggered Maven Central release workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit and standardize release.yml so a pushed v* tag (created by release:prepare) deploys -Prelease to Maven Central. Adds the release-deploy concurrency group and the release environment approval gate, and bumps checkout to v7 — matching the snapshot-deploy workflow and the jdk-setup composite usage. Document the actual flow: release:prepare auto-pushes the tag (pushChanges defaults to true), release.yml waits on the release environment approval gate, then deploys. Add the one-time prerequisites (secrets, release environment, local Docker) and drop the obsolete manual push step. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_013DKrZ3wSe6H5HXPzg8iWC6 --- .github/workflows/release.yml | 42 ++++++++++ integration/src/site/asciidoc/releasing.adoc | 80 +++++++------------- 2 files changed, 68 insertions(+), 54 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..c538883 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,42 @@ +name: Release to Maven Central + +on: + push: + tags: ['v*'] # created by maven-release-plugin (tagNameFormat v@{project.version}) + +permissions: + contents: read + +concurrency: + group: release-deploy + cancel-in-progress: false + +env: + MAVEN_COMMAND: ./mvnw + MAVEN_CLI_COMMON: "-e -B" + +jobs: + release: + runs-on: ubuntu-latest + timeout-minutes: 30 + environment: release + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + + - uses: ./.github/actions/jdk-setup + with: + server-id: central-publish + server-username: CENTRAL_USERNAME + server-password: CENTRAL_TOKEN + gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} + gpg-passphrase: MAVEN_GPG_PASSPHRASE + + # Tests already ran during release:prepare; the archetype IT needs Docker (absent here). + - name: Deploy release to Maven Central + env: + CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }} + CENTRAL_TOKEN: ${{ secrets.CENTRAL_TOKEN }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + run: ${{ env.MAVEN_COMMAND }} ${{ env.MAVEN_CLI_COMMON }} deploy -Prelease -DskipTests -Darchetype.test.skip=true diff --git a/integration/src/site/asciidoc/releasing.adoc b/integration/src/site/asciidoc/releasing.adoc index f1f0b73..7db1502 100644 --- a/integration/src/site/asciidoc/releasing.adoc +++ b/integration/src/site/asciidoc/releasing.adoc @@ -1,70 +1,42 @@ = Releasing -== Snapshot deployment +Releases publish to Maven Central from CI: you run one command locally, then approve the deploy in GitHub +Actions. Driven by `maven-release-plugin` (parent POM) and `release.yml`. -After every successful build on `main`, the `deploy-snapshot.yml` workflow automatically deploys the -`-SNAPSHOT` artifacts to Maven Central's snapshot repository. No manual action is needed. +== Prerequisites (one-time) -== Release process +* Repo secrets: `CENTRAL_USERNAME`, `CENTRAL_TOKEN`, `GPG_PRIVATE_KEY`, `GPG_PASSPHRASE`. +* A `release` GitHub environment with yourself as a required reviewer — this is the approval gate before publish. +* Docker running locally: `release:prepare` runs `verify`, which includes the archetype integration test. -Releases are driven by `maven-release-plugin` and the `release.yml` GitHub Actions workflow. +== Snapshot deployment -=== 1. Prepare the release +Every successful `main` build deploys the `-SNAPSHOT` to Maven Central via `deploy-snapshot.yml`. No action needed. -Run `maven-release-plugin:prepare` locally. This removes the `-SNAPSHOT` suffix, commits the release version, -creates a `v{version}` tag, and bumps to the next development snapshot: +== Releasing +. Run `release:prepare` locally. It runs `clean verify`, strips `-SNAPSHOT`, commits the release version, tags +`v`, bumps to the next snapshot, and *pushes the commits and tag automatically* (`pushChanges` defaults +to true): ++ [source,powershell] ---- .\mvnw.cmd release:prepare ---- ++ +Prompts for the release version, tag (`v`), and next development version; the defaults are usually right. -The plugin prompts for: - -* *Release version* (e.g., `1.0.0` — accepts the default stripped from `1.0.0-SNAPSHOT`). -* *SCM tag* (e.g., `v1.0.0` — use the `v` prefix to match the workflow trigger). -* *Next development version* (e.g., `1.1.0-SNAPSHOT`). - -Review the two commits and the tag that `release:prepare` creates before pushing. - -=== 2. Push the tag - -[source,powershell] ----- -git push origin main --tags ----- - -=== 3. GitHub Actions takes over +. The pushed `v*` tag triggers `release.yml`, which *waits for your approval* on the `release` environment. Approve +the run in the Actions tab. It then deploys with `-Prelease` (GPG-signed, sources + javadoc) and auto-publishes to +Central. Tests are not re-run (`-DskipTests -Darchetype.test.skip=true`); `release:prepare` already verified them. -Pushing a `v*` tag triggers `release.yml`, which: +. Confirm the artifacts under `io.github.database-audits:database-audits-spring-boot-integration` (and +`…-archetype`). `main` now carries the next `-SNAPSHOT`, and `publish-docs.yml` redeploys the site after the +following `main` build. -. Builds the project with `-Prelease`. -. Signs artifacts with GPG. -. Attaches sources and javadoc JARs. -. Deploys to Maven Central. - -The release profile (`-Prelease`) is defined in the parent POM and activates the GPG signing plugin -and the sources/javadoc attachment plugins. - -== Post-release - -After the release workflow succeeds: - -* Verify the artifacts appear on Maven Central under - `io.github.database-audits:database-audits-spring-boot-integration` and - `io.github.database-audits:database-audits-spring-boot-integration-archetype`. -* The `main` branch now carries the next `-SNAPSHOT` version (committed by `release:prepare`). -* The Maven site is automatically rebuilt and deployed to GitHub Pages by `publish-docs.yml` once the - post-release snapshot build on `main` completes. - -== Rollback - -If `release:prepare` needs to be undone before pushing: - -[source,powershell] ----- -.\mvnw.cmd release:rollback ----- +== Aborting -This restores the `pom.xml` files and removes the local tag. It has no effect once the tag is pushed to the -remote. +Because `release:prepare` pushes immediately, the approval gate is the stop point: *reject* the pending `release` +deployment in the Actions tab so nothing publishes, then drop what prepare pushed — delete the remote tag +(`git push --delete origin v`) and revert the two release commits on `main`. (`release:rollback` only +helps if a `prepare` fails before it pushes.) From 197cda7cfcf9928ad917c6d1a965617ed7843772 Mon Sep 17 00:00:00 2001 From: Jeff Jensen Date: Mon, 22 Jun 2026 18:11:14 -0500 Subject: [PATCH 2/2] ci: Disable credential persistence on snapshot-deploy checkout deploy-snapshot also handles Maven Central credentials and never pushes back to git, so drop the persisted GITHUB_TOKEN. Same hardening as the release workflow. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_013DKrZ3wSe6H5HXPzg8iWC6 --- .github/workflows/deploy-snapshot.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deploy-snapshot.yml b/.github/workflows/deploy-snapshot.yml index 28565e2..3a7d603 100644 --- a/.github/workflows/deploy-snapshot.yml +++ b/.github/workflows/deploy-snapshot.yml @@ -22,6 +22,7 @@ jobs: - uses: actions/checkout@v7 with: ref: ${{ github.event.workflow_run.head_sha }} + persist-credentials: false - uses: ./.github/actions/jdk-setup with: