Skip to content

Give the POMs of plugin publications the license and SCM of the project - #766

Merged
alexander-yevsyukov merged 7 commits into
masterfrom
worktree-plugin-pom-metadata
Sep 24, 2026
Merged

alexander-yevsyukov merged 7 commits into
masterfrom
worktree-plugin-pom-metadata

Conversation

@alexander-yevsyukov

Copy link
Copy Markdown
Contributor

What changed

  • CustomPublicationHandler now reaches Maven publications with configureEach instead of an eager forEach. Publications added after the handler is applied — pluginMaven and the plugin markers of java-gradle-plugin — now get the project attributes too.
  • PublicationHandler.copyProjectAttributes() is split: the inception year, license, and SCM move to copyProjectWideAttributes(). Plugin markers get only these; their coordinates, name, and description stay those of the plugin.
  • isPluginMarker moves to PublishingExts.kt as internal, shared with the SBOM code from Publish an SPDX SBOM with each Maven publication #764, which carried its own private copy.
  • New Gradle TestKit test: CustomPublicationHandlerIgTest.

Why

Found while adding SBOM generation (#762, #764): the SPDX Gradle Plugin reads licenses from dependency POMs, and every Spine Gradle plugin artifact showed up as NOASSERTION. Their POMs have no <licenses>, <scm>, or <inceptionYear> — for example validation-gradle-plugin:2.0.0-SNAPSHOT.464, time-gradle-plugin:2.0.0-SNAPSHOT.251, compiler-gradle-plugin:2.0.0-SNAPSHOT.069, and root-gradle-plugins, protobuf-setup-plugins, jvm-tool-plugins at 2.0.0-SNAPSHOT.423.

Root cause. SpinePublishing applies the handler in afterEvaluate of the module. For a module listed in modulesWithCustomPublishing, the root script adds that action before the module applies java-gradle-plugin, which creates pluginMaven and the markers in an afterEvaluate action of its own. The eager forEach saw neither. The published artifacts show it: in protobuf-setup-plugins, the fatJar publication (protobuf-setup-plugins-all), created earlier, has all three sections, while pluginMaven has none.

A second, latent bug. When a module opens spinePublishing { customPublishing = true } itself after applying java-gradle-plugin, the loop ran after the markers existed and replaced their groupId with the project group, which breaks resolving the plugin by its ID.

Tests

CustomPublicationHandlerIgTest builds a fixture with a standard module and a java-gradle-plugin module, and compares the pluginMaven and marker POMs with the standard POM for three declarations: in the root project, in the module, and in both. The last is how tool-base declares protobuf-setup-plugins and jvm-tool-plugins via uber-jar-module.

  • Before the fix, 3 of the 4 root and module cases failed: an unprefixed artifactId, and a marker groupId of io.spine.tools.
  • With the handler's applied guard disabled, the IN_BOTH case fails with two licenses, so applying the attributes twice is caught as well.
  • ./gradlew :buildSrc:build detekt on JDK 17: all 118 tests pass.

Notes for reviewers

  • pluginMaven now also gets its coordinates from the handler, as its KDoc always stated. The values match what validation, time, compiler, tool-base, and ProtoTap set by hand, so their workarounds become redundant but stay harmless.
  • The gradle-plugin module of core-jvm-compiler strips the marker's plugin dependency only when it is named gradle-plugin. After it pulls this change, its marker would list core-jvm-gradle-plugin twice (same GAV) until that workaround is updated; this is tracked separately.
  • POMs of standard publications have no <name>, <url>, or <developers> either, so none are added here. Adding them would change every published POM.
  • The branch also adds the task plan .agents/tasks/plugin-pom-metadata.md and a team memory, plugin-publications-created-late, each in its own commit so the memory can be reviewed on its own.

🤖 Generated with Claude Code

alexander-yevsyukov and others added 7 commits September 24, 2026 18:08
`CustomPublicationHandler` copied the project attributes to the publications
present when it was applied, in `afterEvaluate` of the module. For a module
listed in `modulesWithCustomPublishing`, that action is added by the root
project, so it runs before `java-gradle-plugin` creates `pluginMaven` and
the plugin markers in an `afterEvaluate` action of its own. Their POMs went
out without `<licenses>`, `<scm>`, and `<inceptionYear>` — SBOMs of the
consumers report such a plugin as `NOASSERTION` — while a `fatJar` of the
same module, created earlier, got all three. Where the handler ran after
`java-gradle-plugin` instead, it replaced the `groupId` of the markers with
the project group, which breaks resolving a plugin by its ID.

The handler now reaches the publications with `configureEach`, so those
added later get the same treatment. A plugin marker gets only the attributes
describing the project as a whole, which move from `copyProjectAttributes()`
to `copyProjectWideAttributes()`; its coordinates, name, and description stay
those of the plugin. `isPluginMarker` moves to `PublishingExts.kt`, to be
shared with the SBOM code.

`CustomPublicationHandlerIgTest` compares the POMs with those of a standard
publication for a module declared by the root project, by the module itself,
and by both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Records the evidence from the published POMs, the root cause, and the
follow-ups left out of the fix: the marker workaround in `core-jvm-compiler`,
the snapshot check of `PublicationChecksums`, and the destinations that
`SpinePublishing.publishTo()` fails to inherit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Publishing code in `buildSrc` runs in `afterEvaluate`, often before
`java-gradle-plugin` adds `pluginMaven` and the plugin markers. The memory
records why such code must reach publications with `configureEach` and must
leave the identity of a marker to the plugin it points to.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The test names its modules and publications through constants, reusing
`StandardJavaPublicationHandler.PUBLICATION_NAME` for the standard one.
Restrictive clauses use "that", sentences no longer open with a lowercase
identifier, and the marker test states that the identity of a marker must
not be replaced, which the previous wording left ambiguous.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Applies the rest of the documentation review to the task plan and the team
memory: such sentences start with a word instead, and the third declaration
of the test is named by its constant, `IN_BOTH`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-24T17:25:12.816396Z 4e95044 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@alexander-yevsyukov
alexander-yevsyukov merged commit ad9cad5 into master Sep 24, 2026
3 checks passed
@alexander-yevsyukov
alexander-yevsyukov deleted the worktree-plugin-pom-metadata branch September 24, 2026 17:37
@github-project-automation github-project-automation Bot moved this from In Review to ✅ Done in v2.0 Sep 24, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

Only minor documentation nits remain; no blocking issues were identified.

Review effort: Lite
Findings: 1 Low severity

Open (1)
What changed in this PR

Updates Maven publication handling so late-created Gradle plugin publications receive project metadata while preserving marker coordinates.

Changes:

  • Uses lazy configuration for late publications.
  • Separates shared POM metadata from publication coordinates.
  • Adds marker detection reuse and Gradle TestKit coverage.
File Summary
buildSrc/​src/​test/​kotlin/​io/​spine/​gradle/​publish/​CustomPublicationHandlerIgTest.kt Tests plugin and marker POM metadata and identities.
buildSrc/​src/​main/​kotlin/​io/​spine/​gradle/​publish/​PublishingExts.kt Centralizes plugin-marker detection.
buildSrc/​src/​main/​kotlin/​io/​spine/​gradle/​publish/​PublicationSbom.kt Reuses shared marker detection.
buildSrc/​src/​main/​kotlin/​io/​spine/​gradle/​publish/​PublicationHandler.kt Separates project-wide POM metadata handling.
buildSrc/​src/​main/​kotlin/​io/​spine/​gradle/​publish/​CustomPublicationHandler.kt Configures existing and late publications.
.agents/​tasks/​plugin-pom-metadata.md Documents the implementation plan and verification.
.agents/​memory/​project/​plugin-publications-created-late.md Records publication lifecycle guidance.
.agents/​memory/​MEMORY.md Indexes the new project memory.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

3 participants