littlerobots / version-catalog-update-plugin

Gradle plugin for updating a project version catalog
Apache License 2.0
566 stars 23 forks source link

Whether there are options that only show the updateable version, and do not really perform the update. #70

Closed lost22git closed 2 years ago

lost22git commented 2 years ago

Whether there are options that only show the updateable version, and do not really perform the update.

Because I found that executing the update would destroy my TOML file format.

hvisser commented 2 years ago

If you don't want to rewrite, format or update the TOML file then this plugin isn't for you. You could just use the dependency versions plugin to get a report of available updates in stead.

63 will make updates to make it easier to apply only the changes you want, but it will still format the TOML file in that case.

jhansche commented 2 years ago

There is one use case where having a report is desired, just like in the gradle-versions-plugin, and in this use case, the gradle-versions-plugin is not sufficient to achieve that.

That is, when we have a module that publishes a versionCatalog to be consumed by other projects. In that case, we would still want to see the report of available updates, without modifying the file; and the ben-manes plugin is not going to work because that will only look at actual applied dependencies. In the case of a versionCatalog project, those aliases do not actually get applied to project.dependencies, so neither plugin is really suitable for that.

Also in this case, it's unlikely that we'll be publishing the gradle/libs.versions.toml file, because as a standalone module we may want that file to live in $rootDir/catalog-module/src/main/com.company.versions.toml. The file is intended for publishing only, and doesn't actually play a role in the project's own dependency resolution.

As it is now, I can see no way to get a report of available updates for the dependencies listed in this toml file, because it will only scan the gradle project's actual dependency configurations. If we aren't selecting anything from the toml file in any configuration dependencies, then neither plugin will have an effect.

ben-manes commented 2 years ago

What about creating a configuration that applies all of the toml dependencies? It doesn't have to use them for anything, just make them available for inspection.

jhansche commented 2 years ago

That was exactly the idea I had in mind as well. Unfortunately the toml accessors generated by gradle are not iterable, so this would have to be done manually or via reflection. Or I suppose we could use this plugin's toml parser to iterate the modules and dump everything into a dummy configuration.

ben-manes commented 2 years ago

A quick google and I found this which might be helpful

Make sure we can iterate on entries of a version catalog

I still use the ext pattern where everything is a map declaration, which is nice for applying build logic over an set of definitions. But from the API it looks like you could query for libraries, then for their definition and version, and add that to a configuration. A little more work but since Gradle is a DSL on top of a Java API, most things are available if you peek under the covers.

hvisser commented 2 years ago

You can also do something like this: https://github.com/littlerobots/version-catalog-update-plugin/issues/65#issuecomment-1204954251

Re: separate toml file for publishing, with support for multiple toml files coming soon that should be possible too.

jhansche commented 2 years ago

Both great ideas - and it looks like it works even without using implementation configuration, which would cause the published POM to include these. Instead, I created a dummy configuration and added everything there. This seems to be picked up by the DependencyUpdatesTask still, so it's a win-win:

catalog {
    versionCatalog {
        from(files("src/published-libs.versions.toml"))
    }
}
val dummy by configurations.creating {
    isCanBeResolved = true // So that DependencyUpdatesTask will pick it up
}
dependencies {
    // Only works if settings.gradle imports the `catalog-module/src/published-libs.versions.toml` in versionCatalogs{}
    versionCatalogs.named("publishedLibs").apply {
        libraryAliases.forEach { alias ->
            findLibrary(alias).ifPresent {
                addProvider(dummy.name, it)
            }
        }
        pluginAliases.forEach { alias ->
            findPlugin(alias).ifPresent {
                val mapped: Provider<Dependency> = it.map { plugin ->
                    // assumes that we can find the plugin using the .gradle.plugin marker:
                    create("${plugin.pluginId}:${plugin.pluginId}.gradle.plugin:${plugin.version.requiredVersion}")
                }
                addProvider(dummy.name, mapped)
            }
        }
    }
}

Another nice thing about this, is it gives you a way to inspect the actual toml dependencies using DependencyReportTask - including any that didn't resolve, and can be used as an extra safeguard against adding an invalid dependency to the toml file.

This can also be done without requiring that we import the catalog in settings.gradle, by casting the catalog extension to use CatalogExtensionInternal.getVersionCatalog(), but it seems a lot more involved, because we'd have to manually convert the DependencyModel to a Dependency.

There is also still one risk, where the catalog may contain competing entries: for example, a -modern variant that drops support for older devices (i.e., Android lib with a higher minSdkVersion) and a -legacy variant that rejects those newer versions due to the minSdkVersion conflict. But that's something I think we can work around in this DSL.

Thanks for the ideas!