joshka / tui-widgets

A collection of useful widgets for building terminal user interfaces using Ratatui
https://crates.io/crates/tui-widgets
Apache License 2.0
39 stars 5 forks source link

Latest releases are versioned as minor but are actually major releases #31

Closed matta closed 2 months ago

matta commented 2 months ago

This is a fun one.

TLDR: I can't upgrade to ratatu 0.28 just yet, but in order to defer that upgrade, I had to fix my Cargo.toml to say tui-prompts = "=0.3.20" instead of tui-prompts = "0.3.20". This was hard to diagnose, and I think ideally I shouldn't have had to care about this.

Concretely, the problem is that I can't update to ratatui 0.28 because a dependency I use, crokey, hasn't updated to it and still depends on 0.27. I had this in my Cargo.toml:

tui-prompts = "0.3.17"

...but blowing away my Cargo.lock and re-creating it broke my build because tui-prompts expressed its own ratatui 0.27 -> 0.28 upgrade using a compatible version change, instead of bumping its major version. My code, using ratatui 0.27, was using types incompatible with tui-prompts. In this build the only package using ratatui 0.28 was tui-prompts, and this upgrade happened automatically, because of the characterization of the release as a minor version bump.

The tui-prompts 0.3.21 release, which was a minor release, bumped its ratatui dependency to 0.28. Because tui-prompts uses ratatui APIs in its own API, this amounts to a major version bump, as evidenced by the build breaks I saw. I think tui-prompts version 0.3.21 should have been 0.4.0. This way, Cargo won't automatically upgrade past 0.3.20 to an incompatible version of tui-prompts.

I don't have a direct citation to docs that clearly state this as a best practice. There is https://doc.rust-lang.org/cargo/reference/semver.html, but this is broad and fairly loose recommendation, and doesn't talk specifically about crates that use APIs from other crates. I'm just deducing this from this experience, with a line of reasoning like:

  1. I can't use tui-prompts without using ratatui and crossterm APIs with it.
  2. I use multiple crates that use ratatui and crossterm APIs. As such, when I upgrade ratatui and crossterm, their upgrades need to be coordinated across all the crates.
  3. If ratatui and/or crossterm have a major version bump, rust won't consider their types compabile. As such, a major version bump in these dependencies is a "major version" change to all code using their types in their public API surface.
  4. The default recommendation is to specify versions with bare versions in Cargo.toml ("0.3.17"). By doing so, cargo will attempt to select compatible versions. This should be enough to prevent multiple versions of ratatui and crossterm from appearing in my "cargo tree" output.
  5. Alternatively, tui-widget crates could take careful, and manual, notes of the APIs they use, and express version constraints that span major versions (e.g. tui-prompts could probably claim that it is compatible with both ratatui 0.27 and 0.28, and similar for crossterm). That would be a lot of finicky work, though.

(Incidentally, I also buy into the reasoning that semver is often a joke beacuse it is a human that is deciding what is "major" and what is "minor", and it is extremely easy for API breaks to leak into minor releases accidentally)

joshka commented 2 months ago

Agreed on all of the above. The fix I'm going with (as mentioned in the macros issue) is to properly version this bump and yank the incompatible release. The problem with major version spanning releases is that rust dependency resolution picks up the latest version and then puts two versions in your dependency tree still. It doesn't pick just one version. This is usually ok except when things are in the public API or have "global" static state (both of which apply to crossterm).

If you haven't already, I'd suggest submitting a PR for the crokey update, it could be worth checking whether that also needs a major version bump to help avoid this problem there too.

joshka commented 2 months ago

Packages all updated - give them a whirl :)