We have two types of repos, single-project, and mu...
# plugin-development
b
We have two types of repos, single-project, and multiple-sub-project. We have a conventions plugin that we apply to all projects and sub-projects. It has an extension that accepts the artifact name to be emitted by a given project, and reacts to the presents of the
maven-publish
plugin, configuring publication. e.g.
val artifactName: Property<String> = project.objects.property(String::class.java)
used as
Copy code
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.
v
could do it simply at the top level project and reach down into the subprojects
This 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 an
afterEvaluate
which, as i understand it, is detrimental to config caching
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.
👍 1
b
that’s… a good point. refreshing myself, i see the publishing configuration itself is already in an afterEvaluate 😐 so here’s how that works:
Copy code
// 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.
v
Yeah well, ... As I said, setting the artifact id is either way a bad idea, whether you use
afterEvaluate
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. 🙂