Overriding publish conventions

I’m trying to wrap my head around how Gradle manages publish destinations across multiple projects (separate repositories) as we convert our projects from Maven.

The way we do things in Maven is use a Parent POM which configures distributionManagement to specify the default location for our artifacts. Individual projects are able to override the default setting in their Project POM by specifying a different distributionManagement destination. We even have Maven sub projects that can override that destination for only the sub project while the remainder goes to the default destination.

In trying to replicate this behaviour in Gradle, I’ve noticed that my overrides become additions instead. This is a big issue when using GitHub as my destination because they are super picky about where you publish artifacts. Generally, you would publish to your project repository and all artifacts are visible from the organization itself. For our setup we have the concept of private artifacts for our use only and public artifacts for sharing among downstream developers.

We set up our conventions to default to a private artifact repository and now I’m trying to override that in individual projects to use the public artifact repository instead.

What I expected was if I added

plugins {
    id("publish-conventions")
}
publishing {
    repositories {
        maven {
            name = "github"
            url = uri("https://maven.pkg.github.com/myorg/libs-public")
        }
    }
}

I would see one publishing repository for github. What I’m seeing is one for github pointing to libs-private (the convention) and one for github2 pointing to libs-private.

How do I actually replace that repository instead of create a new one? I hope that I’m not going to have to create a second convention for public artifacts.

We set up our conventions to default to a private artifact repository and now I’m trying to override that in individual projects to use the public artifact repository instead.

You cannot override publishing repositories.
Even calling clear() on the repositories would not help.
The moment the repository is added, tasks for it are created.

In Gradle you can have multiple publishing repositories and publish to them individually.
So the easiest with that setup you described would be to not invoke the publish task, but for example the publishXXXPublicationToYYYRepository or publishAllPublicationsToYYYRepository.

Another possibility would be to set the publishing tasks for the not-wanted repository to isEnabled = false so that they are skipped when you invoke publish.

Another way would indeed be to split your convention plugin, probably into 3 plugins.
One that configures the private repo for publishing and applies the common one,
and one that configures the public repo for publishing and applies the common one.

Another option would be, that you have one plugin that by default does not register any publishing repositories, but adds an extension to publishing.repositories with functions private and public, then the consuming builds can call those functions to decide for the private or the public repo without needing to care about the details of the configuration.

(… and no, there is no good way to have one as default in that setup)

I would like to explore how to do this further. I’m already adding the override in the project that needs such customization; being able to disable the original would be a reasonable addition to that customization.

The next question is “how do I tell the original repository that it’s disabled?”

As I said, you don’t tell it to the repository, it is just a repository.
You tell it to the tasks that are created for that repository.
For example like

val repoName = "..."
publishing
    .publications
    .withType<MavenPublication>()
    .configureEach {
        tasks.named("publish${name.replaceFirstChar { it.titlecaseChar() }}PublicationTo${repoName}Repository") {
            enabled = false
        }
    }

or a bit more succinct but a bit less correct:

val repoName = "...".replaceFirstChar { it.titlecaseChar() }
tasks
    .withType<PublishToMavenRepository>()
    .named { it.startsWith("publish") && it.endsWith("PublicationTo${repoName}Repository") }
    .configureEach { enabled = false }

Thank you so much. I went with your first example and now have a documented method to use for Gradle projects. This will make migrating our projects from Maven just a touch easier.