Applying a settings plugin centrally

Hi,
I have a settings plugin to manage VersionCatalogs using the api.

plugins {
    id("dev.aga.gradle.version-catalog-generator") version "2.1.2"
}

I would like to apply this settings plugin to all projects in my company. So that I would like to apply it via
init.gradle.kts

I tried some solutions on the internet but could not achieve it. So finally end up here.

Is it possible to apply the plugin via init.gradle.kts ?

Sure, just do it.
What did you try and what problems did you have with it?

well, I tried to add repositories and classpath for the plugin in initScript block of init.gradle.kts and then tried to apply the plugin in allProjects block like below.

apply(plugin = “com.github.jk1.dependency-license-report”)

But then I am having gradle error.

> Error resolving plugin [id: ‘dev.aga.gradle.version-catalog-generator’, version: ‘2.1.2’]

> Plugin with id ‘com.github.jk1.dependency-license-report’ not found.

First of all, this tingles me like why/what would the version-catalog-generator do with another plugin.
could be something related to a bug in their code. used with their latest version but still no luck.

I am kinda stucked (due to my lack of knowledge too)

Second, is there any other way without initScript block ? since that block does not let me use variables from outside context. I am totally lost :frowning:

Why would you use allProjects?
You said you want to apply a settings plugin, not a project plugin.
So you need to use for example beforeSettings { ... }.
And you cannot apply by ID, but you need to apply by class.
The classes added to the initscript block are not available on the classpath of the settings script or project scripts, so the plugin cannot be found by ID.
So apply<VersionCatalogGeneratorPlugin>() is what you want to do to apply it.

Sorry for confusion I created, the next step will be to apply some other plugins company wide like license check etc.. but obv, I am missing the apply by class stuff. Will update the status.

thanks.

So here is the update;

beforeSettings {
    apply<dev.aga.gradle.versioncatalogs.VersionCatalogGeneratorPlugin>()
}

Result : expectedly “Unresolved reference: dev
This is from init.gradle.kts

initscript {
    >>>> Although I already defined below definition and extension above at the beginning of the init.gradle.kts, Obv the classpath again is somewhere else, I can not access them so had to duplicate definition. 
    val ARTIFACTORY_BASE_URL = "...."

    fun RepositoryHandler.corporateRepos(ARTIFACTORY_BASE_URL: String) {
        maven {
            name = "central"
            url = uri("$ARTIFACTORY_BASE_URL/libs-release")
        }
        maven {
            name = "snapshots"
            url = uri("$ARTIFACTORY_BASE_URL/libs-snapshot")
        }
        maven {
            name = "gradle-plugin"
            url = uri("$ARTIFACTORY_BASE_URL/gradle-plugin")
        }
    }
    
    repositories {
        mavenLocal()
        corporateRepos(ARTIFACTORY_BASE_URL)
    }
    
    dependencies {
        classpath("dev.aga.gradle:version-catalog-generator:2.1.2")
    }
}

Result : Unresolved reference: dev
This is from settings.gradle.kts in project. Where I am importing the generate method from the plugin’s helper.
import dev.aga.gradle.versioncatalogs.Generator.generate

So here is the update;

Do you still have the initscript { ... } block you mentioned, it is still necessary.
If so, use an import ... instead of a fully-qualified class name.

This is from settings.gradle.kts in project.

As I said, classes you add in the init script are not available in the classpath of settings scripts or build scripts. (Please expose plugins defined in init script to the target project · Issue #27979 · gradle/gradle · GitHub)

I had to leave that plugin for a while since license plugin (project plugin) has critical consequences if failed. It was a bit more easier and your help made it work quite fast. :slight_smile: thx :slight_smile:

During the config, used this where I reached it from a gradle forums https://github.dev/gradle/gradle/blob/27078ba50717046b3508509b53bed66868c7a7c5/gradle/buildScanInit.gradle

initScript block with repository and classpath extension with plugin coordinates are still there.

then in afterEvaluate

afterEvaluate {
        afterEvaluate {
            plugins.withId("java") {
                //https://plugins.gradle.org/plugin/com.github.jk1.dependency-license-report
                plugins.apply(com.github.jk1.license.LicenseReportPlugin::class.java)

                extensions.configure<com.github.jk1.license.LicenseReportExtension> {
                    configurations = arrayOf("compileClasspath", "runtimeClasspath", "testCompileClasspath", "testRuntimeClasspath")
                    allowedLicensesFile="<url_to_allowed_licenses_file>"
                    allowEmptyLicense = true
                    excludeGroups = arrayOf(
                        "...",
                    )
                    
                }

                tasks["build"].dependsOn(tasks.getByName("checkLicense"))
            }
        }

Lastly, I guess this is again yet another classpath issue but why I can not use the repository extension function and other variables defined in the init script file’s very top in initScript block ?

I mean

val someValue = "....."

below fails as someValue is not defined. 
initScript {
   ...$someValue ...
}
1 Like

then in afterEvaluate

You should really not use afterEvaluate.
The main “benefit” of afterEvaluate is timing problems, ordering problems, and race conditions.
There are only very rare edge cases where you have to use it, mostly when needing to cooperate with other plugins badly using afterEvaluate.

plugins.

If you have a look at the JavaDoc of plugins. (i.e. getPlugins()), you will learn that you should not use it, but e.g. pluginManager.withPlugin(...) { ... ] and project.apply....
Especially when using withPlugin (or withId) using afterEvaluate should never be necessary, especially not nested twice.

tasks[“build”].dependsOn(tasks.getByName(“checkLicense”))

check should be the more appropriate lifecycle task here. :wink:

why I can not use the repository extension function and other variables defined in the init script file’s very top in initScript block ?

Same reason you cannot do so in buildscript or plugins blocks in build scripts or settings scripts.
They are extracted and evaluated separately first to determine the dependencies needed to compile the script, so you cannot use anyhting outside the block, because what is outside the block does not exist from the point of view of that block as it is not executed from within that script.

check should be the more appropriate lifecycle task here. :wink:

well our packaging system already packaging the test sources separately (some legacy reasons :slight_smile: ) and running them in a different way, we are mostly skipping check.

You should really not use afterEvaluate .
The main “benefit” of afterEvaluate is timing problems, ordering problems, and race conditions.

Since it’s working I’ve never tought of afterEvaluate phase, but now I will give it a look and try what you offer also.

Lastly, this thread evaluated somewhere else but I learnt a lot. Honestly, the thread broke a lot of false signs towards gradle also.

Thanks for your great patience and helps.

removed afterEvaluate and converted to

allProjects {
     pluginManager.withPlugin("java") {
          ... all java options extra license check plugin etc.. apply and configure here. 
     }

      pluginManager.withPlugin("maven-publish") {
          ... configure internal maven repositories...
     }
}

ıf you don’t like this, I am done and gone in tears :smiley:

1 Like

ıf you don’t like this

Well, if you like it.
It will not compile, but if that is ok for you. :smiley: :smiley: :smiley:

But besides of the type, that seems fine an init script, yeah.
allprojects { ... ] is mainly bad in a project build script as that is then cross-project configuration which is quite evil. :slight_smile:

It will not compile, but if that is ok for you. :smiley: :smiley: :smiley:

sarcastic on comments huh ? It compiled :slight_smile:

With the uppercase P? o_O


current init.gradle.kts snippet. and yes compiling.

..
BUILD SUCCESSFUL in 1m 38s
40 actionable tasks: 25 executed, 15 up-to-date

Of course, there you do not have the uppercase P


ohh, I tought you talk about ‘P’ in withPlugins. Previous post code blocks was by hand writing, not copy/paste. That’s why IDEs exists, isn’t it :slight_smile:

1 Like