Apply plugin inside a plugin

Hello,

I have recently created a simple plugin that interfaces with GitVersion.
It can be found here:

https://plugins.gradle.org/plugin/com.bisiach.gradle.gitversion-plugin

Now I am creating a new plugin that should incorporate the above plugin and force some of the configuration elements on the project where the plug-in is applied to.

I have the basic code for my groovy based plugin, like this

package com.bisiach.gradle;

import org.gradle.api.Plugin;
import org.gradle.api.Project;

class CustomPlugin implements Plugin<Project> {
	@Override
	def void apply(Project project) {
		
	}
}

Inside def void apply(Project project) i should apply the above mentioned plugin to the project object. I can’t figure out the syntax to use.

Any suggestion?

Thanks

I have tried the following:

class CustomPlugin implements Plugin<Project> {
	@Override
	def void apply(Project project) {
		project.buildscript.dependencies.add("classpath","gradle.plugin.com.bisiach.gradle.gitversion-plugin:gradle-gitversion-plugin:1.0.2");
		project.getPluginManager().apply("com.bisiach.gradle.gitversion-plugin");
	}
}

but when the consumer uses this plugin it raises an error

FAILURE: Build failed with an exception.
Where:
Build file '/Users/andreas/eclipse-workspace/tester/build.gradle' line: 12

* What went wrong:
An exception occurred applying plugin request [id: 'com.bisiach.gradle.custom-plugin', version: '1.0.0']
> Failed to apply plugin [id 'com.bisiach.gradle.custom-plugin']
   > Cannot change dependencies of configuration ':classpath' after it has been resolved.

I have found the solution so I post it here for reference:

  1. in the gradle.build of the custom plugin:

    dependencies {
    runtime ‘gradle.plugin.com.bisiach.gradle.gitversion-plugin:gradle-gitversion-plugin:1.0.2’
    }

  2. In the plugin class

    package com.bisiach.gradle;

    import org.gradle.api.Plugin;
    import org.gradle.api.Project;

    class CustomPlugin implements Plugin {
    @Override
    def void apply(Project project) {
    project.getPluginManager().apply(“com.bisiach.gradle.gitversion-plugin”)
    project.version = project.GitVersion.SemVer
    }
    }

Hey thanks for sharing that! You’re quick :slight_smile: I was just about to reply with something I found in the User Guide:

Would you mind trying that approach? And sharing whether or not that also works? Thanks.

Thanks a lot for the link to guide!

Unfortunately I discovered the neither my approach or the one in the guide work.
I will use the terminology in the guide to be more clear.
In my scenario the Base Plugin (the capability plugin) is published public here:

https://plugins.gradle.org/plugin/com.bisiach.gradle.gitversion-plugin

On the other hand, the “convention” plugin will be published privately to a company maven repo. The plugin named i.e: com.acme.gradle.standard-development-plugin.
The idea is that this plug-in will be applied to all customer projects using gradle.init.

During develompent, to test com.acme.gradle.standard-development-plugin I am using composite build.
I have a project “test” that includes the build of com.acme.gradle.standard-development-plugin. In this scenario, adding the following to build.gradle of com.acme.gradle.standard-development-plugin worked. but only because in a composite build, the project “test” can see the runtime dependency:

dependencies {
runtime ‘gradle.plugin.com.bisiach.gradle.gitversion-plugin:gradle-gitversion-plugin:1.0.2’
}

After publishing my com.acme.gradle.standard-development-plugin to an internal maven repo, and including in the project “test” as a normal plugin, the plug in fails to apply the base (capability) plugin com.bisiach.gradle.gitversion-plugin.

The examples outlined in the guide always shoes capability and convention plugins coming from the same gradle build. That is why it works there I think.
I need to achieve the same between 2 plugins coming from 2 different builds/repositories

Bummer :frowning:

Here’s what I think are the actual implementations of the two plugins the User Guide refers to:

And this other one that’s also extended by the Java Plugin:

They’re in three different subprojects. Is Gradle’s structure similar to what you described for your projects.

Reading the Gradle plugin source, it all flew right over my head. I’m not even going to pretend I understand any of it Hah-hah!

But the Gradle source might give you some leads on how you might proceed.

I’m going to need to do that myself soon. What have you figured out so far? Got any pointers to share yet?

Why don’t you work with detached configs?


Conceptually I think i grasp what you mean. But I could really need a little bite more hint.
I guess that instead of

	project.buildscript.dependencies.add("classpath","gradle.plugin.com.bisiach.gradle.gitversion-plugin:gradle-gitversion-plugin:1.0.2");
	project.getPluginManager().apply("com.bisiach.gradle.gitversion-plugin");

I should do something like :

def d = dependencies.create(group: project.group, name: project.name, version: '+')
def c = configurations.detachedConfiguration(d).setTransitive(false)

I cannot see how this will help me load the com.bisiach.gradle.gitversion-plugin in the custom plug-in.
Could you point me in the right direction?

I mistook problem.

To get read of:

dependencies {
   runtime ‘gradle.plugin.com.bisiach.gradle.gitversion-plugin:gradle-gitversion-plugin:1.0.2’
}

or:

project.buildscript.dependencies.add("classpath","gradle.plugin.com.bisiach.gradle.gitversion-plugin:gradle-gitversion-plugin:1.0.2");

you need to declare transitive dependency in your plug-in because build script classpath cannot be altered programmatically.

Then I believe below will work:

project.getPluginManager().apply("com.bisiach.gradle.gitversion-plugin");

@andreasb70, I see that something similar to what @gavenkoa suggests is done in the two links I shared previously:

    ...
	
    @Override
    public void apply(Project project) {
        project.getPluginManager().apply(ComponentModelBasePlugin.class);
        project.getPluginManager().apply(JvmResourcesPlugin.class);
    }
	...
    ...
	
    @Override
    public void apply(Project project) {
        project.getPluginManager().apply(LanguageBasePlugin.class);
        project.getPluginManager().apply(BinaryBasePlugin.class);
    }
    ...	

There’s a good chance something like that could work, if you hadn’t tried it yet.

Please let us know if it does or not? Thanks.

EDIT: Actually, I see that you have tried something similar before…

Have you tried it with the class literal (.class) of the plugin you want to apply? Like it’s done in the Gradle source links? Instead of the plugin’s id string?

1 Like

Did anyone end up getting this working? I’m also trying to get this working but have had issues (the plugins are actually in completely different repos that I’m trying to incorporate)

The Issue with the above mentioned solutions is that they declared the dependency in the plugins build.gradle file as runtime. That’s why you can not apply the Plugin class (as it is missing in the compile classpath). Just change the dependency to implementation.

I don’t think that any lazy configuration will help here as one usually wants to interact with the other plugins datastructures and therefor you’ll need access to the classes on the compileClasspath and runtimeClasspath what the implementation configuration is meant for.

//build.gradle
repositories.pluginPortal()
dependencies {
    implementation ‘gradle.plugin.com.bisiach.gradle.gitversion-plugin:gradle-gitversion-plugin:1.0.2’
}
public class NewPlugin implements Plugin<Project> {
    public void apply(Project project) {
        project.getPlugins().apply(GitVersionPlugin.class);
        // customize...
    }
}

I am using this extensively with gradles internal plugins as well as externals like sonarqube or test-sets.