3

A large project with many developers and gradle projects uses a private maven repository for plugins, dependencies, and publication.

I would like to define a privateMaven() method, just like the built-in jcenter(), mavenCentral(), and google() methods. Currently we write a maven block anywhere we need to use the repository - repositories, publishing.repositories, pluginManagement.repositories, ...

repositories {
  maven {
    url "..."
    credentials { ... }
  }
}

which I would rather be

repositories {
  private()
}

This answer explains how to extend repositories and buildscript.repositories but it doesn't work for publishing.repositories because publishing is provided by a plugin and doesn't work for pluginManagement.repositories. Also I would also have to enumerate every repositories configuration and developers can't use privateMaven() in any block we don't extend.

Is there a way for an init script to add a method to every repositories block, or every RepositoryHandler?

everett1992
  • 2,351
  • 3
  • 27
  • 38

2 Answers2

1

Assuming you're using the maven-publish plugin, you can define an extension like so:

private.gradle

apply plugin: 'maven-publish'

publishing.repositories.ext.privateRepo = {
    publishing.repositories.maven {
        url "https://artifactory.website.com/private-repo"
        credentials {...}
    }
}

build.gradle

apply from: 'private.gradle' // or you can just include the script in here

afterEvaluate {
    publishing {
        publications {...}
        repositories {
            privateRepo()
        }
    }
}

You can also create a plugin if you'd like to distribute the script, the usage would remain exactly the same. https://guides.gradle.org/implementing-gradle-plugins/

PrivatePlugin.groovy

class PrivatePlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        // check if the publishing extension exists first
        final publishing = project.extensions.findByType(PublishingExtension.class)
        if (publishing != null) {
            publishing.repositories.ext.privateRepo = {
                publishing.repositories.maven {
                    url "https://artifactory.website.com/private-repo"
                    credentials {...}
                }
            }
        }
    }
}

Just be sure that if you distribute it as a plugin that you don't ship it with the credentials hardcoded.

Nathan Reline
  • 1,137
  • 10
  • 13
  • I've figured out how to add extensions to the dsl but I don't want to enumerate everywhere the `repositories` can appear. dependencies, plugins, publish plugins... – everett1992 Oct 08 '20 at 17:38
1

My goal is that any repositories block can use privateMaven. I don't want to explicitly extend publishing.repositories.ext, repositories.ext, buildscript.repositories.ext. In addition to being tedious, if I miss one repositories or gradle adds a new repositories then privateMaven will not be available.

One solution which is close, but not perfect, was to create an extension on with a method that takes a reference to RepositoryHandler.

Any repository block and now use the extension as so

repositories {
  custom.privateMaven(it)
}
beforeSettings {
  extensions.create("custom", PrivateMavenExtension::class)
}
     
allprojects {
  extensions.create("custom", PrivateMavenExtension::class)
}

open class PrivateMavenExtension {
  fun privateMaven(handler: RepositoryHandler): MavenArtifactRepository {
    return handler.maven {
      // implementation
    }
  }
}

One major hurdle I haven't solved is that classes defined in an init.d script cannot be loaded in build.gradle. If PrivateMavenExtensions is defined in an init.d script I can't reference the extension in a type-safe way from a build.gradle.kts because the<PrivateMavenExtension>() cannot be resolved.

everett1992
  • 2,351
  • 3
  • 27
  • 38