Ben Madore
03/18/2025, 1:34 PMmaven-publish
plugin, configuring publication. e.g.
val artifactName: Property<String> = project.objects.property(String::class.java)
used as
fooConventions {
artifactName = "my-artifact-name"
}
a few times we’ve run into issues where someone copy-pastes some code and duplicates the artifact name, this unfortunately isn’t caught until the jar file is attempted to be published to artifactory, and user gets an unclear message that the artifact has already been published, and they tend to think it’s a CI problem instead of a project problem.
What would be the most ideal way to validate that the configuration across all sub-projects does not contain any duplicates between each project’s conventions.artifactName
property? Is this a valid use of a Shared Build Service? I could do it simply at the top level project and reach down into the subprojects, but i think then it’d have to be in an afterEvaluate
which, as i understand it, is detrimental to config caching.Vampire
03/18/2025, 1:45 PMcould do it simply at the top level project and reach down into the subprojectsThis by itself is a bad idea, you should neither to cross-project configuration, nor reading from other project's models
but i think then it’d have to be in anwhich, as i understand it, is detrimental to config cachingafterEvaluate
afterEvaluate
is not so much a problem with config cache, but is a problem in itself as the main earnings you get from using it are timing problems, ordering problems, and race conditions
But actually I wonder how you are "configuring publication", as those are not lazy yet (hopefully changes with Gradle 9), so you probably have race conditions there already too.
Also, it is usually a very bad idea to configure things like group, name, and version on the publication. It is almost always preferable to make sure the project name is set accordingly so that the publication information is determined right by default. Ensuring that the project names are unique should also be easier then as you can do that in the settings script / a settings convention plugin.Ben Madore
03/18/2025, 7:12 PM// Injected by the CI job
val artifactoryReleaseUsername: String? by project
val artifactoryReleasePassword: String? by project
val artifactorySnapshotUsername: String? by project
val artifactorySnapshotPassword: String? by project
// Try to read app version from environment for CI jobs
val envVersion: String? = System.getenv("AUTO_VERSION")
val publishVersion = if (!envVersion.isNullOrEmpty()) envVersion else project.version
val isSnapshot = publishVersion.toString().endsWith("SNAPSHOT")
configure<PublishingExtension> {
repositories {
maven {
val releasesRepoUrl: String? = project.properties["gd_maven_releases_url"] as String?
val snapshotsRepoUrl: String? = project.properties["gd_maven_snapshots_url"] as String?
if (isSnapshot && snapshotsRepoUrl != null) {
url = uri(snapshotsRepoUrl)
} else if (releasesRepoUrl != null) {
url = uri(releasesRepoUrl)
}
credentials {
username = if (isSnapshot) artifactorySnapshotUsername else artifactoryReleaseUsername
password = if (isSnapshot) artifactorySnapshotPassword else artifactoryReleasePassword
}
}
}
}
// Does not accept lazy config property, so must use afterEvaluate
afterEvaluate {
// Only configure the maven java publication in applicable scenarios,
// the bootJava publication is configured further below for boot apps
if (!(
project.pluginManager.hasPlugin("org.springframework.boot") ||
project.pluginManager.hasPlugin("java-platform") ||
project.pluginManager.hasPlugin("java-gradle-plugin")
)
) {
configure<PublishingExtension> {
publications {
register<MavenPublication>("mavenJava") {
from(components["java"])
if (extension.artifactName.isPresent) { // Set artifact name if default is overridden
artifactId = extension.artifactName.get()
}
if (extension.resolvedVersionsInMetadataPublications.get()) {
versionMapping {
usage("java-api") { fromResolutionOf("runtimeClasspath") }
usage("java-runtime") { fromResolutionResult() }
}
}
}
}
}
}
}
we wanted to avoid having to put publishing configuration responsibility on each app dev team. in the past we had folks doing all sorts of silly things, such as using the godawful artifactory plugin for publishing.Vampire
03/19/2025, 9:09 AMafterEvaluate
or not.
For the rest, maybe better have a function in the extension to which you give the resolvedVersions...
boolean as argument, and do the publishing configuration in its implementation, then you do not need any afterEvaluate
there. 🙂