#cargo-workspace #cargo #cargo-subcommand #changelog #version #releasing #automatic

bin+lib cargo-smart-release

Cargo subcommand for fearlessly releasing crates in workspaces

39 releases (20 breaking)

0.21.3 Jan 4, 2024
0.21.2 Oct 12, 2023
0.21.1 Aug 22, 2023
0.20.0 Jul 19, 2023
0.7.0 Nov 29, 2021

#123 in Cargo plugins

50 downloads per month

MIT/Apache

225KB
5K SLoC

cargo smart-release

Fearlessly release workspace crates and with beautiful semi-handcrafted changelogs.

asciicast

Key Features

  • zero-configuration
    • cargo smart-release needs no extra flags to do the right thing™️ smartly. If your intervention is needed it will let you know before it makes changes.
    • It won't do anything if there are no changes.
  • made for multi-crate workspaces
    • "Nothing stands by itself, and everything is interconnected" - is how it sees the world, allowing it to efficiently handling complex workspace graphs.
    • works just as well for single-crate workspaces
  • changelogs-deluxe
    • It maintains beautiful changelogs for you while allowing you to edit them for the final polish.
    • See your release notes via in-repository tag objects and in GitHub Releases
    • plays well with cargo release
      • cargo changelog writes changelogs non-destructively, and only that, leaving the release workflow to cargo-release.

If seeing is believing, here is a 12 minute demonstration, and the same in 30 minutes is also available.

Made for this Workflow

When developing various crates in a workspace, when committing changes and if the edit is breaking, a feature, or another change I want to see in changelogs, conventional git messages will be used. This helps building changelog scaffolding automatically later.

When ready for releasing a particular crate or set of crates of interest, run cargo smart-release [<crate-name> ...] to simulate a release. For particularly thorough but error-prone simulations (as in false positives) one could run cargo smart-release --dry-run-cargo-publish. To polish changelogs, run cargo changelog --write <crate-name> to update the scaffolding and edit it by hand until it fits.

After evaluating the release procedure and following instructions, cargo smart-release --execute will cause the fully automatic release of one or more crates.

There are various other options that shouldn't be needed in the common case, use cargo smart-release --help to see them.

Installation

Cargo

Via cargo, which can be obtained using rustup

cargo install cargo-smart-release

Features

  • safe to use as actually performing an operation requires the --execute flag
  • avoid inconsistent states by making operations as atomic as possible, leveraging gitoxide technology to the fullest
  • handle workspace dependencies and cycles gracefully, allowing one invocation to publish multiple crates
  • avoid making any releases if there are no changes
  • avoid bumping versions if the current version isn't released, allowing you to control the version by editing the cargo manifest
  • conventional commit message drive changelog scaffolding and to automatically derive the crate version to publish
  • automatically release dependent workspace IDP crates along with the desired one if they changed since their last release
  • automatically adjust manifest versions and update manifests of crates which use those whose versions were incremented
  • conservatively bump downstream workspace crates in the light of breaking changes, even though these won't be published, making downstream breakage impossible
  • use git tags to know if a crate changed at all, skipping publishes if there is no code change at all
  • it's too eager to release and there should be a way to control patch releases.
  • Handle pre-release versions, like 1.0.0-beta.1
  • Support other remote names than 'origin' - currently the latter name is assumed. Fix by getting the remote of the currently checked out branch.
  • handle version specifications correctly (tables vs values)
  • handle all version comparators correctly (see here for how it's done)
  • Automatically detect if crate changes are breaking to suggest the correct version increment

Comparison to cargo release

cargo-release is the reason this tool exists, as it got me addicted to an all automatic release workflow that knows git. This works perfectly for simple workspaces or single-crate workspaces, as of 2021-08-12, so use it: cargo install cargo-release.

Here is what cargo smart-release does differently: "It tries really hard to do what I want most of the time when publishing workspace gitoxide crates".

  • be safe to execute, so it's disarmed by default
  • specify one or more crates, and detect which crates need publishing automatically
  • handle dependency cycles in such a way that increases the chances of overall success
  • try really hard to not leave the workspace in an inconsistent state when something goes wrong
  • be a playground for gitoxide to have a reason to make it much more convenient and more feasible for application authors (aka dog-fooding)
  • create changelogs non-destructively, along with annotated tags and GitHub releases

Limitations

  • it requires tables to be used when specifying versions, i.e. crate = { version = "1" } instead of `crate = "1".
  • it gracefully fails when encountering version requirement comparators which are not ^, like =
  • it's tested only by using it on gitoxide, there are only very few regression tests with little coverage.
  • short object ids in changelogs may be ambiguous, as they are unconditionally truncated to 7 characters.
  • changelog rewriting of user content will drop links if they are not of the 'inline' form
  • it's very young and probably tries to eat underwear
  • it needs a git repository to govern the workspace

Changelogs

  • When determining if something changed in top-level crates, only the src/ directory is used, unless there is only a single crate in the workspace. This value is hard-coded.
  • For change tracking, it will only obtain manifest values once to know where a crate lives, and expects it to not be moved.
  • If list items populated by commit messages contain items themselves, round-tripping will fail. Ideally there was a way to parse an item on the same level only.

Acknowledgements

Thanks to cargo-release for showing the way and for incredible fast response times. I'd recommend everyone to participate there instead of writing your own.

Special thanks go to git-cliff which gave me the nudge needed to want to write my own.

Dependencies

~32–46MB
~740K SLoC