Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Isolation in multi-project build #81

Open
flelli opened this issue Mar 20, 2021 · 10 comments
Open

Isolation in multi-project build #81

flelli opened this issue Mar 20, 2021 · 10 comments

Comments

@flelli
Copy link

flelli commented Mar 20, 2021

Hi,

I have a polyglot multi-project build where sub projects are isolated by technology. Say I have 2 subprojects:

  • modules:go
  • modules:java

The reason I do this is also because I want the tools and plugins to be isolated. With the former 2 plugins I had them applied only in the modules:java along with Maven, the publishing, etc but the new one fails to apply if not declared in the root project:

`Failed to apply plugin 'io.github.gradle-nexus.publish-plugin'.

Plugin must be applied to the root project but was applied to :modules:java`

Moving the plugin to the root project also implies declaring all the publishing etc in the root project and that would mess up all the configurations I have, basically giving up on isolation.

Is there a way to keep the new plugin in a sub-project?

@marcphilipp
Copy link
Member

Moving the plugin to the root project also implies declaring all the publishing etc in the root project and that would mess up all the configurations I have, basically giving up on isolation.

That's not entirely true. You only need to configure nexusPublishing in the root project but can continue declaring your publications in modules:java.

Is there a way to keep the new plugin in a sub-project?

I'm afraid not. The alternative to a root project plugin would be to convert it into a settings plugin but that wouldn't achieve isolation, either.

@flelli
Copy link
Author

flelli commented Mar 22, 2021

Thanks Marc for your prompt reply,

The point is if I move nexusPublishing only, the build breaks as it can't find any Maven publications defined. So I have to move them as well, which will likely need the signing to be moved too, ending up with moving it all.

Moving the plugin to the root project also implies declaring all the publishing etc in the root project and that would mess up all the configurations I have, basically giving up on isolation.

That's not entirely true. You only need to configure nexusPublishing in the root project but can continue declaring your publications in modules:java.

@marcphilipp
Copy link
Member

@flelli It shouldn't break without any defined publications. Could you please create a reproducer project?

@flelli
Copy link
Author

flelli commented Mar 23, 2021

Sure. In my project I created two additional branches:

  • demo/ok: with the current configuration, using the former 2 separate plugins isolated in the modules/java/build.gradle
  • demo/ko: with the new plugin in the root project

As soon as I run Gradle using the plugin in the root project, I get:

> Could not find method publishing() for arguments [build_3ihi3zopyxie2mmev6s23q6n5$_run_closure1$_closure3@7619cca7] on root project 'nyx' of type org.gradle.api.Project.

As you can see in the modules/java/build.gradle, publishing is statically defined for the modules/java project but also as a closure on its (further) child projects

@vlsi
Copy link
Contributor

vlsi commented Apr 26, 2021

The root project only requirement breaks Gradle's precompiled script plugins :-/

> Task :build-logic:root-build:generatePrecompiledScriptPluginAccessors
Failed to generate type-safe Gradle model accessors for the following precompiled script plugins:
 - src/main/kotlin/allure-gradle.build-logic.root-build.gradle.kts

org.gradle.internal.exceptions.LocationAwareException: Precompiled script plugin '/Users/vlsi/Documents/code/allure-gradle/build-logic/root-build/src/main/kotlin/allure-gradle.build-logic.root-build.gradle.kts' line: 1
An exception occurred applying plugin request [id: 'io.github.gradle-nexus.publish-plugin']
        at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.applyPlugin(DefaultPluginRequestApplicator.java:183)
        at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.lambda$applyPlugins$1(DefaultPluginRequestApplicator.java:125)
        at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
        at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.applyPlugins(DefaultPluginRequestApplicator.java:125)
        at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.applyPlugins(DefaultPluginRequestApplicator.java:121)
        at org.gradle.kotlin.dsl.provider.plugins.precompiled.tasks.SyntheticProjectSchemaBuilder.applyPluginsTo(GeneratePrecompiledScriptPluginAccessors.kt:446)
        at org.gradle.kotlin.dsl.provider.plugins.precompiled.tasks.SyntheticProjectSchemaBuilder.childProjectWith(GeneratePrecompiledScriptPluginAccessors.kt:388)
        at org.gradle.kotlin.dsl.provider.plugins.precompiled.tasks.SyntheticProjectSchemaBuilder.schemaFor(GeneratePrecompiledScriptPluginAccessors.kt:374)
        at org.gradle.kotlin.dsl.provider.plugins.precompiled.tasks.GeneratePrecompiledScriptPluginAccessors.projectSchemaImpliedByPluginGroups(GeneratePrecompiledScriptPluginAccessors.kt:296)
        at org.gradle.kotlin.dsl.provider.plugins.precompiled.tasks.GeneratePrecompiledScriptPluginAccessors.generateTypeSafeAccessorsFor(GeneratePrecompiledScriptPluginAccessors.kt:158)
        at org.gradle.kotlin.dsl.provider.plugins.precompiled.tasks.GeneratePrecompiledScriptPluginAccessors.generate(GeneratePrecompiledScriptPluginAccessors.kt:139)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
...
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
        at java.lang.Thread.run(Thread.java:748)
Caused by: org.gradle.api.plugins.InvalidPluginException: An exception occurred applying plugin request [id: 'io.github.gradle-nexus.publish-plugin']
        at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.exceptionOccurred(DefaultPluginRequestApplicator.java:198)
        at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.applyPlugin(DefaultPluginRequestApplicator.java:180)
        ... 141 more
Caused by: org.gradle.api.internal.plugins.PluginApplicationException: Failed to apply plugin 'io.github.gradle-nexus.publish-plugin'.
        at org.gradle.api.internal.plugins.DefaultPluginManager.doApply(DefaultPluginManager.java:163)
        at org.gradle.api.internal.plugins.DefaultPluginManager.apply(DefaultPluginManager.java:127)
        at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.lambda$applyPlugins$0(DefaultPluginRequestApplicator.java:127)
        at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.applyPlugin(DefaultPluginRequestApplicator.java:176)
        ... 141 more
Caused by: java.lang.IllegalArgumentException: Plugin must be applied to the root project but was applied to :test
        at io.github.gradlenexus.publishplugin.NexusPublishPlugin.apply(NexusPublishPlugin.kt:48)
        at io.github.gradlenexus.publishplugin.NexusPublishPlugin.apply(NexusPublishPlugin.kt:40)
        at org.gradle.api.internal.plugins.ImperativeOnlyPluginTarget.applyImperative(ImperativeOnlyPluginTarget.java:43)
        at org.gradle.api.internal.plugins.RuleBasedPluginTarget.applyImperative(RuleBasedPluginTarget.java:51)
        at org.gradle.api.internal.plugins.DefaultPluginManager.addPlugin(DefaultPluginManager.java:177)
        at org.gradle.api.internal.plugins.DefaultPluginManager.access$100(DefaultPluginManager.java:51)
        at org.gradle.api.internal.plugins.DefaultPluginManager$AddPluginBuildOperation.run(DefaultPluginManager.java:272)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:71)
        at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:71)
        at org.gradle.api.internal.plugins.DefaultPluginManager.lambda$doApply$0(DefaultPluginManager.java:157)
        at org.gradle.configuration.internal.DefaultUserCodeApplicationContext.apply(DefaultUserCodeApplicationContext.java:43)
        at org.gradle.api.internal.plugins.DefaultPluginManager.doApply(DefaultPluginManager.java:156)
        ... 144 more

@JavierSegoviaCordoba
Copy link
Contributor

This probably break the future Gradle project isolation support, right?

What if the plugin must be applied to each project?

@sureshg
Copy link

sureshg commented Mar 7, 2023

@vlsi hi, could you able to find any workaround for pre-compiled script plugins (organized as part of build-logic)? I ended up using something like this

if (project == rootProject) {
  apply(plugin = "io.github.gradle-nexus.publish-plugin")
}

@mauritssilvis
Copy link

Like @flelli, I bumped into the following problem:

An exception occurred applying plugin request [id: 'io.github.gradle-nexus.publish-plugin', version: '1.3.0']
> Failed to apply plugin 'io.github.gradle-nexus.publish-plugin'.
   > Plugin must be applied to the root project but was applied to :other-project

This problem occurred when I had two projects I wanted to publish independently using the Gradle nexus publish plugin. One project depended on the other, though: it was a multi-build project through the setting include("other-project") and the dependency implementation(project(":other-project")).

Following @sureshg's suggestion, I found two workarounds for the above problem:

  • Conditionally apply and configure the plugin in the other project.
  • Replace the multi-build project with a composite build.

For future reference, I'll post both (most likely imperfect but functioning) workarounds below.

Conditional plugin application

Main project

settings.gradle.kts:

// Include the other project as a project
include("other-project")
project(":other-project").projectDir = file("path/to/other/project")

build.gradle.kts:

plugins {
    id("io.github.gradle-nexus.publish-plugin") version "1.3.0"
}

dependencies {
    // Reference the other project
    implementation(project(":other-project"))
}

nexusPublishing {
    repositories {
        // ...
    }
}

Other project

build.gradle.kts:

plugins {
    // Do not apply the plugin
    id("io.github.gradle-nexus.publish-plugin") version "1.3.0" apply false
}

// Conditionally apply and configure the plugin
if (project == rootProject) {
    apply(plugin = "io.github.gradle-nexus.publish-plugin")

    configure<io.github.gradlenexus.publishplugin.NexusPublishExtension> {
        repositories {
            // ...
        }
    }
}

Composite build

Main project

settings.gradle.kts:

// Include the other project as a build
includeBuild("path/to/other/project")

build.gradle.kts:

plugins {
    id("io.github.gradle-nexus.publish-plugin") version "1.3.0"
}

dependencies {
    // Reference the other project using its project coordinates
    implementation("<other project group>:<other project name>:<other project version>")
}

nexusPublishing {
    repositories {
        // ...
    }
}

Other project

build.gradle.kts:

plugins {
    id("io.github.gradle-nexus.publish-plugin") version "1.3.0"
}

nexusPublishing {
    repositories {
        // ...
    }
}

@Vampire
Copy link
Contributor

Vampire commented Nov 22, 2023

@marcphilipp would you mind listing the actual reasons why the plugin has to be a root or settings plugin?
Just to make it clear why this is the case, and for the case that someone wants to come up with a PR that maybe changes this.
The afterEvaluate { allprojects { ... } } is a double-bad-practice anyway and is better replaced by something different anyway. :-D

@marcphilipp
Copy link
Member

I originally made it a root project plugin so there's a single place to configure Nexus repositories that are shared across subprojects. While each subproject has an "init" task, they use a resource attached to the project to synchronize on to ensure a shared staging repo is created. This could probably be changed to create a checksum of the repo config or require some kind of identifier and a BuildService but I lack the time to give it a try.

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

No branches or pull requests

7 participants