Skip to content

Migrate multi-project aggregation to an explicit aggregator setup #848

Description

@skhokhlov

Summary

Move from the current "apply at root, implicitly aggregate all subprojects" model to an explicit, opt-in aggregator model modeled on Gradle's test-report-aggregation / jacoco-report-aggregation plugins. This is the concrete refactor that unblocks Project Isolation (#847) and is a breaking change warranting a major version bump.

Current model

Today the plugin is applied once at the root. The root discovers all subprojects, configures a Direct BOM task on each, and the aggregate task implicitly includes every subproject. Membership is automatic and the wiring is centralized on the root.

Target model

  • Per-project application. Each project that should contribute to an aggregate applies the plugin itself and publishes its own Direct BOM as a consumable variant.
  • Explicit aggregation membership. The aggregating project declares which projects to include, e.g. dependencies { cyclonedxAggregation project(":app-a") }, mirroring jacocoAggregation / testReportAggregation. The aggregator resolves these members and merges their BOMs. No auto-discovery, no silent inclusion.
  • Loud failure. If a declared member is not wired correctly, or its BOM is missing or unparseable, the aggregate task fails — it does not silently drop the member. Silent under-reporting of an SBOM (a security-consumed, public-contract artifact) is worse than a hard failure.

What changes for users

  • Applying the plugin only at the root no longer aggregates subprojects. Each contributing project must apply the plugin, and the aggregator must declare its members. This is the deliberate, documented break.
  • The "aggregate the whole tree with zero per-project wiring" experience moves to a user-side concern: a CI init script can apply the plugin across all projects and declare every subproject as a member generically. That script uses cross-project iteration and therefore runs only with Project Isolation disabled, which is acceptable for that use case.

Why not keep it implicit

Implicit, root-driven membership requires the root to read its subprojects at configuration time — the exact cross-project access Project Isolation forbids. Explicit membership is the only model that is both Isolation-safe and configuration-cache-safe, and it makes the contents of an aggregate BOM auditable rather than magical.

Work items

  • Move per-project Direct BOM publishing into each project's own application path.
  • Add the resolvable cyclonedxAggregation configuration and member-declaration API.
  • Aggregate task: resolve declared members, merge, and own the root→member edges.
  • Hard failure on missing/unparseable/unwired members.
  • Update README/wiki to the per-project model + a migration guide.
  • Document the init-script (Isolation-off) pattern for whole-tree aggregation.
  • Major version bump.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions