This repository is the central publication point for the Nabu Maven ecosystem.
It is responsible for two things:
- ingesting released module artifacts from the individual module repositories
- publishing central Maven BOMs that describe the released ecosystem state
The current flow is intentionally incremental. Only modules that have actually been released and ingested into GitHub Packages appear with concrete versions in the published BOM.
Contains the source catalogs:
core.xmlmodules.xml
These are still the authoritative lists of known core artifacts and modules.
This repository contains:
- GitHub Actions workflows that publish
core-bom,modules-bom, and theprojectsparent POM - scripts that ingest module release assets into GitHub Packages
- the
modules-state.jsonsidecar file - a small explicit allowlist for hybrid module-side build plugins
This repository is also the GitHub Packages Maven host:
https://maven.pkg.github.com/nabu-platform/maven
Example:
nabu-platform/nabu-types-structure
Each module repository is responsible for:
- building its own artifact from a tag
- signing it in GitHub Actions
- creating a GitHub Release with the
.narattached
The module repository does not publish directly into the central Maven package registry.
That is done centrally by nabu-platform/maven.
The end-to-end flow for a module is:
- A module repository gets a release tag
- The module workflow builds the tagged version
- The workflow signs the produced artifact
- The workflow creates a GitHub Release and uploads the
.nar - The central
mavenworkflow is run manually - The central workflow downloads release assets that are not yet in GitHub Packages
- The central workflow publishes those assets into
nabu-platform/maven - The central workflow regenerates the BOM from the actually published package versions
- The central workflow publishes the new BOM and parent artifacts
In short:
- tags create released module assets
- the central workflow ingests them into packages
- the central workflow updates the BOM to match
Module release workflows trigger on tags that match:
v*
The leading v is stripped and the remainder becomes the Maven artifact version.
Example:
- tag:
v1.13-SNAPSHOT.20260616130811 - published artifact version:
1.13-SNAPSHOT.20260616130811
The version after v is not otherwise interpreted. It only needs to be a Maven-safe version string.
Example implementation:
nabu/types/structure/.github/workflows/release.yml
That workflow does the following:
- checks out the module source
- checks out
nabu-platform/poms - installs
poms/modules.xmlas the parent POM into the runner-local Maven repository - derives the release version from the tag
- runs
mvn versions:setto align the Maven project version with the tag - decodes the signing keystore from GitHub Actions secrets
- builds and signs the artifact
- renames the produced
.jarpayload to.nar - creates a GitHub Release and uploads the
.nar
Important details:
- module repositories build from their own tagged commit
- the release asset is the
.nar - the
.narremains self-describing because it contains Maven metadata underMETA-INF/maven/...
GitHub Actions GITHUB_TOKEN cannot reliably publish packages into another repository's Maven registry.
Because of that, the chosen model is:
- module repos write releases only to their own repository
- the
mavenrepo reads those releases and publishes into its own package registry
This avoids cross-repo package write problems while keeping a single central Maven endpoint.
Main workflow:
.github/workflows/publish-modules-bom.yml
It performs four stages:
- Check out this repository and
nabu-platform/poms - Publish released module assets into GitHub Packages
- Generate and publish
modules-bom - Generate and publish the
projectsparent POM
Both the BOM and the parent are published twice:
- as a floating development alias (
1.0-SNAPSHOT) - as a concrete timestamped release version (for example
1.0-SNAPSHOT.20260622135330)
Script:
.github/scripts/publish_module_releases.py
It reads the managed module list from:
poms/modules.xml
It can also include a small explicit allowlist passed by workflow arguments for hybrid artifacts that are published with the module ecosystem but are not sourced from the full modules catalog.
For each managed dependency, it:
- maps Maven coordinates to a GitHub repository name
- checks the latest GitHub Release in that repository
- skips the module if there is no release
- skips the module if the version is already present in GitHub Packages
- downloads the
.narasset if needed - extracts
groupId,artifactId, andversionfrom embeddedpom.properties - verifies that the embedded coordinates match the expected release tag version
- publishes the
.narinto GitHub Packages usingmvn deploy:deploy-file
Repository mapping rule:
- repository name =
groupIdwith.replaced by-, then-, thenartifactId
Examples:
nabu.types:structure->nabu-types-structurenabu.frameworks:tasks->nabu-frameworks-tasksnabu:maven-plugin-install->nabu-maven-plugin-install
The current explicit allowlist is intentionally small and hardcoded in the workflow:
nabu:maven-plugin-install:jarnabu:maven-plugin-environment:jar
These plugin artifacts are published through the modules workflow, but they are no longer added to the generated modules-bom. Their versions are instead written into the generated be.nabu:projects parent POM.
Published package example:
nabu.types:structure:1.13-SNAPSHOT.20260616130811:nar
Script:
.github/scripts/generate_bom.py
It reads the managed dependency list from:
poms/modules.xmlorpoms/core.xml
It can also add a small explicit allowlist for hybrid artifacts that should appear in the published BOM without importing a much larger source catalog.
For each entry, it:
- queries GitHub Packages for published versions
- selects the newest published version by package timestamp metadata
- substitutes that concrete version into the generated BOM
- leaves the source version untouched if nothing was published yet
Published BOM examples:
- floating development alias:
be.nabu:modules-bom:1.0-SNAPSHOT - concrete release:
be.nabu:modules-bom:1.0-SNAPSHOT.20260622135330
Published parent examples:
- floating development alias:
be.nabu:projects:1.0-SNAPSHOT - concrete release:
be.nabu:projects:1.0-SNAPSHOT.20260622135330
The floating alias stays on 1.0-SNAPSHOT, while the concrete release is published with a timestamped version. In both cases the managed dependency entries inside the BOM are updated to concrete released package versions.
The generated parent imports modules-bom and carries pluginManagement for the Nabu Maven plugins.
The published parent is intentionally called projects, not modules, to avoid colliding with the existing local be.nabu:modules parent used in local module-development workflows.
During bootstrap, the BOM is intentionally mixed:
- released modules appear with concrete versions
- unreleased modules still retain the source catalog version expression or snapshot value from
poms/modules.xml
Example of a released entry:
<dependency>
<groupId>nabu.types</groupId>
<artifactId>structure</artifactId>
<version>1.13-SNAPSHOT.20260616130811</version>
</dependency>This means the central BOM gradually becomes more concrete as more modules are released and ingested.
File:
modules-state.json
Purpose:
- track lifecycle state per managed module without modifying the source catalog structure
Current rules:
- if a module is first seen by the central scripts, an entry is added automatically as
active - existing entries are not modified automatically
- if a module is marked
retired, the central scripts:- no longer check its releases
- no longer include it in the generated BOM
Current file shape:
{
"nabu.types:structure": "active",
"nabu.old:legacy": "retired"
}This allows future cleanup without deleting history from poms/modules.xml.
Module release workflows sign artifacts in GitHub Actions before creating the GitHub Release.
The current setup uses a GitHub-specific signing identity so CI-built artifacts are distinguishable from locally signed artifacts.
Signing material is stored as GitHub organization secrets and shared only with the selected repositories.
Expected secret names:
SIGN_KEYSTORE_BASE64SIGN_KEYSTORE_PASSWORDSIGN_KEY_ALIASSIGN_KEY_PASSWORD
The working setup uses a classic JKS keystore, not PKCS12. That was chosen because the older Maven jarsigner plugin setup behaved reliably with JKS and failed opaquely with PKCS12.
The module workflow:
- decodes the Base64 keystore into a temporary file on the runner
- passes the following Maven properties:
sign.keystoresign.storetype=JKSsign.aliassign.storepasssign.keypass
The actual signing behavior comes from the shared maven-jarsigner-plugin configuration in poms/modules.xml.
The central maven workflows publish into their own repository package registry.
To make Maven authenticate reliably, the workflows create an explicit Maven settings.xml:
<settings>
<servers>
<server>
<id>github</id>
<username>${env.GITHUB_ACTOR}</username>
<password>${env.GITHUB_TOKEN}</password>
</server>
</servers>
</settings>The workflows then publish using:
-DrepositoryId=github-Durl=https://maven.pkg.github.com/nabu-platform/maven
This avoids ambiguity in setup-java server injection.
There are two intended ways to consume the published ecosystem.
Use the floating parent or BOM version:
be.nabu:projects:1.0-SNAPSHOTbe.nabu:modules-bom:1.0-SNAPSHOT
This means:
- you want the latest published ecosystem state
- the resolved content can move as new releases are ingested centrally
- local Maven caches can keep older snapshot metadata or artifacts
Because of that, development consumers should refresh snapshots explicitly:
mvn -U process-resourcesUse -U whenever you want Maven to re-check the central GitHub Packages endpoint for newer snapshot metadata.
Use the concrete timestamped parent or BOM version:
be.nabu:projects:1.0-SNAPSHOT.20260622135330be.nabu:modules-bom:1.0-SNAPSHOT.20260622135330
This means:
- you want one fixed ecosystem definition
- all dependency and plugin versions are frozen to that published point in time
- no moving snapshot alias is involved
This is the recommended mode for:
- qlty
- acceptance
- production
- any reproducible deployment pipeline
A typical workflow is:
- use
1.0-SNAPSHOTduring normal development while iterating quickly - run Maven with
-Uwhen you want to pick up the latest centrally published changes - once a set is validated, switch to the concrete timestamped parent version for stabilized environments
The generated artifacts have different responsibilities:
modules-bom- manages dependency versions for Nabu module artifacts
- does not manage Maven plugin versions
projectsparent- imports
modules-bom - manages the Nabu Maven plugin versions through
pluginManagement - activates
maven-plugin-installby default
- imports
This means module-builder projects normally only need one thing:
- inherit
be.nabu:projects
That gives them:
- dependency versions via the imported BOM
- plugin versions via the parent POM
- default execution of the dependency install plugin
- Commit and push the module workflow if needed
- Create a tag like:
v1.13-SNAPSHOT.20260616130811
- Push the tag
- Wait for the module workflow to produce a signed
.narGitHub Release asset
- Go to
nabu-platform/maven - Run workflow:
Publish Modules BOM
- This will:
- import missing module releases into GitHub Packages
- regenerate and publish a concrete
modules-bomandprojectsparent version - regenerate and publish the floating
1.0-SNAPSHOTaliases for both
- Go to
nabu-platform/maven - Run workflow:
Publish Core BOM
Working today:
- module release tagging
- GitHub Release asset creation for modules
- GitHub CI signing with org secrets
- central release asset ingestion into GitHub Packages
- central
modules-bompublication - central package-state sidecar with retirement support
Known current limitation:
- the published BOM is still based on the full source catalog from
poms/modules.xml - only the versions of released modules are concretized automatically
- unreleased modules remain present with source-catalog version expressions or snapshot values
Likely next improvements:
- make the published bootstrap BOM fully incremental if desired
- add the same release flow to more modules
- bring
coreartifacts into the same central publication flow - optionally add explicit reporting for deprecated modules alongside
retired
The implemented model is:
- module repositories own source builds and release assets
- the
mavenrepository owns central package publication and BOM publication pomsremains the source catalog of known artifactsmodules-state.jsonlets the central system remember lifecycle state without rewriting the source catalog
This gives a phased migration path from local snapshot-based development to a centrally published Maven ecosystem without breaking existing local workflows.