I'm getting a bit frustrated with getting the publ...
# community-support
s
I'm getting a bit frustrated with getting the publication of a version-catalog for my multi-module project working. My multi-project is already published to Maven Central, and I just want to additionally publish a version catalog for easier consumption by users. At first I though each project can just "opt-in" to be part of the version-catalog, but after reading the docs it seems that I need to create a new subproject that is exclusively responsible for publishing the version-catalog. In that new project, I need to manually list all libraries via a DSL. So the 1M-question is: How can I add all libraries of my multi-project there without hard-coding everything? If I iterate over subprojects, I fear that I'm again violating some Gradle best-practices about decoupling projects 😬
t
I ended up doing it like this. certainly has that cross project coupling feel but so far configuration cache hasn't gotten angry at it.
Copy code
fun Project.addLibrary() {
            val subproject = this
            val aliasPrefix = subproject.path.let { path ->
                if (path.count { it == ':' } > 1) {
                    path.split(':')
                        .dropLast(1)
                        .filter { it.isNotBlank() }
                        .joinToString(separator = "-", postfix = "-") { it.normalizeName() }
                } else {
                    ""
                }
            }
            val aliasName = subproject.name.normalizeName()

            library("$aliasPrefix$aliasName", subproject.group.toString(), subproject.name)
                .versionRef("aetnahealth")
        }

        fun Project.processSubProjects() {
            println("Processing subproject: ${this.path}")
            this@processSubProjects.subprojects {
                val subproject = this
                val hasMavenPublish = subproject.plugins.hasPlugin("maven-publish")
                if (!hasMavenPublish) {
                    subproject.processSubProjects()
                } else {
                    subproject.addLibrary()
                }
            }
        }

        gradle.projectsEvaluated {
            rootProject.processSubProjects()
        }
biggest catch is I had to make sure configuration on demand was disabled for the invocation that creates the catalog
v
Yeah, accessing
plugins
alone is bad already, accessing it on another project is super-bad. Same for the
group
, don't reach into models of other projects.
t
(thinking out loud) I suppose that the "proper" way of doing it dynamically would be to use a BuildService, "exploring" all projects and building the catalog from the settings script using gradle.lifecycle.afterProject, and ensuring that the catalog project is evaluated last by using evaluationDependsOn from gradle.lifecycle.beforeProject, or something like that. I'm not sure this is worth it compared to declaring things explicitly at the expense of some duplication (I suppose it should be possible to test the catalog relatively simply with TestKit; the major risk then would be forgetting to add a project to the catalog)
t
build service is probably the right way. I may steal that idea once my current mess becomes an issue for me. Already have a convention plugin that wraps/configures the built in maven-publish plugin so reworking wouldn't be too hard. already sort of straddling since all my plugins that are done via includeBuild are just hard coded in. I don't anticipate that to go away. Luckily I am basically the only one editing those parts of the project so I don't mind being the weak link in having to remember to update/add things.
s
I'm really surprised that Gradle makes this so hard... I mean, isn't it the primary use-case that you want to publish a version-catalog from a multi-project? Because for a single-project there would be no benefit in publishing a catalog in the first place...
v
I think the primary intended use-case is that in a company you define a list of dependencies with versions to be used by all builds, so create the catalog and publish it and then consume it in the other builds.
You could maybe just declare them manually and then add a
doLast
or
doFirst
action to the
generateCatalogAsToml
task that verifies you did not forget to add any.
t
For a multi-project build, you'd more likely publish a platform than a version catalog.
t
isn't it the primary use-case that you want to publish a version-catalog
bad assumption there I think. gradle has always been about building software well. toml is a relatively new QOL feature. we are just lucky enough to be living thru the growing pains.
Hell i'd even go so far as to say if your project can justify publishing a BOM or TOML you are probably a very mature project and probably really demand fine grain control like the basic DSL exposes. It is just unfortunate that good build script health demands isolation while a BOM/TOML really needs to read tons of details from sibling projects
can't have your cake and eat it
v
For a multi-project build, you'd more likely publish a platform than a version catalog.
Often both. The version catalog to get accessors for all modules without having to look up which modules exist. The platform to align versions of the modules. The later optimally properly modeled so that it happens auto-magically without the needed to manually use the platform.
👍 1
s
So, to sum up, there's no simple way or third-party plugin that allows me to publish a version catalog for my multi-project with just a few lines of code, correct?
v
I have no idea, I'm not an encyclopedia of all existing 3rd party plugins. :-D
t
I'm not an encyclopedia
^yet But yeah what he said I've not heard of one. Only toml I have imported was from the AWS kotlin SDK which is where I took strong inspiration from when setting up our version catalog artifact.