Configure tasks / extensions defined in convention plugins dynamically

Hi, I’ve got a question regarding task / extension configuration. We’re using jib in our multi-module build and in order to avoid duplicating the configuration in every module (majority of the configuration is the same, but there are some differences so we can’t reuse them without overwriting these differences), I am attempting to move the configuration to buildSrc and then either configuring or overwriting parts of the configuration in build.gradle.kts files of specific modules.

So, let’s say my jib configuration is the same for all modules, except for the image option, where I have to pass a different service name for each module

  1. The “common” convention configuration in buildSrc folder:
// buildSrc/src/main/kotlin/com.acme.jib-configuration.gradle.kts
plugins {
    id("com.google.cloud.tools.jib")
}

jib {
    val serviceName = // how do I pass the service name variable from a submodule here? 
    to {
       image = "europe-west1-docker-pkg.dev/something/$serviceName
    }
    ...
}
  1. A build.gradle.kts of one of my modules
// someModule/build.gradle.kts
plugins {
    id("com.acme.jib-configuration")
}

dependencies {
    ....
}

jib {
    // I imagine I would have to pass the serviceName value here somehow
}

I’ve been exploring how to do this with extra, but I haven’t managed to get it to work. Looking at this, I have a feeling I’m approaching this with an incorrect approach, because it feels like something that should be easily done.

My question is, where am I going wrong in my approach? Should I instead define a task inside buildSrc that configures the jib extension and then I call it in each submodule with the parameters that I need for that module? Should I define a custom plugin for this? I imagine that if we want to make the configuration for jib common among all our projects, making it a custom plugin is a prerequisite?

Any pointer into the right direction would be helpful, I feel like I’m just around the corner from the correct solution but I’m approaching it from the wrong perspective.

Kind regards

I’ve been exploring how to do this with extra , but I haven’t managed to get it to work.

Using extra is almost always the wrong answer, it is almost always just a dirty work-around for not doing something properly.

Should I instead define a task inside buildSrc that configures the jib extension and then I call it in each submodule with the parameters that I need for that module?

No, tasks should not change configuration.
There was a pattern in the past to configure task from other tasks execution phase, but this should not be done anymore, especially as it is not configuration cache compatible.

Should I define a custom plugin for this?

You already did, so not sure what you mean.

Any pointer into the right direction would be helpful, I feel like I’m just around the corner from the correct solution but I’m approaching it from the wrong perspective.

It depends on whether you care about Groovy DSL and Kotlin DSL, or just care about Kotlin DSL as it is anyway just for your build privately.
In the latter case, I’d probably just define an extension function like

fun com.google.cloud.tools.jib.gradle.JibExtension.forService(serviceName: String) {
    to {
        image = "europe-west1-docker-pkg.dev/something/$serviceName"
    }
}

that you then can use like

jib {
    forService("foo")
}

If you care about both DSLs and consistency, you could either do the same for Kotlin and for Groovy add a closure as extension to the JibExtension that can then be called the same way as shown above just from Groovy DSL.

Or alternatively you could register an extension either on the JibExtension or on the project that has a method that does the setup when called.