Skip to content

Add incremental build context API and implementation - #12576

Draft
gnodet wants to merge 1 commit into
feature/12571-build-reportfrom
move-the-incremental-build-context-api-in-pr-1118
Draft

Add incremental build context API and implementation#12576
gnodet wants to merge 1 commit into
feature/12571-build-reportfrom
move-the-incremental-build-context-api-in-pr-1118

Conversation

@gnodet

@gnodet gnodet commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Port and modernize the incremental build context from PR #1118, building on the original Sonatype plexus-build-api / Takari incrementalbuild work. This gives mojo authors a first-class API for incremental builds — tracking which input files changed, managing input→output associations, skipping unnecessary work, and cleaning up stale outputs automatically.

Stacked on top of #12572 (Build Report Foundation). Diagnostic messages are handled by DiagnosticReporter from #12572, not by this API — clean separation of concerns per @laeubi's feedback.

Companion PRs demonstrate the API with four core plugins:

Closes #1118.

What's in this PR

Public API (maven-api-core) — 14 types in 2 packages

org.apache.maven.api.build.context — mojo-facing API:

Type Role
BuildContext Main entry point — register inputs/outputs, check status, associate files
Input / Output Tracked input and output resources with status
InputSet Aggregation support (many inputs → one output, e.g., JAR, index)
Metadata<R> Lazy status inspection before committing to process
Resource Base for Input/Output — path, status
Status Change status enum: NEW, MODIFIED, UNMODIFIED, REMOVED
@Incremental Annotation for mojo fields — marks config parameters for change detection
BuildContextException Runtime exception (extends MavenException)

org.apache.maven.api.build.context.spi — integration SPI:

Type Role
Workspace Filesystem abstraction with 3 modes (NORMAL, ESCALATED, SUPPRESSED)
CommittableBuildContext Extended BuildContext with commit() for state persistence
BuildContextEnvironment Construction parameters (state file, workspace, config, finalizer)
BuildContextFinalizer Batch-commits all contexts after mojo success
FileState Immutable value object for file metadata

Not in this API (handled by #12572): diagnostic messages, severity levels, message sinks. Mojos should use DiagnosticReporter for structured diagnostics.

Implementation (maven-impl) — 12 classes + 8 test classes (36 tests)

Core incremental build engine in o.a.m.internal.build.context.impl.

Maven integration (maven-core) — 5 classes

DI wiring, configuration digesting, post-mojo commit finalization, maven.buildcontext.skip property.

Performance

Benchmarked against stock 3.x plugins on a 20-module reactor (4000 sources, 600 resources):

Scenario 3.x Plugins BuildContext Plugins Change
Clean build 23.4s 32.6s +39% (one-time cost)
No-op rebuild 15.7s 8.7s −44%
Leaf module change 14.8s 8.9s −40%
Mid-chain change 12.1s 8.7s −28%
Delete + stale cleanup 30.3s 15.7s −48%

-Dmaven.buildcontext.skip=true disables the context entirely for CI/release builds.

Key design decisions

  1. No diagnostic messages in this APIDiagnosticReporter from Build report, console modes, and warning control #12572 handles diagnostics. A future bridge PR will replay previous-build diagnostics for unchanged files so warning counts stay consistent across incremental builds.

  2. No DELTA workspace mode — per @laeubi's feedback from plexus-build-api experience, IDE-driven delta detection is unreliable. Maven does its own timestamp scan (NORMAL mode). IDE integration focuses on output notification (newOutputStream), not input detection.

  3. Automatic config change detection — digests all @Parameter fields and plugin classpath. Mojos get this for free.

  4. maven.buildcontext.skip — disables digesting, state persistence, and tracking entirely. Zero overhead for CI clean builds.

Test plan

  • 36 build context tests passing in maven-impl
  • Integration test: MavenITgh12576IncrementalBuildContextTest
  • A/B benchmark: patched plugins vs stock 3.x across 5 scenarios
  • CI build passes

🤖 Generated with Claude Code

@gnodet
gnodet force-pushed the move-the-incremental-build-context-api-in-pr-1118 branch from e5a76c1 to 1e02718 Compare July 28, 2026 21:53
@gnodet gnodet mentioned this pull request Jul 28, 2026
@gnodet gnodet changed the title Move build context API to o.a.m.api.build.context Add incremental build context API and implementation (supersedes #1118) Jul 28, 2026
@gnodet gnodet changed the title Add incremental build context API and implementation (supersedes #1118) Add incremental build context API and implementation Jul 29, 2026
@gnodet gnodet added this to the 4.1.0 milestone Jul 30, 2026
@kwin

kwin commented Aug 3, 2026

Copy link
Copy Markdown
Member

Plexus Build API also provides context aware (file, line) logging. Would be good to add here as well

Update: Seems this is part of resource now and therefore already considered.

@laeubi

laeubi commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Plexus Build API also provides context aware (file, line) logging. Would be good to add here as well

Update: Seems this is part of resource now and therefore already considered.

Just one note from experience with https://github.com/codehaus-plexus/plexus-build-api:

  1. Please don't call it BuildContext this is just ambiguous and confusing (e.g. it has nothing to do with maven build that maven plugins usually work with - see also Provide a new Resources API codehaus-plexus/plexus-build-api#76) and is hardly implementable as it mixes different concerns. Instead I have tried to reworked it (still wip) into small, self-contained semantic APIs e.g. messages-api, progress-api and resources-api (and more are on the pipeline e.g process-api
  2. Don't focus too much on that part "IDE will detect changes" - this has not worked out well and often failed (see especially the clarification of hasDelta(Path file) - Check if file has changes (documented as "best effort" hint) in PR. An IDE has mostly the same problems as maven that it can not prevent files from changing externally (e.g. git branch, user deletes stuff, external process (maven included) and so on. So most of this should be implementable at maven itself without any help of the IDE, what is only interesting is the part about a mojo is informing about things it changed (so family of refresh / newOutputStream) or copy / move - one new thing will be markDerived (useful for code generator mojos
  3. The most valuable one could do for the IDE from a mojo is adding messages (see above) that give context of errors / warning that otherwise is hidden in the build logs.

@gnodet

gnodet commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @kwin and @laeubi for the feedback. I spent time going through the plexus-build-api rework and the referenced issues — very useful context.

On naming / separation of concerns (@laeubi point 1)

Agreed that the old plexus-build-api BuildContext was too broad. This API is already narrower — it's specifically about incremental input/output tracking (register inputs, detect changes, associate outputs, clean stale files). It doesn't do progress reporting or general context storage.

That said, the diagnostic message part (Resource.addMessage() / Sink / Message) does overlap with #12572's DiagnosticCollector / BuildReport API, which already handles structured diagnostics with dedup, warning modes, and persistence. I'm open to stripping the message types from this PR and letting #12572 handle diagnostics entirely — that would make this API purely about incremental file tracking, which is one coherent concern.

On the name itself: BuildContext has recognition from the Sonatype/Takari lineage, but I see the ambiguity point. Alternatives like IncrementalContext would be more precise. Open to suggestions.

On IDE delta detection (@laeubi point 2)

Fully agree — the implementation doesn't rely on IDE-driven deltas for correctness. NORMAL mode (the CLI default) does full filesystem scan with timestamp/size comparison. The DELTA workspace mode in the SPI is opt-in for IDEs as a performance hint, not a correctness requirement.

Good point about markDerived() — we don't have that in the current SPI but it would be valuable for code generators. Worth adding.

On messages (@laeubi point 3, @kwin)

As noted above, the context-aware message API (Resource.addMessage(line, column, ...)) overlaps with #12572. The one unique capability here is cross-build message persistence — re-reporting errors from previous builds for unchanged files. Whether that's worth the additional API surface or is better handled at a higher level (build report) is a question I'd like input on.

@gnodet
gnodet changed the base branch from master to feature/12571-build-report August 4, 2026 11:07
@gnodet
gnodet force-pushed the move-the-incremental-build-context-api-in-pr-1118 branch from 1ac5eb0 to dfd8d5c Compare August 4, 2026 11:07
Port and modernize the incremental build context from PR #1118,
building on the original Sonatype plexus-build-api / Takari
incrementalbuild work.

API (maven-api-core):
- BuildContext: register inputs, check status, associate
  outputs, skip execution, automatic stale output cleanup
- SPI: Workspace (NORMAL/ESCALATED/SUPPRESSED),
  CommittableBuildContext, BuildContextEnvironment,
  BuildContextFinalizer
- Diagnostic messages are NOT part of this API — use
  DiagnosticReporter from the build report API instead

Implementation (maven-impl):
- DefaultBuildContext with timestamp/size change detection
- State serialization for cross-build persistence
- PathMatcherFactory integration for Ant-style patterns
- 36 tests

Maven integration (maven-core):
- MojoExecutionScoped DI wiring
- ClasspathDigester + MojoConfigurationDigester for automatic
  configuration change detection
- MavenBuildContextFinalizer for post-mojo commit
- maven.buildcontext.skip property to disable entirely
- Performance: released-artifact digest bypass, no-op state skip,
  single-syscall file status, field reflection cache

Based on #12572 (Build Report Foundation).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gnodet
gnodet force-pushed the move-the-incremental-build-context-api-in-pr-1118 branch from dfd8d5c to 7d3165e Compare August 4, 2026 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants