Maven build operations — compile, test, verify with JaCoCo coverage and multi-module profile management
Resources
2Install
npx skillscat add cuioss/plan-marshall/build-maven Install via the SkillsCat registry.
Build Maven
Maven build execution with output parsing, module discovery, and wrapper detection. Wrapper resolution prefers the project wrapper (mvnw) and falls back to the system mvn when no checked-in wrapper is present. See `build-api-reference.md` § Wrapper Detection for the detection table.
Enforcement
See build-api-reference.md § Enforcement for shared rules.
All commands use python3 .plan/execute-script.py plan-marshall:build-maven:maven {command} {args}.
Scripts
| Script | Purpose |
|---|---|
maven.py |
CLI dispatcher |
_maven_execute.py |
Execution config via factory (uses shared default_command_key_fn) |
_maven_cmd_discover.py |
Module discovery via pom.xml + Maven metadata commands |
_maven_cmd_parse.py |
Log parsing with JVM base patterns + Maven-specific extensions |
_maven_cmd_rewrite_log.py |
Additive OpenRewrite #118 log-parse consumption (Signal B) via the rewrite-log-parse domain verb, fail-closed |
Subcommands
Supports: run, parse, coverage-report, check-warnings, discover, rewrite-log.
See build-api-reference.md for the full subcommand API and availability matrix.
Maven-Specific Behavior
- run:
--command-argstakes Maven goals/options, e.g.,"verify -Ppre-commit -pl my-module" - parse: Additional
no-openrewritemode filters OpenRewrite markers - coverage-report: Searches
target/site/jacoco/jacoco.xml,target/jacoco/report.xml,target/site/jacoco-aggregate/jacoco.xml - discover: Subprocess-free — parses each
pom.xmlwith stdlib XML for coordinates, packaging, and declared profile ids, and walks the filesystem for sources/tests. Resolved coordinates, inherited profiles, and the resolved dependency tree are filled lazily, one module at a time, byenrich_maven_module(which runsdependency:tree,help:all-profiles) only when a consumer — the dependency graph or the resolver's profile-canonical path — needs them.
Producer-Side Finding Storage (run --plan-id)
When run is invoked with --plan-id <P>, every parsed issue from a failed build is auto-stored via the producer path (always-on). Without --plan-id, the build parses and formats only (no finding storage). The maven-specific issue→finding-type routing is:
Parsed category (Issue) |
Finding type |
|---|---|
test_failure, test_* |
test-failure |
categories containing lint or style |
lint-issue |
| everything else (compilation, dependency, plugin, surefire/failsafe) | build-error |
Severity is mapped from Issue.severity (error → error, warning → warning). The finding's module carries maven, rule carries the parser category.
For the producer→store→consumer→gate flow including the producer-mismatch fidelity contract, see `ref-workflow-architecture/standards/findings-pipeline.md`. This SKILL.md owns the per-tool issue→finding-type routing only.
Additive OpenRewrite log-parse consumption (rewrite-log)
The rewrite-log subcommand consumes Signal B of the two-signal OpenRewrite model — the cui-open-rewrite #118 structured WARN lines in the captured Maven build log — additively, alongside (never replacing) the existing openrewrite_info categorization and issue routing. build-maven does NOT parse the WARN format itself: the format is owned by the domain bundle, and core reaches it only through the rewrite-log-parse domain verb, resolved null-on-absent. See `../extension-api/standards/ext-point-domain-verb.md` § Declaration for the resolution/dispatch contract (not re-copied here).
The consumption is fail-closed (ADR-009) — it never reports a vacuous "clean". Four distinct verdicts:
| Verdict | Condition | Meaning |
|---|---|---|
observed |
The build reached rewrite:run AND an active domain provides the verb AND the dispatched parser succeeded |
The domain parser was dispatched against the log; structured findings (path, line, column, recipe, message, newly-detected vs pre-existing) are surfaced. |
not_observed |
The build never reached rewrite:run (e.g. a compile failure before the OpenRewrite goal) |
Absence-of-evidence is a distinct third state, never a false clean — the findings were simply not produced this run. |
domain_inactive |
The build reached rewrite:run but no active domain provides the rewrite-log-parse verb (e.g. a non-java-cui project) |
A first-class skip via null-on-absent resolution, not a false clean. |
parse_error |
The build reached rewrite:run and the verb resolves, but the dispatched parser returned an error payload (executor not found, output unparseable / not an object) or a non-dict |
Findings could not be observed this run — fail closed rather than report a false observed with zero findings. |
The existing Maven parse pipeline, the openrewrite_info categorization, and the tree-scan marker signal (marker-detect) are unchanged by this additive consumer.
Module Discovery
Reads pom.xml <modules> declarations from the parent POM.
Profile Processing Pipeline
- Filter to command-line activated profiles (
Active: false) - Apply skip list from configuration (
build.maven.profiles.skip) - Map to canonical command names (
build.maven.profiles.map.canonical)
Discover as the canonical source for integration-tests / e2e
discover is the authoritative source for the integration-tests and e2e test targets consumed at end-of-phase-5 whole-tree verification. These canonicals are not separate plugins or hard-coded goals — they are Maven profiles that discover surfaces from each pom.xml's declared profile ids (and, lazily, the inherited profiles enrich_maven_module resolves via help:all-profiles). The Profile Processing Pipeline above maps those discovered profiles to canonical command names (build.maven.profiles.map.canonical), so a project's integration-tests / e2e canonical resolves iff discover found the backing Maven profile. On a project that declares no such profile, the canonical does not resolve and the end-of-phase-5 step records skipped rather than failing.
Whole-tree gates such as integration-tests and e2e live only in the verification_steps end-of-phase-5 sweep, never in the module-scoped per-deliverable build. The phase-5-execute canonical-verify step reads the canonical from its default:verify:{canonical} step ID and resolves it through architecture resolve --command {canonical}, which consults this discover-derived profile-to-canonical mapping. For the exact step-invocation shape — how the parameterized canonical-verify step invokes the resolved integration-tests target, honours its execution_tier / bash_timeout_seconds, and reports pass/skip/fail — see the central standard at `../phase-5-execute/standards/canonical_verify.md` (do NOT inline-copy the invocation shape here).
Module-edge derivation (Axis-C derivation resolver)
extension.py's BuildExtension subclasses both BuildExtensionBase (Axis-B, the file-to-build map above) and DerivationResolverBase (Axis-C, module-edge derivation), so this skill also answers which modules depend on which for the graph / path / neighbors / impact query family and the adjacency surfaces of overview and module / info.
The resolver id is maven. Its derivation is the coordinate join: each module publishes a groupId:artifactId in its metadata, each module names its dependencies as groupId:artifactId:scope strings, and an edge exists wherever a dependency coordinate matches another module's published coordinate (matched on the first two colon-separated parts, so the scope segment is ignored). This join previously lived inline in manage-architecture; it belongs here because the coordinate contract is Maven domain knowledge, and core owns the merge, the provenance, and the traversal rather than the derivation.
Two behaviours are worth naming because they are contract obligations rather than implementation detail:
- An ambiguous coordinate yields no edge and a reported collision. When two distinct modules claim the same
groupId:artifactId, the resolver emits no edge for that coordinate and reports it innotes[]. A last-write-wins pick would silently drop one module and every edge pointing at it, with the survivor decided by map iteration order. - The enriched overlay is not consulted. The precedence of a curated or discovered
internal_dependenciesdeclaration over a derived edge set is core's ruling, applied ahead of the resolver call.
The contract itself — the four faces, the N-resolver union semantics, the anti-vacuity provenance property, and the generic ambiguous-identity-key obligation that binds every resolver — is owned by `../extension-api/standards/ext-point-derivation-resolver.md` and is deliberately not restated here.
Canonical invocations
The canonical argparse surface for maven.py. The plugin-doctor analyzer (_analyze_manage_invocation.py) reads this section as source-of-truth for the manage-invocation-invalid and missing-canonical-block rules. Consuming docs xref this section by name instead of restating the command inline. See `pm-plugin-development:plugin-script-architecture` cross-skill-integration.md § "Script invocation in documentation".
run
python3 .plan/execute-script.py plan-marshall:build-maven:maven run \
--command-args COMMAND_ARGS \
[--timeout SECONDS] [--mode {actionable,structured,errors}] [--format {toon,json}] \
(--project-dir PROJECT_DIR | --plan-id PLAN_ID)--project-dir and --plan-id are mutually exclusive.
parse
python3 .plan/execute-script.py plan-marshall:build-maven:maven parse \
--log LOG \
[--mode {default,errors,structured,no-openrewrite}] [--format {toon,json}] \
(--project-dir PROJECT_DIR | --plan-id PLAN_ID)coverage-report
python3 .plan/execute-script.py plan-marshall:build-maven:maven coverage-report \
[--project-path PROJECT_PATH] [--report-path REPORT_PATH] [--threshold PERCENT] \
(--project-dir PROJECT_DIR | --plan-id PLAN_ID)check-warnings
python3 .plan/execute-script.py plan-marshall:build-maven:maven check-warnings \
[--warnings WARNINGS] [--acceptable-warnings ACCEPTABLE_WARNINGS] \
(--project-dir PROJECT_DIR | --plan-id PLAN_ID)discover
python3 .plan/execute-script.py plan-marshall:build-maven:maven discover \
[--root ROOT] [--format {toon,json}]rewrite-log
python3 .plan/execute-script.py plan-marshall:build-maven:maven rewrite-log \
--log LOG [--format {toon,json}]Consumes the OpenRewrite #118 log-parse signal from a captured build log, fail-closed. Returns a rewrite_log.verdict of observed / not_observed / domain_inactive / parse_error (see § "Additive OpenRewrite log-parse consumption").
run-config-key
python3 .plan/execute-script.py plan-marshall:build-maven:maven run-config-key \
--command-args COMMAND_ARGS [--format {toon,json}]References
build-api-reference.md— Shared subcommand API, error categories, issue routing, wrapper detectionbuild-execution.md— Execution contract and lifecyclestandards/maven-impl.md— Maven-specific execution and configuration detailspm-dev-java:java-maintenance/standards/pom-maintenance.md— POM structure standards