openlang

The version catalog works everywhere except my convention plugins

Moving versions into gradle/libs.versions.toml, with shared setup in convention plugins under buildSrc. The idea was one place for versions. Three cases, in order.

In a subproject's build script, alias(libs.plugins.kotlin.jvm) and libs both work. No complaints.

The build script of buildSrc itself doesn't inherit the main project's catalog. It has to be imported by hand in buildSrc/settings.gradle.kts.

dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            from(files("../gradle/libs.versions.toml"))
        }
    }
}

Still as documented. A little odd that buildSrc needs telling where its own repository keeps the file, but it works and the accessors appear.

The third case is where it stops being pleasant. Inside a precompiled script plugin in buildSrc there is no type-safe libs. The docs say to look the catalog up by name with extensions.getByType(VersionCatalogsExtension::class.java).named("libs") and then ask it for each entry by alias. And that plugin's plugins block can't reach the catalog at all, so a convention plugin that applies another plugin names it by id, and the version comes from wherever buildSrc declared the plugin artifact.

So the picture is uneven. The build scripts that matter least get the nicest accessors. The convention plugins, where most of the shared setup now lives, get lookups by string.

There's always one place left where entries come out by name. At that point I wonder whether plain strings for coordinates inside convention plugins would be the more honest choice.

The conversation continues 3

Follow the reasoning
  1. Permalink

    Against strings. Then the version lives in two places. Once in the catalog, once in the convention plugin. Sooner or later only one of them gets bumped.

    The by-name lookup is ugly, ko_jae is right about that. It's one ugly line, and the version still has a single home. Keep the findLibrary calls together in one plugin, so a wrong alias at least fails in one file you know to look in.

  2. Permalink

    otto's way works for libraries. One convention plugin pulls the catalog with named("libs") and gets library coordinates through findLibrary("guava").get().

    What bothers me is that a typo fails in two very different ways. Misspell libs.guava in a subproject and script compilation stops right there on an unresolved name. Misspell the alias in the convention plugin and findLibrary returns an empty Optional, then get() throws NoSuchElementException with nothing about the alias in the message. Is there a way to get the alias into that message, or does everyone just grep for findLibrary when it happens?

  3. Permalink

    That bare exception ko_jae hit comes from get(). Swap it for orElseThrow with a message. fun VersionCatalog.lib(alias: String) = findLibrary(alias).orElseThrow { IllegalStateException("catalog has no library '$alias'") }. Every lookup goes through that one function.

    A wrong alias then fails at configuration with its own name attached.

Other sides of the same question

  1. tryEval passed a package I had broken on purpose

    Wrote a small sweep over an overlay that wraps each package in builtins.tryEval and lists the ones that fail. It reported eve…

    Replies 4nix
  2. for_each keys are addresses, not labels

    A for_each key isn't a label. It's half of the resource address, terraform_data.queue["prod-orders"], and the state tracks th…

    Replies 6hcl
  3. A stopped shell job is not a finished one

    Got a question about a supervisor rule that treats a stopped process as a finished one, and a tiny repro makes the problem ob…

    Replies 17bashpython