Skip to content
BETAGuardrails are in beta. The library, the configuration format and the CLI command can still change.

Guardrails / Collectors

Maven build

The Maven build in the project directory: the root pom.xml coordinates, its modules, its properties and every dependency it and its modules declare, with the versions its imported BOMs supply.

Facts keymaven
Versionv1
Scriptmaven.py
Timeout30 seconds

Inputs

InputDescriptionDefaultEnvironment
projectDirDirectory holding the project, relative to the directory the CLI runs in..GUARDRAIL_INPUT_PROJECTDIR

A guardrail that declares an input of the same name passes it through, so the guardrail's configuration in buildnote.json is what decides these values.

A guardrail asks for these facts by name, and reads them back the same way:

json
{
  "collect": ["maven"]
}
python
maven = guardrail.facts("maven")

Facts

The document maven collects. A path carrying [] is an entry of the list before it, and one carrying [path] is a key of the object before it.

FactMeaning
directoryThe project directory the guardrail configured with projectDir, from the directory the CLI runs in. Every path this collector states is stated from there too, so a path it names resolves from where the CLI was invoked rather than from the directory it happened to run in.
existsWhether that directory is there. Nothing else is collected when it is not, and the collector collects nothing at all when the directory holds no pom.xml.
pomThe project's pom.xml, from the directory the CLI runs in, or null when there is none.
rootDirectory holding the POM this one names as its <parent>, from the directory the CLI runs in, or null when the POM declares no parent, resolves it from the repository with an empty <relativePath>, or has none above it. It is never looked for above the directory the CLI runs in, so a module checked on its own inherits the properties, managed versions and imported BOMs of its parent rather than resolving none of them. Nothing else of the parent is collected: coordinates, modules and the dependencies stay the ones of directory.
sourcesThe build files that were there to read, from the directory the CLI runs in, followed by the POM in root when there is one.
malformedWhether the POM could not be parsed. The coordinates, properties and modules keep their defaults when it is true, and the fact is absent when there is no POM at all.
coordinates.groupIdGroup id, inherited from the parent when the POM declares none.
coordinates.artifactIdArtifact id.
coordinates.versionVersion, inherited from the parent when the POM declares none.
coordinates.packagingPackaging, jar when the POM declares none.
propertiesEvery entry under <properties>, by name, with the ones the POM in root declares underneath the project's own.
modulesEvery module the POM declares.
modules[].pathModule directory, from the directory the CLI runs in.
modules[].pomThe module's POM path when it is there, null when it is not.
modules[].coordinatesThe module's own coordinates, shaped as above, or null when its POM could not be read.
dependenciesEvery dependency the root POM and every module POM that is checked in takes on, inside a <profile> or out of one, split by whether a POM declares it. A plain <dependencyManagement> entry is a managed version rather than a dependency, so it is not one, and a dependency a module inherits from its parent is listed against the POM declaring it rather than against both.
dependencies.directEvery dependency a POM declares, the root POM first, together with every BOM they import.
dependencies.direct[].pathgroup:name of the dependency.
dependencies.direct[].versionVersion, filled in from <dependencyManagement> when the dependency declares none, taken from an imported BOM when nothing manages it, and resolved through the properties in scope. null when nothing resolves one.
dependencies.direct[].scopesThe scope declared, compile when the POM declares none and import for a BOM. One entry, because a POM declares a dependency once.
dependencies.direct[].sourcePOM declaring it, from the directory the CLI runs in.
dependencies.direct[].profilePresent only when a <profile> declares it, and then that profile's id. Whether the profile activates is not something the POM alone says.
dependencies.direct[].platformPresent and true only when it is a <dependencyManagement> entry imported with <scope>import</scope>, meaning it is a BOM supplying versions rather than code.
dependencies.direct[].managedByPresent only when the version came from an imported BOM, and then that BOM's group:name:version. A version <dependencyManagement> supplies in the same build carries no managedBy, because the POM states it. The BOM is not in the repository, so it is never read: it is matched to a dependency by group, most specific first, and the version taken is the BOM's own. Treat a version carrying a managedBy as a hint rather than a fact. It is wrong wherever the BOM does not publish one version line for the whole group, and it is set even on a coordinate the BOM never lists but whose group happens to sit under it. A BOM the root POM imports supplies versions to every module, one a module imports only to that module, and one the POM in root imports supplies them to projectDir and to every module of it.
dependencies.transitiveAlways empty. A Maven build checks in no resolved dependency graph, so nothing but the declared dependencies is visible without running Maven.

A collector that cannot finish prints what it had along with an incomplete key saying why, so the facts below the point it stopped are absent. A check that cares reads incomplete before the rest.

Example facts

The example facts collected by maven collector:

json
{
  "directory": ".",
  "exists": true,
  "pom": "pom.xml",
  "sources": [
    "pom.xml"
  ],
  "modules": [
    {
      "path": "service",
      "pom": "service/pom.xml",
      "coordinates": {
        "groupId": "com.acme",
        "artifactId": "widget-service",
        "version": "1.1.0",
        "packaging": "jar"
      }
    }
  ],
  "properties": {
    "kotlin.version": "2.1.0",
    "maven.compiler.release": "21"
  },
  "coordinates": {
    "groupId": "com.acme",
    "artifactId": "widget",
    "version": "1.1.0",
    "packaging": "pom"
  },
  "dependencies": {
    "direct": [
      {
        "path": "org.junit:junit-bom",
        "version": "6.0.3",
        "scopes": [
          "import"
        ],
        "source": "pom.xml",
        "platform": true
      },
      {
        "path": "com.google.guava:guava",
        "version": "33.2.0-jre",
        "scopes": [
          "compile"
        ],
        "source": "service/pom.xml"
      },
      {
        "path": "org.jetbrains.kotlin:kotlin-stdlib",
        "version": "2.1.0",
        "scopes": [
          "compile"
        ],
        "source": "service/pom.xml"
      },
      {
        "path": "org.junit.jupiter:junit-jupiter",
        "version": "6.0.3",
        "scopes": [
          "test"
        ],
        "source": "service/pom.xml",
        "managedBy": "org.junit:junit-bom:6.0.3"
      }
    ],
    "transitive": []
  },
  "root": null,
  "malformed": false
}

Collected for

GuardrailCategoryInputs
kotlin/build-manifestkotlinprojectDir
maven/coordinates-declaredmavenprojectDir
maven/dependencies-versionedmavenprojectDir
maven/no-snapshot-dependenciesmavenprojectDir
maven/pom-parsesmavenprojectDir

All collectors

Buildnote Limited
Registered in England and Wales, Reg: 16140412