Releasing new versions of your projects is one of the more laborious tasks of an open source maintainer. There are many great tools that automate part of this process, but typically there are still a lot of manual steps involved. In addition, there are lots of things that can go wrong. New bugs might have been introduced, dependency updates can go wrong, the automatic deployment might not work anymore.

After some practice with three of my Rust projects (fd, hyperfine and bat), my workflow has converged to something that works quite well and avoids many pitfalls that I have walked into in the past. My hope in writing this post is that this process can be useful for others as well.

The following is my release checklist for fd, but I have very similar lists for other projects. It is important to take the steps in the given order.

Check and update dependencies. a) Use cargo outdated to check for outdated dependencies. deps.rs can also be used to get the same information.

b) Run cargo update to update dependencies to the latest compatible (minor) version.

c) If possible and useful, manually update to new major versions. As for updates to new major versions, take a look at the upstream changes and carefully evaluate if an update is necessary (now).

Get the list of updates since the last release. Go to GitHub -> Releases -> "XX commits to master since this release" to get an overview of all changes since the last release. Example: fd/compare/v7.1.0...master

Update the documentation. a) Review and update the -h and --help text.

b) Update the README (program usage, document new features, update minimum required Rust version)

c) Update the man page.

Install the latest master locally and test new features. a) Run cargo install -f .

b) Test the new features manually.

c) Run benchmarks to avoid performance regressions. In an ideal world, we have written tests for all of the new code. These tests also run in our CI pipeline, so there is nothing to worry about, right? In my experience, there are always things that need to be reviewed manually. This is especially true for CLI tools that are more difficult to test due to their intricate dependencies on the interactive terminal environment.

Clean up the code base. a) Run cargo clippy and review the suggested changes [Optional]

b) Run cargo fmt to auto-format your code.

c) Run cargo test to make sure that all tests still pass. The last two steps are typically automated in my CI pipeline. They are included here for completeness.

Bump version information. a) Update the project version in Cargo.toml

b) Run cargo build to update Cargo.lock

c) Search the whole repository for the old version and update as required (README, install instructions, build scripts, ..) Forgetting to also update Cargo.lock has prevented me from successfully publishing to crates.io in the past.

Dry run for cargo publish . cargo publish --dry-run --allow-dirty Running cargo publish is one of the last steps in the release process. Using the dry-run functionality at this stage can avoid later surprises.

Commit, push, and wait for CI to succeed. git push all the updates from the last steps and wait until CI has passed. I used to immediately tag my "version update" commit to start the automated deployment. Having this intermediate "wait for CI" step has definitely prevented some failed releases.

Write release notes. While waiting for CI to finish, I already start to write the release notes. I go through the list of updates and categorize changes into "Feature", "Change", "Bugfix" or "Other". I typically include links to the relevant Github issues and try to credit the original authors.

Tag the latest commit and start deployment. git tag vX.Y.Z; git push --tags This assumes that the CI pipeline has been set up to take care about the actual deployment (upload binaries to GitHub).

Create the release. Create the actual release on GitHub and copy over the release notes.

Verify the deployment. Make sure that all binaries have been uploaded. Manually test the binaries, if possible.

Publish to crates.io. Make sure that your repository is clean or clone a fresh copy of the repository. Then run cargo publish Do this after the git push --tags step. A git tag can be deleted if something goes wrong with the cargo publish call, but cargo publish can not be undone if the deployment via git push --tags fails.