Is there a way to define an ArtifactRepository in a single place and use it everywhere?

Say I have a functions that creates an ArtifactRepository:

fun RepositoryHandler.myCustomRepository(): MavenArtifactRepository {
    // etc...
}

I want to use this function:

  • for both dependency loading and plugin loading
  • in my root project, all subprojects, and in buildSrc

The best I’ve found is to use settings.gradle.kts and buildSrc/settings.gradle.kts and define and use the function in four places:

  • settings.gradle.kts in pluginManagement
  • settings.gradle.kts in dependencyResolutionManagement
  • buildSrc/settings.gradle.kts in pluginManagement
  • buildSrc/settings.gradle.kts in dependencyResolutionManagement

This still requires that I have 4 copies of this code. Is there some way to define this function in ONE place, and use it in all four of these places?

As pluginManagement is executed before settings plugins are the on the class path, even a settings plugin would not help to reduce it to 1.

So the only thing that comes to mind is an init script that could do it, and thus most probably a custom Gradle distribution.

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:
// 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
}
  1. in settings.gradle.kts, in the main build do something like:
pluginManagement {
    includeBuild("repositories")
}

plugins {
    id("my.repositories")
}

dependencyResolutionManagement {
    repositories {
        dependencyRepositories()
    }
}
  1. in settings.gradle.kts, in buildSrc/, do almost the same thing:
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. :person_facepalming:

    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.