littlerobots / version-catalog-update-plugin

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

Optionally add new versions as comments #63

Closed nkiesel closed 2 years ago

nkiesel commented 2 years ago

Hi,

we are currently using "refreshVersions" in a rather large project (200+ dependencies). I started using this plugin as an alternative in some smaller projects, and it's working fine. However, we cannot afford to always handle upgrades to all 200+ dependencies in a single commit for the large project. The only options I see right now would thus be to use "git incremental add" (assuming libs.versions.timl is under Git control), or a git restore followed by a manual version upgrade. A better approach for us thus could be to run ./gradlew versionCatalogUpdate --propose (or perhaps ./gradlew versionCatalogPropose), which would add available upgrades as comments behind the outdated versions. We could then manually modify the file, shifting the comments to versions where we want to upgrade. Running the same command some time later would then upgrade the version numbers in the comments, or add new comments.

This would allow running the command regularly to stay informed about possible upgrades, without being forced to accept all upgrades.

hvisser commented 2 years ago

I agree that updating everything in bulk is not a great idea (even though this plugin might imply that 😄), and it would be great to have a mechanism to control the updates a bit more like you mention. I see a couple of options:

  1. Run the versions report from the versions plugin (no work to be done in this plugin). The downside is that you'd have to go in and find the things you want to update, but all of the info should be there in the report (except for plugin versions maybe).
  2. Update the version catalog, either with comments or just updating and then use vcs or local history to rollback the changes that you don't want. This is mostly how I personally do it now, but with a lot of updates this can get cumbersome.
  3. Based on your proposal, we could do an incremental run and record what would be updated, but in stead of writing to the actual catalog file, a separate file is written that you can then edit. I imagine this to look like the catalog file with only the [libraries] and [plugins] sections with the same keys as your version catalog file. Updates would be commented out so that you can "enable" them, before running the task again to apply the changes. I think that could be very cool :) Writing to a separate file also prevents touching / changing the catalog file. What's also cool is that we could point out updates for pinned dependencies.

There are some details to be figured out, but in general I think the 3rd option could work, wdyt?

nkiesel commented 2 years ago

Thanks for your feedback. I don't think I fully understand your 3rd option idea. Assume I have a catalog file, and 2 libraries have newer versions available. If I run the current "update", I would get 2 lines changed in the [versions] section. Just looking at the file I cannot see that, but assuming the file is under version control, a simple git diff -- grade or equivalent would show me the 2 changed version values. Your 3rd option would not change the existing file, but instead create a new one. You said this would "only (have) the [libraries] and [plugins] sections". These would be identical to their equivalents in the original version catalog file, no? So how would that help? You also said that "updates would be commented out". So would the new file contain 2 more lines in my scenario, both commented out but containing the available newer versions? In this case, I could find the comments, and decide to either leave them untouched or remove the matching existing line and uncomment the new line?

hvisser commented 2 years ago

OK so that new file is just a temporary file that isn't checked in to version control, maybe I should have made that more clear.

Basically the steps would be:

  1. You'd run ./gradlew versionCatalogUpdate --interactive. That would create a new file libs.versions.update.toml.
  2. You edit that file and remove / comment out any updates that you don't want from that file
  3. You run ./gradlew versionCatalogUpdate --interactive --continue (or something like it) to update the actual lib.versions.toml and apply the changes, which would then also update any applicable version block too like normal.

What I meant by "only library and plugin sections" is that it would show you the full dependency declaration. So maybe your real toml file has mylib = { module = "some:library", version.ref="myversion" }, the scratch file would have

# Current version is 1.0.0
mylib = "some:library:1.2.3"

I think it would make more sense to not comment anything out in that temporary file, by default it would basically list all the changes that can be made, you'd just remove lines or comment them out if you don't want to apply those changes.

nkiesel commented 2 years ago

Ok, now I understand. And yes, that would be nice!

One minor concern: if I have many libraries sharing the same version (e.g. jackson dataformat, databind, xml, yaml, ...), then your approach would add a line for each of them to libs.versions.update.toml if we have a new Jackson release, correct? And what would happen if I then only comment out half of these lines?

hvisser commented 2 years ago

That's no different than updating / changing a dependency in the toml file; it would try to keep stuff in the version group where it can and create a new version group (if applicable) for other dependencies. I'd think that just having an update for the version (in a versions section) wouldn't make much sense out of context, but maybe it's something to experiment with.

Initially I'm thinking it would complicate things a bit because you can reuse a version between multiple library (groups) even if they aren't really related.

If you would apply half of it though by mistake, you should be able to run the same thing again and add the missing updates to fix it. I think it would be worth exploring to see if this works anyway :)

mtrakal commented 2 years ago

Hi, what I preffer in that case is not to update autmatically, but add comment behind current version like this to libs.versions.toml:

androidx-activity = "1.5.1" # 1.5.2
androidx-appcompat = "1.4.2" # 1.4.4

etc. If I want to keep current version I still can, but when new version will be released I know about it (and know about just new update when I again call versionCatalogUpdate).

Origin state:

androidx-activity = "1.5.1"
androidx-appcompat = "1.4.2"

call versionCatalogUpdate

androidx-activity = "1.5.1" # 1.5.2
androidx-appcompat = "1.4.2" # 1.4.4

I update just appcompat (because activity causes for me some issue now) and commit it to git (with commented version):

androidx-activity = "1.5.1" # 1.5.2
androidx-appcompat = "1.4.4

after a week I just call versionCatalogUpdate:

androidx-activity = "1.5.1" # 1.5.3
androidx-appcompat = "1.4.4

from Git diff / changes I now see, that version of not updated lib has new version and I can try to update to latest one.

Of course in comment can be mentioned alpha/beta versions too like androidx-activity = "1.5.1" # 1.5.2 [1.7.0-alpha01, 1.6.2-beta03, 1.5.3-rc01]

nkiesel commented 2 years ago

This was my original proposal, and also what the refreshVersions Gradle Plugin did earlier (now they add all newer versions, not just the latest one).

hvisser commented 2 years ago

Comments are super hard to manage (technically) and I don't really like how those comments would accumulate in the TOML file, updating the file with no real changes. Therefore a think a staging file like what is implemented now is the better option: the TOML file isn't touched(*) until you tell the plugin to apply the changes, so it's easy to discard any update too. So I hope what is implemented now will fit the use case, testing it on a few projects seems promising to me :)

(*) that's not completely true, it is still being updated removing unused dependencies and formatting bundles, but typically that shouldn't result in a huge diff.