Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Release to Maven Central

on:
workflow_dispatch:
inputs:
mode:
description: Verify the release build or upload a signed bundle for manual publishing
required: true
default: verify
type: choice
options:
- verify
- upload

permissions:
contents: read

jobs:
verify:
if: inputs.mode == 'verify'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '8'
cache: maven
- run: mvn --batch-mode --no-transfer-progress clean verify

upload:
if: inputs.mode == 'upload'
runs-on: ubuntu-latest
environment: maven-central
steps:
- name: Require a release tag
shell: bash
run: |
if [[ "${GITHUB_REF_TYPE}" != "tag" || "${GITHUB_REF_NAME}" != v* ]]; then
echo "Upload mode must be dispatched from a v* release tag." >&2
exit 1
fi
- uses: actions/checkout@v7
- uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '8'
cache: maven
server-id: central
server-username: CENTRAL_USERNAME
server-password: CENTRAL_PASSWORD
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
gpg-passphrase: MAVEN_GPG_PASSPHRASE
- name: Confirm a non-SNAPSHOT project version
shell: bash
run: |
project_version="$(mvn --quiet help:evaluate -Dexpression=project.version -DforceStdout)"
if [[ "${project_version}" == *-SNAPSHOT ]]; then
echo "Refusing to upload SNAPSHOT version ${project_version}." >&2
exit 1
fi
if [[ "${GITHUB_REF_NAME}" != "v${project_version}" ]]; then
echo "Tag ${GITHUB_REF_NAME} does not match project version ${project_version}." >&2
exit 1
fi
- name: Upload signed bundle for Central validation
run: mvn --batch-mode --no-transfer-progress clean deploy -Prelease
env:
CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }}
CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ The 1.x client does not implement WooCommerce HTTPS Basic Authentication. Use it
mvn verify -Dgpg.skip=true
```

Maintainers preparing a Central release should follow [RELEASING.md](RELEASING.md).

See [CONTRIBUTING.md](CONTRIBUTING.md) and [SECURITY.md](SECURITY.md) before opening an issue or pull request.

## License
Expand Down
54 changes: 54 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Releasing

Releases use the Central Publisher Portal and preserve the coordinates
`com.icoderman:wc-api-java`. The release profile uses
`org.sonatype.central:central-publishing-maven-plugin` with automatic publishing
disabled. Uploading a bundle therefore does not make it public; a maintainer must
review and publish the validated deployment in the Central Portal.

## Safety gates

- Normal pushes and pull requests never invoke the release workflow.
- The workflow is manual and defaults to `verify` mode.
- `upload` mode uses the protected `maven-central` GitHub environment and only
accepts a `v*` tag matching the non-SNAPSHOT POM version.
- The Central plugin has `<autoPublish>false</autoPublish>`.
- Publishing the validated deployment in Central is a separate, explicit,
irreversible action.

Configure the `maven-central` GitHub environment with required reviewers before
adding secrets. Store these environment secrets there:

- `CENTRAL_USERNAME`: username from a newly generated Central Portal user token.
- `CENTRAL_PASSWORD`: password from that token.
- `GPG_PRIVATE_KEY`: ASCII-armored export of the signing private key.
- `GPG_PASSPHRASE`: passphrase for the signing key.

Never commit credentials, private keys, passphrases, Maven `settings.xml`, or a
recovered GnuPG home. The historical signing key fingerprint is
`161A 7A08 F89C 1657 FC4F 0B75 DE35 65D0 3185 1B72`.

## Release sequence

1. Verify `master` and prepare release notes.
2. Change the POM from `1.5-SNAPSHOT` to `1.5.0` in a reviewed release PR.
3. Merge with the repository's noreply commit identity and wait for CI.
4. Create and push the signed/approved `v1.5.0` tag.
5. Dispatch this workflow from `v1.5.0` in `upload` mode.
6. Inspect the validated deployment in the Central Portal.
7. Publish it only after explicit owner approval.
8. Resolve the artifact from a clean Maven consumer before creating the GitHub
Release and announcing availability.

For a credential-free build check, dispatch `verify` mode or run:

```bash
mvn clean verify
```

For a local signed-bundle check without deploying, use an isolated GnuPG home and
run:

```bash
GNUPGHOME=/path/to/isolated/.gnupg mvn clean verify -Prelease
```
56 changes: 38 additions & 18 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -107,24 +107,6 @@
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.8</version>
<configuration>
<useAgent>true</useAgent>
</configuration>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
Expand All @@ -134,4 +116,42 @@
</plugins>
</build>

<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.8</version>
<configuration>
<useAgent>true</useAgent>
</configuration>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.11.0</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
<autoPublish>false</autoPublish>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>

</project>
Loading