Skip to main content

Java CI/CD Workflows

Generated by java-ci-library, which is composed by all three Java service archetypes:

  • java-rest-service-archetype
  • java-grpc-service-archetype
  • java-graphql-service-archetype

The protocol has no effect on the pipeline - all three render the same two workflow files.

Build Workflow

.github/workflows/build.yaml, shown as rendered for a project named billing-service:

name: Build

on:
push:
branches: ["**"]
pull_request:

permissions:
contents: write
id-token: write

env:
IMAGE_NAME: billing-service
APPLICATION_NAME: billing-service

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: p6m-actions/java-maven-setup@v1

- name: Cut Patch Version
if: github.ref_name == 'main'
id: cut-patch
uses: p6m-actions/java-maven-cut-tag@v1
with:
version-level: patch

- name: Build
uses: p6m-actions/java-maven-build@v1
with:
run-test: "false"
build-command: "mvn verify --no-transfer-progress"

# ... shared container build, release and dispatch steps

Step Chain

#StepScopeRuns on
1CheckoutSharedAlways
2Maven setupJavaAlways
3Cut Patch VersionJavamain
4BuildJavaAlways
5Login to Artifactory Container RegistrySharedmain
6Set up Docker BuildxSharedAlways
7Build and Publish Docker ImageSharedAlways
8Make ArtifactsSharedmain
9Create Github releaseSharedmain
10Update Application ManifestSharedmain

Java is the only language that disables the build action's separate test phase, folding tests into a single mvn verify instead.

Language-Specific Steps

Maven Setup

- uses: p6m-actions/java-maven-setup@v1

p6m-actions/java-maven-setup installs a JDK and warms the Maven dependency cache.

InputDefaultPassed by the workflow
java-version21(default)
java-distributiontemurin(default)
maven-version(unset)(default) - uses the Maven wrapper or the preinstalled Maven
cachetrue(default) - caches ~/.m2
install-dependenciestrue(default) - resolves dependencies after setup
maven-cache-key-suffix(unset)(default)
OutputDescription
java-versionThe installed JDK version
maven-versionThe installed Maven version
cache-hitWhether the Maven cache was restored
maven-cache-dirPath to the Maven cache directory

Cut Patch Version

- name: Cut Patch Version
if: github.ref_name == 'main'
id: cut-patch
uses: p6m-actions/java-maven-cut-tag@v1
with:
version-level: patch

p6m-actions/java-maven-cut-tag bumps the version with mvn versions:set, commits every pom.xml it touched, and creates an annotated tag.

InputRequiredValue
version-levelNopatch in build.yaml; the dispatch input in cut-tag.yaml
OutputDescription
versionThe new version, e.g. 1.4.2
tagThe created tag

Internally the action:

  1. Runs p6m-actions/token-exchange@v2 for a P6M App installation token, git identity, and the [skip ci] commit hook.
  2. Fails fast if the computed tag already exists.
  3. Runs mvn versions:set -DnewVersion=<v> -DgenerateBackupPoms=false.
  4. Stages the parent pom.xml and every module pom.xml outside target/, so a multi-module archetype project bumps as a unit.
  5. Commits, tags, and pushes both.
Multi-module projects bump together

The archetype renders a parent POM plus -bom, -core, -server, -integration-tests and, with persistence enabled, -persistence modules. The cut-tag action stages all of their POMs, so the whole reactor stays on one version.

Build

- name: Build
uses: p6m-actions/java-maven-build@v1
with:
run-test: "false"
build-command: "mvn verify --no-transfer-progress"

p6m-actions/java-maven-build runs lint, test, build, and package phases, each individually toggleable.

InputDefaultValue in the workflow
run-linttrue(default) - mvn checkstyle:check
run-testtrue"false" (explicit)
test-commandmvn testnot used, tests are disabled
run-buildtrue(default)
build-commandmvn compilemvn verify --no-transfer-progress (explicit)
run-packagefalse(default)
maven-options-B -q(default)
archive-coveragefalse(default) - JaCoCo reports under target/site/jacoco are not uploaded

Outputs: none.

The two overrides work together. Replacing mvn compile with mvn verify makes the build phase run the full lifecycle - compile, Surefire unit tests, package, and Failsafe integration tests - in one reactor pass. The separate test phase is then redundant, so run-test is turned off to avoid compiling and testing twice. --no-transfer-progress suppresses per-artifact download noise in the log.

Checkstyle is skipped unless configured

run-lint defaults to true, but the action guards it: when lint-command mentions checkstyle it first greps pom.xml for maven-checkstyle-plugin. If the plugin is not configured - which is the case for a freshly generated project - it logs "Skipping linting" and moves on. Adding the plugin to your POM is what turns the gate on.

Cut Tag Workflow

.github/workflows/cut-tag.yaml:

name: Cut Tag

on:
workflow_dispatch:
inputs:
version-level:
description: "Version bump level"
required: true
default: "patch"
type: choice
options:
- patch
- minor
- major

permissions:
id-token: write
contents: write

jobs:
cut-tag:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- uses: p6m-actions/java-maven-setup@v1

- uses: p6m-actions/java-maven-cut-tag@v1
with:
version-level: ${{ inputs.version-level }}
Inputversion-level - patch, minor, or major
OutputsA [skip ci] version bump commit across the POMs and an annotated tag, both pushed

Version File

The parent pom.xml is the source of truth:

<project>
<groupId>com.example.payments</groupId>
<artifactId>billing-service</artifactId>
<version>1.4.2</version>
</project>