Skip to content

javachanges GitHub Actions Release Flow

1. Overview

This repository now includes a GitHub Actions release pipeline built on javachanges itself.

This page is repository-specific. For broader GitHub Actions integration patterns, see GitHub Actions Usage Guide.

The intended flow is:

  1. feature branches merge into main
  2. main contains one or more .changesets/*.md files
  3. GitHub Actions generates or updates a release PR
  4. the release PR is merged
  5. GitHub Actions can publish snapshots from snapshot
  6. GitHub Actions tags the release, publishes to Maven Central, and creates a GitHub Release

1.1 Workflow graph

Loading diagram...

2. Workflows

The repository contains four workflows:

FilePurpose
.github/workflows/ci.ymlRegular CI for Java 8 build and publish-profile verification
.github/workflows/release-plan.ymlScans pending changesets on main and generates a release PR
.github/workflows/publish-snapshot.ymlPublishes the current snapshot branch build to the configured snapshot repository
.github/workflows/publish-release.ymlPublishes after the release PR is merged

3. Release PR workflow

The core command in release-plan.yml is:

bash
mvn -B -DskipTests exec:java -Dexec.args="github-release-plan --directory $GITHUB_WORKSPACE --write-plan-files false --execute true"

It:

ActionMeaning
Reads .changesets/*.mdCollects pending release intent
Computes release versionsProduces releaseVersion and nextSnapshotVersion
Applies the planUpdates <revision> and CHANGELOG.md without committing generated plan files
Deletes consumed changesetsPrevents duplicate releases

The workflow then commits those changes to:

bash
changeset-release/main

and creates or updates a pull request.

4. Snapshot publish workflow

publish-snapshot.yml runs on pushes to snapshot and on manual workflow_dispatch.

It:

  1. validates snapshot repository variables and credentials
  2. derives a stable snapshot build stamp for the workflow run
  3. runs javachanges preflight --snapshot
  4. runs javachanges publish --snapshot --execute true

The workflow publishes a unique snapshot revision such as:

text
1.3.1-20260420.154500.abc1234-SNAPSHOT

In this repository, the workflow explicitly passes a build stamp based on:

text
<github.run_id>.<github.run_attempt>.<git short sha>

so reruns remain distinguishable even when they target the same root snapshot line on the snapshot branch.

Configure these GitHub Actions secrets for snapshot publishing:

TypeNameRequired
SecretMAVEN_CENTRAL_USERNAMEYes
SecretMAVEN_CENTRAL_PASSWORDYes
SecretMAVEN_GPG_PRIVATE_KEYYes
SecretMAVEN_GPG_PASSPHRASEYes

The snapshot workflow in this repository now uses central-publishing-maven-plugin with a -SNAPSHOT revision and the same Central Portal token pair used for releases, instead of publishing through distributionManagement with a separate maven-snapshots server id.

After the workflow succeeds, the primary snapshot verification addresses are:

  • https://central.sonatype.com/repository/maven-snapshots/
  • https://central.sonatype.com/repository/maven-snapshots/io/github/sonofmagic/javachanges/<resolved-snapshot-version>/maven-metadata.xml
  • https://central.sonatype.com/repository/maven-snapshots/io/github/sonofmagic/javachanges/<resolved-snapshot-version>/javachanges-<timestamped-version>.jar

The repository root itself is not directly browseable for hosted snapshots, so verification should rely on metadata URLs, concrete artifact URLs, or a real Maven/Gradle resolve.

5. Release publish workflow

publish-release.yml runs in two modes:

  1. automatically after a merged release PR
  2. manually through workflow_dispatch when you need to retry publishing for an existing merged release commit

Automatic mode only runs when all of these are true:

ConditionMeaning
the PR was mergednot just closed
the base branch is mainonly the mainline is released
the head branch is changeset-release/mainonly release PRs trigger publishing

It then:

  1. checks out the merged release commit
  2. runs github-tag-from-plan --execute true
  3. runs github-release-from-plan to generate target/release-notes.md and export releaseVersion
  4. publishes to Maven Central with the central-publish profile
  5. runs github-release-from-plan --execute true to create or update the GitHub Release

5.1 Release retry behavior

Publish Release is designed to be safe to rerun for the same merged release commit.

If a previous run created the release tag but failed before Maven Central publishing or GitHub Release creation, rerun Publish Release with the same merged release commit SHA. github-release-publish-state continues when no GitHub Release exists and the remote tag points at that commit. github-tag-from-plan then treats the existing tag as a recoverable state instead of trying to recreate it.

If the remote tag exists but points at a different commit, the workflow fails before publishing. In that case, inspect the tag and rerun the workflow for the tagged commit, or move the tag only after confirming the previous tag target was wrong.

6. Required repository secrets

Configure these in Settings > Secrets and variables > Actions:

SecretPurpose
MAVEN_CENTRAL_USERNAMESonatype Central Portal token username
MAVEN_CENTRAL_PASSWORDSonatype Central Portal token password
MAVEN_GPG_PRIVATE_KEYASCII-armored GPG private key
MAVEN_GPG_PASSPHRASEGPG private key passphrase

publish-release.yml validates these secrets before it prepares Java, Maven settings, or GPG. If any secret is missing, the workflow stops immediately with a direct error that names the missing secret.

After actions/setup-java imports the private key, both publishing workflows now run the javachanges ensure-gpg-public-key command. That step:

  1. extracts the imported signing key fingerprint
  2. attempts to upload the public key to hkps://keyserver.ubuntu.com and hkps://keys.openpgp.org
  3. waits until the fingerprint becomes discoverable from at least one supported keyserver

This prevents Maven Central from failing later with an error like Invalid signature for file ... Could not find a public key by the key fingerprint.

For the failed run at Actions > Publish Release, the practical recovery path is:

  1. add the missing secrets
  2. rerun the failed workflow or failed job
  3. if the previous failure mentioned an undiscoverable GPG key fingerprint, rerun after this repository change so the workflow can publish and verify the public key before deploy
  4. confirm the rerun reaches the Publish to Maven Central step

Typical development flow:

  1. create a branch
  2. change code
  3. add a changeset
  4. open a PR
  5. merge into main

Example:

bash
mvn -q -DskipTests compile exec:java -Dexec.args="add --directory $PWD --summary 'add GitHub Actions release automation' --release minor"

That command writes a changeset file in the official package-map format, for example:

md
```md
---
"javachanges": minor
---

add GitHub Actions release automation
```

8. Versioning model

To support “merge release PR first, publish the real release afterwards,” this repository now uses:

xml
<version>${revision}</version>

and maintains development state with:

xml
<revision>1.0.0-SNAPSHOT</revision>

That means:

StageVersion
Published versionDerived with manifest-field --fresh true, for example 1.0.0
Main branch versionAlready advanced to the next snapshot, for example 1.0.1-SNAPSHOT

The publish workflow uses:

bash
-Drevision=<releaseVersion>

so it publishes the real release version instead of the current snapshot revision on main.

The snapshot workflow uses:

bash
-Drevision=<baseVersion>-<snapshotBuildStamp>-SNAPSHOT

so repeated snapshot publishes do not overwrite one another under the same visible revision line.

In this repository, the intended developer path is:

  1. merge release work into main
  2. merge work that should produce a published snapshot into snapshot
  3. let publish-snapshot.yml publish from the snapshot branch head

9. Manual triggers

If you need to rerun one of the workflows manually:

WorkflowSupports workflow_dispatch
Release PlanYes
Publish SnapshotYes
Publish ReleaseYes, with release_commit_sha set to the merged release commit

If a merged release PR already triggered a failed Publish Release run, you usually do not need a new release PR. Trigger Publish Release manually and pass the original merged release commit SHA through release_commit_sha.

10. Local validation

Before relying on the automation, you can validate locally:

bash
mvn -B verify
mvn -B -Pcentral-publish -Dgpg.skip=true verify
mvn -B -DskipTests compile exec:java -Dexec.args="status --directory $PWD"
mvn -B -DskipTests compile exec:java -Dexec.args="preflight --directory $PWD --snapshot --snapshot-build-stamp local.dev.001"

11. Summary

The standard release path for this repository is now:

StageEntry point
Regular validationCI workflow
Snapshot publishingPublish Snapshot workflow
Release PR generationRelease Plan workflow
Real publishingPublish Release workflow

For reusable workflow patterns outside this repository, continue with GitHub Actions Usage Guide.

Released under the Apache-2.0 License.