Search code examples
gradlegradle-kotlin-dsl

Where can I define a repository function so that I can use it in my entire gradle build, including buildSrc?


I have a functions that's an alternative to mavenCentral, which creates an ArtifactRepository:

fun RepositoryHandler.myCustomRepository(): ArtifactRepository {
    // about 20 lines of code
}

I have a multi-project Gradle build that also has a buildSrc, and I want to use myCustomRepository:

  • 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 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

Unfortunately, it seems that I also need to define four identical copies of the function, two in each settings.gradle.kts file. I haven't been able to find a single place to define it that's visible to all four locations where I need to use it.

That is:

settings.gradle.kts

fun RepositoryHandler.myCustomRepository(): ArtifactRepository {
    // copy #1
}

pluginManagement {
    fun RepositoryHandler.myCustomRepository(): ArtifactRepository {
        // copy #2
    }

    repositories {
        myCustomRepository()
        gradlePluginPortal()
    }
}

dependencyResolutionManagement {
    repositories {
        myCustomRepository()
    }
}

buildSrc/settings.gradle.kts

fun RepositoryHandler.myCustomRepository(): ArtifactRepository {
    // copy #3
}

pluginManagement {
    fun RepositoryHandler.myCustomRepository(): ArtifactRepository {
        // copy #4
    }

    repositories {
        myCustomRepository()
        gradlePluginPortal()
    }
}

dependencyResolutionManagement {
    repositories {
        myCustomRepository()
        gradlePluginPortal()
    }
}

Is there some way to define this function in only ONE place, and use it in all four of these places?


Solution

  • pluginManagement is special

    You cannot simply use an external function in the pluginManagement block because pluginManagement, like the plugins block, is isolated from the rest of the file1 so there is no import mechanism.

    Settings plugins in a composite builds

    What you can do as an alternative is to write a Settings plugin inside of an included build. Such a settings plugin can itself perform actions inside pluginManagement, including calling a given function.

    Also, a settings plugin, when applied inside the plugins block, has its JAR added to classpath of the settings.gradle.kts file so you can use any other functions defined in the plugin project in that file (though not pluginManagement).

    Sketch of layout

    All in all that would look something like this:

    1. An included build project which defines and exports a settings plugin using the Java Gradle plugin, and declares your function myCustomRepository(). Here's the key source file:

      // myIncludedBuild/src/main/kotlin/MySettingsPlugin.kt
      
      class MySettingsPlugin : Plugin<Settings> {
          override fun apply(target: Settings) {
              target.pluginManagement.apply {
                  repositories.myCustomRepository()
              }
          }
      }
      
      fun RepositoryHandler.myCustomRepository() {
          println(this::class.qualifiedName)
      }
      
    2. Then in settings.gradle.kts of the main project you can do:

      pluginManagement {
          includeBuild("myIncludedBuild")
      }
      
      plugins {
          // Calls myCustomRepository via its apply method
          id("mySettingsPlugin")
      }
      
      dependencyResolutionManagement {
          repositories.myCustomRepository()
      }
      
    3. buildSrc's settings.gradle.kts is identical except it needs a slightly different relative path to find the included build:

      pluginManagement {
          includeBuild("../myIncludedBuild")
      }
      

    Execute that build and you get the following output four times: org.gradle.api.internal.artifacts.dsl.DefaultRepositoryHandler_Decorated

    Use in other build.gradle.kts files

    Now you have an included build, you can proceed in similar fashion with Project plugins, or directly use the buildscript blocks to add the code of the included build project to any given build.gradle.kts file.


    1Gradle 6.0 upgrade instructions