A Maven plugin for automated semantic versioning with Markdown-based changelog management.
- Overview
- Requirements
- Installation
- Goals
- Configuration Properties
- Examples
- GitHub Action Integration
- Maintenance Scripts
- License
The Semantic Version Maven Plugin automates version management using semantic versioning principles (MAJOR.MINOR.PATCH). It integrates changelog management through Markdown files, enabling you to:
- Create version bump specifications with Markdown changelog entries
- Automatically update POM file versions based on semantic versioning rules
- Maintain synchronized changelog files across single and multi-module Maven projects
- Support multiple versioning strategies for different project structures
- Java: 17 or higher
- Maven: 3.9.12 or higher
Add the plugin to your pom.xml:
<build>
<plugins>
<plugin>
<groupId>io.github.bsels</groupId>
<artifactId>semantic-version-maven-plugin</artifactId>
<version>1.5.0</version>
</plugin>
</plugins>
</build>- create: Creates a version Markdown file for specifying version bumps.
- update: Updates POM file versions and CHANGELOG.md files based on version Markdown files.
- verify: Verifies that version Markdown files are consistent with the project scope.
- graph: Generates a JSON representation of the project dependency graph.
Full name: io.github.bsels:semantic-version-maven-plugin:create
Description: Creates a version Markdown file that specifies which projects should receive which type of semantic version bump (PATCH, MINOR, or MAJOR). The goal provides an interactive interface to select projects and their version bump types, and allows you to write changelog entries either inline or via an external editor.
Phase: Not bound to any lifecycle phase (standalone goal)
| Property | Type | Default | Description |
|---|---|---|---|
versioning.modus |
Modus |
PROJECT_VERSION |
Versioning strategy: • PROJECT_VERSION: All projects in multi-module builds• REVISION_PROPERTY: Only current project using the revision property• PROJECT_VERSION_ONLY_LEAFS: Only leaf projects (no modules) |
versioning.identifier |
ArtifactIdentifier |
GROUP_ID_AND_ARTIFACT_ID |
Artifact key format in version Markdown files: • GROUP_ID_AND_ARTIFACT_ID: use groupId:artifactId keys (default)• ONLY_ARTIFACT_ID: use artifactId only when all modules share the same groupId |
versioning.directory |
Path |
.versioning |
Directory for storing version Markdown files |
versioning.dryRun |
boolean |
false |
Preview changes without writing files |
versioning.backup |
boolean |
false |
Create backup of files before modification |
versioning.commit.message.create |
String |
Created version Markdown file for {numberOfProjects} project(s) |
Commit message template for version Markdown file creation. Use {numberOfProjects} placeholder for project count |
versioning.git |
Git |
NO_GIT |
Defines the git operation mode: • NO_GIT: no git operations will be performed• STAGING: stage all changed files (added to the git index)• STASH: added changed files to the git staging (deprecated since 1.5.0: use STAGING)• COMMIT: commit all changed files with the configured commit message |
Basic usage (interactive mode):
mvn io.github.bsels:semantic-version-maven-plugin:createWith custom versioning directory:
mvn io.github.bsels:semantic-version-maven-plugin:create \
-Dversioning.directory=.versionsDry-run to preview:
mvn io.github.bsels:semantic-version-maven-plugin:create \
-Dversioning.dryRun=trueMulti-module project (leaf projects only):
mvn io.github.bsels:semantic-version-maven-plugin:create \
-Dversioning.modus=PROJECT_VERSION_ONLY_LEAFSFull name: io.github.bsels:semantic-version-maven-plugin:update
Description: Updates POM file versions and CHANGELOG.md files based on version Markdown files created by the
create goal. The goal reads version bump specifications from Markdown files, applies semantic versioning to project
versions, updates dependencies in multi-module projects, and merges changelog entries into CHANGELOG.md files.
Phase: Not bound to any lifecycle phase (standalone goal)
| Property | Type | Default | Description |
|---|---|---|---|
versioning.bump |
VersionBump |
FILE_BASED |
Version bump strategy: • FILE_BASED: Use version Markdown files from .versioning directory• MAJOR: Apply MAJOR version bump to all projects• MINOR: Apply MINOR version bump to all projects• PATCH: Apply PATCH version bump to all projects• SUFFIX_ONLY: Only update the version suffix (requires versioning.suffix) |
versioning.modus |
Modus |
PROJECT_VERSION |
Versioning strategy: • PROJECT_VERSION: All projects in multi-module builds• REVISION_PROPERTY: Only current project using the revision property• PROJECT_VERSION_ONLY_LEAFS: Only leaf projects (no modules) |
versioning.identifier |
ArtifactIdentifier |
GROUP_ID_AND_ARTIFACT_ID |
Artifact key format in version Markdown files: • GROUP_ID_AND_ARTIFACT_ID: use groupId:artifactId keys (default)• ONLY_ARTIFACT_ID: use artifactId only when all modules share the same groupId |
versioning.directory |
Path |
.versioning |
Directory containing version Markdown files |
versioning.dryRun |
boolean |
false |
Preview changes without writing files |
versioning.backup |
boolean |
false |
Create backup of POM and CHANGELOG files before modification |
versioning.commit.message.update |
String |
Updated {numberOfProjects} project version(s) [skip ci] |
Commit message template for version updates. Use {numberOfProjects} placeholder for project count |
versioning.dependency.bump.message |
String |
Project version bumped as result of dependency bumps |
Changelog entry text used when a project version is bumped because of dependency updates |
versioning.update.scripts |
String |
- |
Script paths to execute per updated module, separated by the OS path separator (: on Unix-like systems, ; on Windows). Each script runs in the module directory with CURRENT_VERSION, NEW_VERSION, DRY_RUN (true or false), GIT_STASH (true or false. Deprecated since 1.5.0: use GIT_STAGING), GIT_STAGING (true or false), PROJECT_PATH (absolute path to module directory) and EXECUTION_DATE (yyyy-MM-dd) environment variables. For instance, to automate deprecation version management: -Dversioning.update.scripts=./update-deprecation-version.sh (adjusting the paths to the project root). |
versioning.version.header |
String |
{version} - {date#yyyy-MM-dd} |
Header format for version Markdown files. Supports {version} and {date#yyyy-MM-dd} placeholders; date uses a DateTimeFormatter pattern. |
versioning.changelog.header |
String |
Changelog |
Header label for the changelog title (H1) |
versioning.major.header |
String |
Major |
Header label for major changes in the changelog |
versioning.minor.header |
String |
Minor |
Header label for minor changes in the changelog |
versioning.patch.header |
String |
Patch |
Header label for patch changes in the changelog |
versioning.other.header |
String |
Other |
Header label for non-semantic changes in the changelog |
versioning.suffix |
String |
- |
Optional suffix to append to the bumped version (e.g., -BETA, -RC1). If it doesn't start with a dash, one will be automatically added. |
versioning.git |
Git |
NO_GIT |
Defines the git operation mode: • NO_GIT: no git operations will be performed• STAGING: stage all changed files (added to the git index)• STASH: added changed files to the git staging (deprecated since 1.5.0: use STAGING)• COMMIT: commit all changed files with the configured commit message |
Basic usage (file-based versioning):
mvn io.github.bsels:semantic-version-maven-plugin:updateForce MAJOR version bump (override version files):
mvn io.github.bsels:semantic-version-maven-plugin:update \
-Dversioning.bump=MAJORForce MINOR version bump:
mvn io.github.bsels:semantic-version-maven-plugin:update \
-Dversioning.bump=MINORForce PATCH version bump:
mvn io.github.bsels:semantic-version-maven-plugin:update \
-Dversioning.bump=PATCHDry-run to preview changes:
mvn io.github.bsels:semantic-version-maven-plugin:update \
-Dversioning.dryRun=trueWith backup files:
mvn io.github.bsels:semantic-version-maven-plugin:update \
-Dversioning.backup=trueCustom versioning directory:
mvn io.github.bsels:semantic-version-maven-plugin:update \
-Dversioning.directory=.versionsCustom version file header:
mvn io.github.bsels:semantic-version-maven-plugin:update \
-Dversioning.version.header='Release {version} ({date#yyyy-MM-dd})'Multi-module project with revision property:
mvn io.github.bsels:semantic-version-maven-plugin:update \
-Dversioning.modus=REVISION_PROPERTYWith version suffix:
mvn io.github.bsels:semantic-version-maven-plugin:update \
-Dversioning.suffix=BETAFull name: io.github.bsels:semantic-version-maven-plugin:verify
Description: Verifies that version Markdown files are consistent with the project scope. The goal reads version
Markdown files, validates that all referenced artifacts exist in scope, enforces the selected verification mode, and
optionally requires consistent version bumps across all projects. When versioning.git is not NO_GIT, it runs
git status before verification. This goal does not write files; versioning.dryRun and versioning.backup have no
effect.
Phase: Not bound to any lifecycle phase (standalone goal)
| Property | Type | Default | Description |
|---|---|---|---|
versioning.verification.mode |
VerificationMode |
ALL_PROJECTS |
Verification scope: • NONE: skip verification• AT_LEAST_ONE_PROJECT: require at least one version-marked project• DEPENDENT_PROJECTS: require all dependent projects to be version-marked• ALL_PROJECTS: all projects in scope must be version-marked |
versioning.verification.consistent |
boolean |
false |
When true, all version-marked projects must share the same version bump type |
versioning.modus |
Modus |
PROJECT_VERSION |
Project scope for verification: • PROJECT_VERSION: all projects in multi-module builds• REVISION_PROPERTY: only current project using the revision property• PROJECT_VERSION_ONLY_LEAFS: only leaf projects (no modules) |
versioning.identifier |
ArtifactIdentifier |
GROUP_ID_AND_ARTIFACT_ID |
Artifact key format in version Markdown files: • GROUP_ID_AND_ARTIFACT_ID: use groupId:artifactId keys (default)• ONLY_ARTIFACT_ID: use artifactId only when all modules share the same groupId |
versioning.directory |
Path |
.versioning |
Directory containing version Markdown files |
versioning.git |
Git |
NO_GIT |
Git mode. Any value other than NO_GIT triggers a git status check before verification. Supported modes:• NO_GIT: no git operations will be performed• STAGING: stage all changed files (added to the git index)• STASH: added changed files to the git staging (deprecated since 1.5.0: use STAGING)• COMMIT: commit all changed files with the configured commit message |
Basic verification:
mvn io.github.bsels:semantic-version-maven-plugin:verifyVerify dependent projects and require consistent bumps:
mvn io.github.bsels:semantic-version-maven-plugin:verify \
-Dversioning.verification.mode=DEPENDENT_PROJECTS \
-Dversioning.verification.consistent=trueFull name: io.github.bsels:semantic-version-maven-plugin:graph
Description: Generates a JSON representation of the dependency graph for Maven projects within the current execution scope. It identifies internal dependencies between projects and can output the graph either to the console or to a specified file. The output includes transitive dependencies sorted in build order (topological order).
Phase: Not bound to any lifecycle phase (standalone goal)
| Property | Type | Default | Description |
|---|---|---|---|
versioning.graphOutput |
GraphOutput |
ARTIFACT_AND_FOLDER |
Specifies the graph output format: • ARTIFACT_ONLY: Only Maven artifact identifiers• FOLDER_ONLY: Only project folder paths• ARTIFACT_AND_FOLDER: Both artifact identifiers and folder paths |
versioning.outputFile |
Path |
- |
Path to the output file. If not specified, the graph is printed to the console. |
versioning.relativePaths |
boolean |
true |
When true, project folder paths are resolved relative to the execution root; otherwise, absolute paths are used. |
versioning.modus |
Modus |
PROJECT_VERSION |
Project scope for the graph: • PROJECT_VERSION: All projects in multi-module builds• REVISION_PROPERTY: Only current project using the revision property• PROJECT_VERSION_ONLY_LEAFS: Only leaf projects (no modules) |
The generated JSON is a map where each key is a project's artifact identifier (groupId:artifactId), and the value is a
list of its internal dependencies.
ARTIFACT_ONLY:
{
"io.github.bsels:parent": [],
"io.github.bsels:child": [
"io.github.bsels:parent"
]
}FOLDER_ONLY:
{
"io.github.bsels:parent": [],
"io.github.bsels:child": [
"."
]
}ARTIFACT_AND_FOLDER:
{
"io.github.bsels:parent": [],
"io.github.bsels:child": [
{
"artifact": {
"groupId": "io.github.bsels",
"artifactId": "parent"
},
"folder": "."
}
]
}Basic usage (print to console):
mvn io.github.bsels:semantic-version-maven-plugin:graphWrite to file with absolute paths:
mvn io.github.bsels:semantic-version-maven-plugin:graph \
-Dversioning.outputFile=graph.json \
-Dversioning.relativePaths=falseArtifact-only output:
mvn io.github.bsels:semantic-version-maven-plugin:graph \
-Dversioning.graphOutput=ARTIFACT_ONLYThese properties apply to create, update, and verify goals. The verify goal does not use
versioning.dryRun or versioning.backup:
| Property | Type | Default | Description |
|---|---|---|---|
versioning.modus |
Modus |
PROJECT_VERSION |
Defines versioning strategy for project structure: • PROJECT_VERSION: Process all projects in topological order• REVISION_PROPERTY: Process only the current project using the revision property• PROJECT_VERSION_ONLY_LEAFS: Process only leaf projects (no child modules) |
versioning.identifier |
ArtifactIdentifier |
GROUP_ID_AND_ARTIFACT_ID |
Artifact key format in version Markdown files: • GROUP_ID_AND_ARTIFACT_ID: use groupId:artifactId keys (default)• ONLY_ARTIFACT_ID: use artifactId only when all modules share the same groupId |
versioning.directory |
Path |
.versioning |
Directory path for version Markdown files (absolute or relative to project root) |
versioning.dryRun |
boolean |
false |
When true, performs all operations without writing files (logs output instead) |
versioning.backup |
boolean |
false |
When true, creates .bak backup files before modifying POM and CHANGELOG files |
versioning.git |
Git |
NO_GIT |
Defines the git operation mode: • NO_GIT: no git operations will be performed• STAGING: stage all changed files (added to the git index)• STASH: added changed files to the git staging (deprecated since 1.5.0: use STAGING)• COMMIT: commit all changed files with the configured commit message |
| Property | Type | Default | Description |
|---|---|---|---|
versioning.commit.message.create |
String |
Created version Markdown file for {numberOfProjects} project(s) |
Commit message template used when creating version Markdown files. The {numberOfProjects} placeholder is replaced with the actual count |
| Property | Type | Default | Description |
|---|---|---|---|
versioning.bump |
VersionBump |
FILE_BASED |
Determines version increment strategy: • FILE_BASED: Read version bumps from Markdown files in .versioning directory• MAJOR: Force MAJOR version increment (X.0.0) for all projects• MINOR: Force MINOR version increment (0.X.0) for all projects• PATCH: Force PATCH version increment (0.0.X) for all projects• SUFFIX_ONLY: Only update the version suffix (requires versioning.suffix) |
versioning.commit.message.update |
String |
Updated {numberOfProjects} project version(s) [skip ci] |
Commit message template used when updating project versions. The {numberOfProjects} placeholder is replaced with the actual count |
versioning.dependency.bump.message |
String |
Project version bumped as result of dependency bumps |
Changelog entry text used when a project version is bumped because of dependency updates |
versioning.update.scripts |
String |
- |
Script paths to execute per updated module, separated by the OS path separator (: on Unix-like systems, ; on Windows). Each script runs in the module directory with CURRENT_VERSION, NEW_VERSION, DRY_RUN (true or false), GIT_STASH (true or false. Deprecated since 1.5.0: use GIT_STAGING), GIT_STAGING (true or false), PROJECT_PATH (absolute path to module directory) and EXECUTION_DATE (yyyy-MM-dd) environment variables. For instance, to automate deprecation version management: -Dversioning.update.scripts=./update-deprecation-version.sh (adjusting the paths to the project root). |
versioning.version.header |
String |
{version} - {date#yyyy-MM-dd} |
Header format for version Markdown files. Supports {version} and {date#yyyy-MM-dd} placeholders; date uses a DateTimeFormatter pattern. |
versioning.changelog.header |
String |
Changelog |
Header label for the changelog title (H1) |
versioning.major.header |
String |
Major |
Header label for major changes in the changelog |
versioning.minor.header |
String |
Minor |
Header label for minor changes in the changelog |
versioning.patch.header |
String |
Patch |
Header label for patch changes in the changelog |
versioning.other.header |
String |
Other |
Header label for non-semantic changes in the changelog |
versioning.suffix |
String |
- |
Optional suffix to append to the bumped version (e.g., -BETA, -RC1). If it doesn't start with a dash, one will be automatically added. |
| Property | Type | Default | Description |
|---|---|---|---|
versioning.verification.mode |
VerificationMode |
ALL_PROJECTS |
Verification scope: • NONE: skip verification• AT_LEAST_ONE_PROJECT: require at least one version-marked project• DEPENDENT_PROJECTS: require all dependent projects to be version-marked• ALL_PROJECTS: all projects in scope must be version-marked |
versioning.verification.consistent |
boolean |
false |
When true, all version-marked projects must share the same version bump type |
| Property | Type | Default | Description |
|---|---|---|---|
versioning.graphOutput |
GraphOutput |
ARTIFACT_AND_FOLDER |
Specifies the graph output format: • ARTIFACT_ONLY: Only artifact identifiers• FOLDER_ONLY: Only folder paths• ARTIFACT_AND_FOLDER: Artifacts and folder paths |
versioning.outputFile |
Path |
- |
Path to the output file. If not specified, output is printed to the console. |
versioning.relativePaths |
boolean |
true |
When true, project paths are relative to execution root; otherwise, absolute. |
-
Create version specification:
mvn io.github.bsels:semantic-version-maven-plugin:create
- Select MINOR version bump
- Enter changelog: "Added new user authentication feature"
-
Preview changes:
mvn io.github.bsels:semantic-version-maven-plugin:update -Dversioning.dryRun=true
-
Apply version update:
mvn io.github.bsels:semantic-version-maven-plugin:update
-
Create version specifications for multiple modules:
mvn io.github.bsels:semantic-version-maven-plugin:create
- Select
module-api→ MAJOR (breaking changes) - Select
module-core→ MINOR (new features) - Enter changelog for each module
- Select
-
Update with backups:
mvn io.github.bsels:semantic-version-maven-plugin:update -Dversioning.backup=true
Skip version file creation and force PATCH bump:
mvn io.github.bsels:semantic-version-maven-plugin:update -Dversioning.bump=PATCHUpdate only the version suffix without changing the semantic version:
mvn io.github.bsels:semantic-version-maven-plugin:update \
-Dversioning.bump=SUFFIX_ONLY \
-Dversioning.suffix=RC1Configure the plugin directly in pom.xml:
<build>
<plugins>
<plugin>
<groupId>io.github.bsels</groupId>
<artifactId>semantic-version-maven-plugin</artifactId>
<version>1.5.0</version>
<configuration>
<modus>PROJECT_VERSION</modus>
<versionDirectory>.versioning</versionDirectory>
<dryRun>false</dryRun>
<backupFiles>true</backupFiles>
<versionBump>FILE_BASED</versionBump>
</configuration>
</plugin>
</plugins>
</build>You can automate your release process by integrating this plugin into a GitHub Action workflow.
Below is an example workflow that triggers on a push to the main branch, updates versions based on Markdown files,
commits changes, and creates a GitHub release.
name: Push create release
on:
push:
branches: [ main ]
permissions:
contents: write
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Setup Java
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
- name: Checkout repository
uses: actions/checkout@v7
- name: Set up Git user
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
- name: Run versioning
id: bumpVersion
run: |
set -e
# Run the update goal to apply version bumps and commit changes
# We also run maintenance scripts to update the README and deprecation versions
mvn io.github.bsels:semantic-version-maven-plugin:update \
-Dversioning.git=COMMIT \
-Dversioning.update.scripts=./update-deprecation-version.sh
# Capture the new version for subsequent steps
VERSION=$(./mvnw help:evaluate -Dexpression=project.version -q -DforceStdout)
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Create tag and push
run: |
git tag "v${{ steps.bumpVersion.outputs.version }}"
git push
git push origin tag "v${{ steps.bumpVersion.outputs.version }}"
- name: Create release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ format('v{0}', steps.bumpVersion.outputs.version) }}
run: |
gh release create "$tag" \
--repo="$GITHUB_REPOSITORY" \
--title="${GITHUB_REPOSITORY#*/} ${tag#v}" \
--generate-notesTo ensure that every pull request includes the necessary versioning files,
you can use the verify goal in your PR workflow.
This example fails the build if the versioning specifications are missing or inconsistent.
name: Pull Request Build
on:
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Setup Java
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '17'
- name: Build verify versioning
run: |
# Run the verify goal to check for consistent versioning files
mvn io.github.bsels:semantic-version-maven-plugin:verifyThe plugin can execute external scripts during the update goal via the versioning.update.scripts property. These
scripts are useful for keeping documentation and source code in sync with the new version.
Each script receives the following environment variables:
CURRENT_VERSION: The version before the bump.NEW_VERSION: The new version being applied.PROJECT_PATH: Absolute path to the module directory.DRY_RUN:trueorfalse.GIT_STAGING:trueorfalse(indicates if the script should stage its changes).EXECUTION_DATE: The date of execution inyyyy-MM-ddformat.
This script automates the replacement of the 1.5.0 placeholder in the codebase.
It searches for the placeholder in Java source files and Markdown documentation and replaces it with the NEW_VERSION.
#!/usr/bin/env bash
set -e
if [ -z "$NEW_VERSION" ]; then
echo "Error: NEW_VERSION environment variable is not set."
exit 1
fi
PLACEHOLDER="1.5.0"
BASE_DIR="${PROJECT_PATH:-.}"
# Identify files containing the placeholder within the project path
# Exclude the script itself, .git, and target directories
FILES=$(grep -lR "$PLACEHOLDER" "$BASE_DIR" --exclude=update-deprecation-version.sh --exclude-dir=.git --exclude-dir=target || true)
if [ -z "$FILES" ]; then
echo "No files containing placeholder $PLACEHOLDER found."
exit 0
fi
if [ "$DRY_RUN" = "true" ]
then
for FILE in $FILES; do
echo "Dry run: replacement in $FILE"
sed "s/$PLACEHOLDER/$NEW_VERSION/g" "$FILE"
done
else
for FILE in $FILES; do
echo "Processing $FILE..."
sed -i "s/$PLACEHOLDER/$NEW_VERSION/g" "$FILE"
if [ "$GIT_STAGING" = "true" ]
then
git add "$FILE"
fi
done
echo "Successfully updated deprecation version to $NEW_VERSION"
fiUsage in pom.xml:
<configuration>
<updateScripts>./update-deprecation-version.sh</updateScripts>
</configuration>This project is licensed under the MIT License. See the LICENSE file for details.