I have an function I want to use in place of `mave...
# community-support
l
I have an function I want to use in place of
mavenCentral()
. I've defined it as an extension function on `RepositoryHandler`:
Copy code
fun RepositoryHandler.myRepository(
    // some parameters
): MavenArtifactRepository =
    maven {
        // implementation
    }
I want to use it: • in my main (multiproject) build ◦ for buildscript repositories (eg: loading plugins) ◦ for project dependencies • in buildSrc ◦ for buildscript repositories (eg: loading plugins) ◦ for project dependencies What is the right place to put something like this? Things I've tried: 1. If I put it in
buildSrc/src/main/kotlin
, I can't use it in the buildscript repositories of buildSrc. 2. If I give buildSrc its own buildSrc, and put it in
buildSrc/buildSrc/src/main/kotlin
, then the main build can't use it at all. 3. I put it in
buildSrc/src/main/kotlin
and symlink it to
buildSrc/buildSrc/src/main/kotlin
it lets me use it in all 4 places. Aside from seeming somewhat sketchy, this has the problem that now
buildSrc/buildSrc
also needs buildscript repositories defined, and cannot use
myRepository
. How do I define
myRepository
in one place, and use it everywhere in my build(s) that need repositories?
e
I don't think it's possible to add to everywhere without modifying your Gradle distribution
l
Is there any way to have an initscript that's local to the project?
e
no, that still won't work for some parts of the buildscript (such as
pluginManagement { repositories { ... } }
IIRC)
l
I would've thought this would be a pretty common need. We have a caching maven proxy, and we want all dependency requests to go through it, but the configuration is somewhat verbose. I'd like to avoid having to specify the configuration in multiple places. What's the best we can do without a custom Gradle distribution?
e
you shouldn't need to specify it in very many places; `settings.gradle(.kts)`'s
pluginManagement
+
dependencyResolutionManagement
should generally be enough, unless you're also declaring non-plugin buildscript dependencies or per-project repositories (which is not a good idea anyway)
l
Looks like I need to define it in 4 places: •
settings.gradle.kts
in
pluginManagement
settings.gradle.kts
in
dependencyResolutionManagement
buildSrc/settings.gradle.kts
in
pluginManagement
buildSrc/settings.gradle.kts
in
dependencyResolutionManagement
Strangely, even if I define the function at the top-level of
settings.gradle.kts
, I can't reference it inside
pluginManagement
(though I can inside
dependencyResolutionManagement
), so I end up having 4 copes of the same code. 🙁
I asked this question on Stack Overflow as well, and Simon Jacobs came up with a solution that seems to work. Here it is with a few more details filled-in: 1. Create a settings plugin in a separate build:
Copy code
// repositories/build.gradle.kts
plugins {
    `java-gradle-plugin`
    `kotlin-dsl`
}

dependencies {
    repositories {
        gradlePluginPortal()
    }
}

gradlePlugin {
    plugins {
        create("RepositoriesPlugin") {
            id = "my.repositories"
            implementationClass = "RepositoriesPlugin"
        }
    }
}


// repositories/src/main/kotlin/RepositoriesPlugin.kt
class RepositoriesPlugin : Plugin<Settings> {
    override fun apply(target: Settings) {
        target.pluginManagement.repositories.pluginRepositories()
    }
}

fun RepositoryHandler.pluginRepositories() {
    // TODO: set up repositories here
}

fun RepositoryHandler.dependencyRepositories() {
    // TODO: set up repositories here
}
2. In
settings.gradle.kts
, in the main build do something like:
Copy code
pluginManagement {
    includeBuild("repositories")
}

plugins {
    id("my.repositories")
}

dependencyResolutionManagement {
    repositories {
        dependencyRepositories()
    }
}
3. In
settings.gradle.kts
, in
buildSrc/
, do almost the same thing:
Copy code
pluginManagement {
    includeBuild("repositories")
}

plugins {
    id("my.repositories")
}

dependencyResolutionManagement {
    repositories {
        pluginRepositories()
        dependencyRepositories()
    }
}
Any code we want to share between the 4 repository locations can be in
RepositoriesPlugin.kt
(once!), so we don't have to have multiple copies of our repository setup code. Some caveats: 1. The
pluginManagement.repositories
for both builds (main and buildSrc) end up being the same. This is fine for our purposes. I assume a second settings plugin could be defined if these needed to be different. 2. The repository plugin's build itself needs repositories set up. 🤦 I believe this is only necessary in order to get the Kotlin compiler, so perhaps this could be avoided by writing the plugin in Groovy, but I haven't tested this. 3. This is a lot more circuitous than I would have expected for something I'd expect to be a pretty common need, so probably isn't worth it unless you have sufficiently complex repository setup.