The best place to create plugin configuration

Hi. Adjusting to deprecation warnings in Gradle 6+ I’m moving the configuration for my gradle-pitest-plugin from the root project to a project it is applied. In general it is not a problem, but I have two questions:

  1. Should the plugin configuration (with dependencies required for the plugin task to execute) be put as the project.configuration or project.buildscript.configuration (it seems to work in both cases and I wonder which is recommended)?

  2. I create my configuration in:

    void apply(Project project) {
        ...
        project.plugins.withType(JavaPlugin).configureEach {
            setupExtensionWithDefaults()
            project.tasks.register(PITEST_TASK_NAME, PitestTask) { t ->
                ...
                createConfiguration()
                ...
            }
        }
    }

However, it seems to cause, that I cannot just use it in build.gradle, but I have to create it manually there:

plugins {
    id 'info.solidsoft.pitest' version '1.4.9'
}

configurations.create('pitest')   //while removed generates error about unknown configuration
dependencies {
   pitest 'org.pitest:pitest-junit5-plugin:0.12'
}

I wonder, if there is a good way to do not have to manually create a configuration by the users of my plugin, yet still use project.plugins.withType(JavaPlugin).configureEach { (if it is still recommended)?

[1] buildscript is only meant for dependencies that are to be on the plugin classpath itself.

[2] If I understand it correctly you want all cases of where the java plugin is applied that the pitest extension is added as well. Iwould like to add a couple of views on this.

a) It someone applies pitest it can be reasonably assumed that they either applied java or java-library, so I would not conditionally configure of the subproject. Instead I would just create the appropriate configuration and extension. Of course if it depends on java or java-library then you need to either apply it with the plugin apply method or add the dependency. It’s up to you as you know the intended usage of the plugin.

b) Any iser in a multi-project you can add id 'info.solidsoft.pitest' version '1.4.9' apply false to the root and then in the subproject do plugins {id 'info.solidsoft.pitest'} or simply apply plugin: 'info.solidsoft.pitest'. That is the best way to deal with selective application in multi-project scenarios.

c) Your plugin’s apply method should just need to project.configuration.maybeCreate('pitest') and for the default dependency you can use the defaultDependencies method on the configuration.

d) Don’t create the configuration within the lazy-configuration of the task. Create it outside. Configurations and extensions are “static” specifications within a build, whereas tasks tend to be more complex and now can preferaby be configured only if they are needed. Don’t get caught out by lazy-created tasks. Those actions are only meant to be applied to the newly instantiated tasks and nothing else.

Thanks for you suggestions, Schalk!

It could be a plugin classpath dependency, but in fact I refactored it to use JavaExec, so it is not needed to bootstrap the plugin itself.

I use that deferred construction to refer to the elements specific for Java (which might not be accessible if the Java plugin is applied after mine). However, creating the configuration itself in fact seems to be same in general. I moved it out and it works nice.