Maven Release Plugin
Original document: github.com/nyg/kraken-api-java/blob/master/RELEASE.md
This document explains how a kraken-api-java release is created, describes what are the tools used, and how they interact with each other.
When a release is created, the visible "output" is an updated CHANGLOG.md file, a GitHub release with a changelog, and the release artifact available in the Maven Central repository.
Overview
When wanting to make a release, the following must/will be performed:
- Manually execute the prepare goal of the maven-release-plugin, this will create a git tag and push it to the remote repository.
- Once the tag is pushed, the user-defined GitHub Actions workflow is triggered and creates a GitHub release with a changelog generated by git-cliff.
- Manually execute the perform goal of the maven-release-plugin, this will build and upload the artifacts to Sonatype's servers.
- Manually publish to Maven Central the uploaded artifacts using Sonatype's website (this can be done automatically in step 3, see below).
In theory, all of these steps could be merged into a single GitHub Actions workflow. However, for the time being, we prefer to delegate a minimum amount of steps to GitHub. Regarding step 2, it could be run manually from one's own machine as it consists of a single GitHub REST API call.
Also note that we do not use GitHub's own Maven repository, a.k.a. GitHub Packages.
Detailed steps
The Maven release plugin helps automatizing certain tasks when making releases for Maven-based projects. Releasing requires invoking two of the plugin's goals: prepare
and perform
.
In short, the prepare
goal updates version numbers in the POMs and creates a tag in the SCM (e.g. Git). The perform
goal checks out the created tag, builds the project artifacts and publishes them on a remote Maven repository.
Prepare release
The detailed list of steps executed by the prepare goal are defined here and here. In scope of this project, the main ones are:
-
Change the version numbers in the POM files. How the plugin will compute the version number to use for release (and the one to use for the next development version) is defined by the
projectVersionPolicyId
andprojectVersionPolicyConfig
goal parameters. As this mechanism does not allow us to specify whether we are performing a patch, minor or major release (if we are even using semantic versioning), we just pass these values via thereleaseVersion
anddevelopmentVersion
parameters (i.e.-DreleaseVersion=2.0.0 -DdevelopmentVersion=2.0.1-SNAPSHOT
on the command line).Note: in multi-module projects, set
autoVersionSubmodules
to true to have all POMs updated. -
Run the preparation goals. By default, the goals bound to the
clean
andverify
lifecycle phases are executed. In this project we add another goal:exec:exec
(of MojoHaus' exec-maven-plugin), in order to execute thescripts/generate-changelog.sh
script which will execute git-cliff to update the CHANGELOG.md file. The config for git-cliff is in thecliff.toml
file. The preparation goals are defined in the main POM file with thepreparationGoals
parameter.Note: these goals are run for every Maven module, which require us to do some trickery in the generate-changelog.sh script to only run in the parent module. It's also possible to specify a list of profiles to enable via the
preparationProfiles
parameter. -
Create and push a commit with the changes made in the two steps above. The default commit message is something like "[maven-release-plugin] prepare release v2.0.0". The message can be customized with the following parameters:
scmCommentPrefix
andscmReleaseCommitComment
. We only modify the prefix tochore(release):
in order to adhere to conventional commits.Note: both commits and tags are signed (this requires some Git config, GPG keys and the
signTag
goal parameter). It is possible to prevent pushing the commit to the remote repository by settingpushChanges
to false. -
Tag the commit created in step 3 and push the tag to the remote repository. We specify the tag name on the command line, using the
tag
parameter, e.g.-Dtag=v2.0.0
. If the tag is not given, see theprojectTagNamingPolicyId
andtagNameFormat
parameters. -
Change the version numbers in the POM files to prepare for the next development version. As mentioned in the first step, this value is passed via the command line, with the
developmentVersion
parameter.Note: if some custom goal needs to be run after this change and before the commit, it can be specified with the
completionGoals
parameter. -
Create and push a commit with the changes made above. The message of the commit can be customized with the
scmDevelopmentCommitComment
.
The prepare goal also creates a release.properties
file that is used by the perform
goal in order to know which tag to checkout and build.
Finally, when wanting to make a release, the command line looks like this:
mvn -Dtag=v2.0.0 -DreleaseVersion=2.0.0 -DdevelopmentVersion=2.0.1-SNAPSHOT release:prepare
If we want to make sure thing are correct before committing we can use -DdryRun=true
. If we prefer not to push, we can use -DpushChanges=false
. If the goal execution fails, or after a dry-run, we can clean the created files using:
mvn release:clean
GitHub release
As described above, a tag is created and pushed to the remote repository. In our case, that's GitHub. GitHub allows setting up workflows to run automatically when certain events are triggered. In .github/workflows/github-release.yml
, we define a workflow to run whenever a new tag is pushed. This workflow will execute the following steps:
- Checkout the repository using the checkout action.
- Generate a CHANGELOG.md file using the git-cliff-action.
- Create a GitHub release using the GitHub CLI and give it the CHANGELOG.md file generated above to be used in the description.
Perform release
The perform
goal is simpler than the prepare
goal. Its documentation can be found here. In scope of this project, the main steps are:
-
Checkout out the version of the project specified in the
release.properties
file created by theprepare
goal. This is done in the target folder. -
Run the perform goals defined by the
goals
parameter. The default isdeploy site-deploy
. While this is left unchanged, we set thereleaseProfiles
tosonatype-release
. In this user-defined profile we do the following:-
use the maven-source-plugin to create a source JAR (bound to the package phase),
-
use the maven-javadoc-plugin to create a Javadoc JAR (bound to the package phase),
-
use the maven-gpg-plugin to sign the JARs with a previously created GPG key (bound to the verify phase),
Note: these steps are required in order to produce a deployment considered valid by Sonatype, see here.
-
use the central-publishing-maven-plugin to upload the built artifacts to the Sonatype's website (bound to the deploy phase). Once the artifacts are uploaded, they must be published to Maven Central. This can either be done manually through Sonatype's website, or by asking the plugin to do it for us by setting the
autoPublish
parameter to true. Also, as we don't want to publish the examples module, we exclude it with theexcludeArtifacts
parameter.
-
-
Remove the files left by
prepare
goal.