Skip to content

fix(build-logic): guard skip_shadow_publish variant-order race#34

Merged
THEROER merged 1 commit into
mainfrom
fix/publish-skip-shadow-order
Jul 6, 2026
Merged

fix(build-logic): guard skip_shadow_publish variant-order race#34
THEROER merged 1 commit into
mainfrom
fix/publish-skip-shadow-order

Conversation

@THEROER

@THEROER THEROER commented Jul 6, 2026

Copy link
Copy Markdown
Owner

The real cause of the 1.23.0 publish-maven failures (my earlier afterEvaluate-on-from fix targeted the wrong call).

publish-maven.yml runs with -Pskip_shadow_publish=true, which triggers the block in MagicUtilsPublishingPlugin that calls java.withVariantsFromConfiguration(shadowRuntimeElements) { skip() } to keep the fat :all jar out of production publishing. That call throws:

Variant for configuration 'shadowRuntimeElements' does not exist in component 'java'. For a given configuration, 'addVariantsFromConfiguration' must be called before 'withVariantsFromConfiguration'.

…whenever the shadow plugin has not yet registered the variant. The shadow plugin registers it from its own afterEvaluate; CI's injected Develocity plugin (via setup-gradle) reorders the hooks so ours runs first. Modules without real shading (:processor) never register the variant at all. Reproduces locally only with -Pskip_shadow_publish=true, which is why it slipped past earlier checks.

Fix: gate the skip on plugins.withId("com.gradleup.shadow") and wrap it in runCatching. Shaded modules still drop :all (verified: config's module metadata loses shadowRuntimeElements under the flag); plain modules no longer fail. Full publishCommonMatrix publishFabricMatrix -Pskip_shadow_publish=true now configures cleanly.

Summary by Sourcery

Guard shadow variant skipping during Maven publishing to avoid configuration-time failures in CI when the shadow variant is not present.

Enhancements:

  • Restrict skip_shadow_publish handling to projects applying the shadow plugin so modules without shading no longer attempt to skip a missing variant.
  • Wrap shadow variant skipping in a safe call to avoid crashes when the variant ordering differs in CI.
  • Simplify Java component binding for Maven publication by configuring it directly instead of via afterEvaluate.

publish-maven runs with -Pskip_shadow_publish=true, which calls
java.withVariantsFromConfiguration(shadowRuntimeElements) to hide the :all
variant. That throws "Variant for configuration 'shadowRuntimeElements' does
not exist in component 'java'" when the shadow plugin has not yet registered
the variant — the ordering of its afterEvaluate hook vs. ours is reordered by
CI's injected Develocity plugin, and modules without real shading (:processor)
never register the variant at all. Gate the skip on plugins.withId("com.gradleup.shadow")
and wrap it in runCatching, so shaded modules still drop their :all variant
(verified: config's module metadata loses shadowRuntimeElements) while plain
modules no longer fail. Reproduces locally only with -Pskip_shadow_publish=true.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@sourcery-ai

sourcery-ai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

This PR hardens the Gradle publishing logic for shadowed artifacts by making the skip-shadow behavior conditional on the shadow plugin being applied and by removing an unnecessary afterEvaluate wrapper around the java component binding for the non-shadow publication path.

Sequence diagram for guarded skip_shadow_publish handling in MagicUtilsPublishingPlugin

sequenceDiagram
    actor Developer
    participant Project
    participant MagicUtilsPublishingPlugin
    participant ShadowPlugin
    participant JavaComponent
    participant ShadowRuntimeElementsConfiguration

    Developer->>Project: run publish with -Pskip_shadow_publish
    Project->>MagicUtilsPublishingPlugin: apply

    MagicUtilsPublishingPlugin->>Project: plugins.withId(com.gradleup.shadow)
    Project-->>ShadowPlugin: apply

    ShadowPlugin->>Project: afterEvaluate_register_shadowRuntimeElements
    Project->>JavaComponent: addVariantsFromConfiguration(ShadowRuntimeElementsConfiguration)

    Project->>MagicUtilsPublishingPlugin: afterEvaluate
    alt skip_shadow_publish and shadow variant present
        MagicUtilsPublishingPlugin->>JavaComponent: withVariantsFromConfiguration(ShadowRuntimeElementsConfiguration) skip
        JavaComponent-->>MagicUtilsPublishingPlugin: runCatching result
    else no_shadow_plugin_or_no_variant
        MagicUtilsPublishingPlugin-->>Project: [no skip executed]
    end

    MagicUtilsPublishingPlugin->>Project: publication.from(Project.components.getByName(java))
Loading

File-Level Changes

Change Details Files
Guard skip-shadow variant manipulation so it only runs when the shadow plugin is applied and fails safely if the variant is missing.
  • Wrap the skip-shadow behavior in a plugins.withId("com.gradleup.shadow") block to ensure it only executes when the shadow plugin is present.
  • Keep the configuration of skip_shadow_publish inside project.afterEvaluate but only after the shadow plugin has had a chance to register its variant.
  • Wrap the call to withVariantsFromConfiguration in runCatching to prevent configuration failures if the shadowRuntimeElements variant is unexpectedly absent.
build-logic/src/main/kotlin/dev/ua/theroer/magicutils/build/publish/MagicUtilsPublishingPlugin.kt
Simplify the standard java publication setup by binding the java component eagerly instead of in an afterEvaluate block.
  • Remove the afterEvaluate wrapper around publication.from(project.components.getByName("java")) for the non-shadow publish path.
  • Rely on the java component being available at publication configuration time rather than deferring it to afterEvaluate.
build-logic/src/main/kotlin/dev/ua/theroer/magicutils/build/publish/MagicUtilsPublishingPlugin.kt

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot 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.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="build-logic/src/main/kotlin/dev/ua/theroer/magicutils/build/publish/MagicUtilsPublishingPlugin.kt" line_range="27-36" />
<code_context>
         if (project.hasProperty("skip_shadow_publish")) {
-            project.afterEvaluate {
-                (project.components.findByName("java") as? AdhocComponentWithVariants)?.let { java ->
-                    project.configurations.findByName("shadowRuntimeElements")?.let { shadow ->
-                        java.withVariantsFromConfiguration(shadow) { it.skip() }
+            project.plugins.withId("com.gradleup.shadow") {
+                project.afterEvaluate {
+                    (project.components.findByName("java") as? AdhocComponentWithVariants)?.let { java ->
+                        project.configurations.findByName("shadowRuntimeElements")?.let { shadow ->
+                            runCatching { java.withVariantsFromConfiguration(shadow) { it.skip() } }
+                        }
                     }
</code_context>
<issue_to_address>
**issue (bug_risk):** Avoid silently swallowing failures from `withVariantsFromConfiguration`.

Wrapping `withVariantsFromConfiguration` in `runCatching` without handling `onFailure` or the result hides any misconfiguration or runtime error and could silently break publishing. Consider either allowing the exception to propagate or explicitly handling/logging failures so configuration problems are visible in CI/output.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +27 to +36
// guaranteed — and CI's injected plugins (Develocity via setup-gradle)
// reorder it so ours runs first, which failed every publish. Modules
// without real shading (e.g. :processor) never register the variant at all,
// so there is simply nothing to skip. Guard the call: only skip when the
// variant is actually present on the component.
if (project.hasProperty("skip_shadow_publish")) {
project.afterEvaluate {
(project.components.findByName("java") as? AdhocComponentWithVariants)?.let { java ->
project.configurations.findByName("shadowRuntimeElements")?.let { shadow ->
java.withVariantsFromConfiguration(shadow) { it.skip() }
project.plugins.withId("com.gradleup.shadow") {
project.afterEvaluate {
(project.components.findByName("java") as? AdhocComponentWithVariants)?.let { java ->
project.configurations.findByName("shadowRuntimeElements")?.let { shadow ->

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.

issue (bug_risk): Avoid silently swallowing failures from withVariantsFromConfiguration.

Wrapping withVariantsFromConfiguration in runCatching without handling onFailure or the result hides any misconfiguration or runtime error and could silently break publishing. Consider either allowing the exception to propagate or explicitly handling/logging failures so configuration problems are visible in CI/output.

@THEROER THEROER merged commit 7e5ce4c into main Jul 6, 2026
8 checks passed
@THEROER THEROER deleted the fix/publish-skip-shadow-order branch July 10, 2026 02:19
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.

1 participant