Disabling a project's publication dynamically

Hi,
I have a Gradle plugin which adds a publication to the project it’s applied to. At the moment, it looks something like the following:

    val myArtifact = project.artifacts.add("artifactName", artifactFile) {
        builtBy(createArtifactTask)
    }

    project.publishing.publications {
        create<MavenPublication>("myPublication") {
            groupId = project.group.toString()
            artifactId = "${project.name}-special-publication"
            version = project.version.toString()
            artifact(myArtifact.file) {
                extension = "tar.gz"
                builtBy(createArtifactTask)
            }
        }
}

There are cases though when the publication should not exist (or its publish tasks should be disabled). These cases depend on how the plugin extension object was configured by the project (the plugin extension uses NamedDomainObjectContainer fields).

I can’t seem to figure out how and where this plugin can evaluate its extension object to decide whether or not to disable a publication’s publish tasks or to not create the publication at all. Running code inside the project.afterEvaluate block doesn’t seem to run after population of the extension object unless I call something like DomainObjectCollection.all or the like.

Is there a proper way to achive dynamic publications via a plugin?
Thanks

afterEvaluate is almost never a viable solution for anything. The main earnings you get from it are timing problems, ordering problems, and race conditions. You should avoid it wherever possible.

From what you described the most proper solution is to set onlyIf on those tasks and in the action you give to it evaluate whether the task should be skipped or not.

Hi Björn,
Yeah, I’ve been trying to avoid it.
Can I assume that in the plugin’s apply method, the project extension object has already been set?
It seems like I need to somehow evaluate the NamedDomainObjectContainer object with .all or such so that its contents will be set.
Thanks.

Oh, my mistake, seems like the extension object isn’t populated yet. all executes a an action asyncronously when objects are added to the container. I’ll have to try adding the publications lazily when objects are registered with the container.

Can I assume that in the plugin’s apply method, the project extension object has already been set?

You can be 100 % sure that this will NOT be the case.

with .all

If you do so, you destroy any laziness and cause all elements to be immediately realized when registered. If that is what you intend it might be ok. If you just want to handle all that are registered if they are actually going to be realized for some other reason, then you use configureEach.

That you can get all configured values using all or configureEach does not mean they are already set when your apply method runs. Both methods get all current and future elements which makes it work.

For my usecase, I’m interested that at least a single element has been registered. So I’m listening on whenObjectAdded and creating the publication only for the first registered element.

Just so that you aware, this as well causes all elements in the collection to be eagerly realized, because whenObjectAdded receives the created element as argument.

Yes, I understand.
In my case these elements are really simple objects so there’s no issue in realizing them (I think).
I do wonder though, how I would achive the same requirement of conditionally adding a publication based on an extension in a plugin without realizing the elements. Gradle is hard sometimes.
Thanks Björn.

1 Like

Iirc there is not really a good way, maybe with Gradle 9 something is coming.
One way for example would be to not expose the collection to the consumer directly, but to have some function in your extension that fills the collection and can then e.g. register the publication on first call.

I’ll try to remember that option for future use.
Thanks again Björn!

1 Like