summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEliza Weisman <eliza@buoyant.io>2019-07-03 10:18:02 -0700
committerGitHub <noreply@github.com>2019-07-03 10:18:02 -0700
commitbd9760e124d9facb40a2cb86fdb18fdff2abae1f (patch)
tree2725e3dfbcf5304a87099a5e01bc2d31d5110e7e
parent3e898f58a56630643b4dad529cdfd61c026b584f (diff)
add release documentation to CONTRIBUTING.md (#1171)
## Motivation Currently, the process for releasing a new version of a Tokio crate is somewhat complex, and is not well-documented. To make it easier for contributors to release minor versions more frequently, there should be documentation describing this process. ## Solution This branch adds a section to `CONTRIBUTING.md` describing how to release a new version of a Tokio crate. The steps are based on those described by @carllerche in an offline conversation. I've also added a quick shell script to actually publish new crate versions. This should make it harder to make mistakes when publishing. Signed-off-by: Eliza Weisman <eliza@buoyant.io>
-rw-r--r--CONTRIBUTING.md60
-rwxr-xr-xbin/publish117
2 files changed, 177 insertions, 0 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index da207a2b..8bd28043 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -381,3 +381,63 @@ _Adapted from the [Node.js contributing guide][node]_.
[node]: https://github.com/nodejs/node/blob/master/CONTRIBUTING.md
[hiding-a-comment]: https://help.github.com/articles/managing-disruptive-comments/#hiding-a-comment
[documentation test]: https://doc.rust-lang.org/rustdoc/documentation-tests.html
+
+## Releasing
+
+Since the Tokio project consists of a number of crates, many of which depend on
+each other, releasing new versions to crates.io can involve some complexities.
+When releasing a new version of a crate, follow these steps:
+
+1. **Ensure that the release crate has no path dependencies.** When the HEAD
+ version of a Tokio crate requires unreleased changes in another Tokio crate,
+ the crates.io dependency on the second crate will be replaced with a path
+ dependency. Crates with path dependencies cannot be published, so before
+ publishing the dependent crate, any path dependencies must also be published.
+ This should be done through a form of depth-first tree traversal:
+
+ 1. Starting with the first path dependency in the crate to be released,
+ inspect the `Cargo.toml` for the dependency. If the dependency has any
+ path dependencies of its own, repeat this step with the first such
+ dependency.
+ 2. Begin the release process for the path dependency.
+ 3. Once the path dependency has been published to crates.io, update the
+ dependent crate to depend on the crates.io version.
+ 4. When all path dependencies have been published, the dependent crate may
+ be published.
+
+ To verify that a crate is ready to publish, run:
+
+ ```bash
+ bin/publish --dry-run <CRATE NAME> <CRATE VERSION>
+ ```
+
+2. **Update Cargo metadata.** After releasing any path dependencies, update the
+ `version` field in `Cargo.toml` to the new version, and the `documentation`
+ field to the docs.rs URL of the new version.
+3. **Update other documentation links.** Update the `#![doc(html_root_url)]`
+ attribute in the crate's `lib.rs` and the "Documentation" link in the crate's
+ `README.md` to point to the docs.rs URL of the new version.
+4. **Update the changelog for the crate.** Each crate in the Tokio repository
+ has its own `CHANGELOG.md` in that crate's subdirectory. Any changes to that
+ crate since the last release should be added to the changelog. Change
+ descriptions may be taken from the Git history, but should be edited to
+ ensure a consistent format, based on [Keep A Changelog][keep-a-changelog].
+ Other entries in that crate's changelog may also be used for reference.
+5. **Perform a final audit for breaking changes.** Compare the HEAD version of
+ crate with the Git tag for the most recent release version. If there are any
+ breaking API changes, determine if those changes can be made without breaking
+ existing APIs. If so, resolve those issues. Otherwise, if it is necessary to
+ make a breaking release, update the version numbers to reflect this.
+6. **Open a pull request with your changes.** Once that pull request has been
+ approved by a maintainer and the pull request has been merged, continue to
+ the next step.
+7. **Release the crate.** Run the following command:
+
+ ```bash
+ bin/publish <NAME OF CRATE> <VERSION>
+ ```
+
+ Your editor and prompt you to edit a message for the tag. Copy the changelog
+ entry for that release version into your editor and close the window.
+
+[keep-a-changelog]: https://github.com/olivierlacan/keep-a-changelog/blob/master/CHANGELOG.md
diff --git a/bin/publish b/bin/publish
new file mode 100755
index 00000000..df0669f4
--- /dev/null
+++ b/bin/publish
@@ -0,0 +1,117 @@
+#!/usr/bin/env bash
+set -e
+USAGE="Publish a new release of a tokio crate
+
+USAGE:
+ $(basename "$0") [OPTIONS] [CRATE] [VERSION]
+
+OPTIONS:
+ -v, --verbose Use verbose Cargo output
+ -d, --dry-run Perform a dry run (do not publish or tag the release)
+ -h, --help Show this help text and exit"
+
+DRY_RUN=""
+VERBOSE=""
+
+err() {
+ echo -e "\e[31m\e[1merror:\e[0m $@" 1>&2;
+}
+
+status() {
+ WIDTH=12
+ printf "\e[32m\e[1m%${WIDTH}s\e[0m %s\n" "$1" "$2"
+}
+
+verify() {
+ status "Verifying" "if $CRATE v$VERSION can be released"
+ ACTUAL=$(cargo pkgid | sed -n 's/.*#\(.*\)/\1/p')
+
+ if [ "$ACTUAL" != "$VERSION" ]; then
+ err "expected to release version $VERSION, but Cargo.toml contained $ACTUAL"
+ exit 1
+ fi
+
+ if git tag -l | grep -Fxq "$TAG" ; then
+ err "git tag \`$TAG\` already exists"
+ exit 1
+ fi
+
+ PATH_DEPS=$(grep -F "path = \"" Cargo.toml | sed -e 's/^/ /')
+ if [ -n "$PATH_DEPS" ]; then
+ err "crate \`$CRATE\` contained path dependencies:\n$PATH_DEPS"
+ echo "path dependencies must be removed prior to release"
+ exit 1
+ fi
+}
+
+release() {
+ status "Releasing" "$CRATE v$VERSION"
+ cargo package $VERBOSE
+ cargo publish $VERBOSE $DRY_RUN
+
+ status "Tagging" "$TAG"
+ if [ -n "$DRY_RUN" ]; then
+ echo "# git tag $TAG && git push --tags"
+ else
+ git tag "$TAG" && git push --tags
+ fi
+}
+
+while [[ $# -gt 0 ]]
+do
+
+case "$1" in
+ -v|--verbose)
+ VERBOSE="--verbose"
+ set +x
+ shift
+ ;;
+ -d|--dry-run)
+ DRY_RUN="--dry-run"
+ shift
+ ;;
+ -*)
+ err "unknown flag \"$1\""
+ echo "$USAGE"
+ exit 1
+ ;;
+ *) # crate or version
+ if [ -z "$CRATE" ]; then
+ CRATE="$1"
+ elif [ -z "$VERSION" ]; then
+ VERSION="$1"
+ else
+ err "unknown positional argument \"$1\""
+ echo "$USAGE"
+ exit 1
+ fi
+ shift
+ ;;
+esac
+done
+# set -- "${POSITIONAL[@]}"
+
+if [ -z "$VERSION" ]; then
+ err "no version specified!"
+ HELP=1
+fi
+
+if [ -n "$CRATE" ]; then
+ TAG="$CRATE-$VERSION"
+else
+ err "no crate specified!"
+ HELP=1
+fi
+
+if [ -n "$HELP" ]; then
+ echo "$USAGE"
+ exit 1
+fi
+
+if [ -d "$CRATE" ]; then
+ (cd "$CRATE" && verify && release )
+else
+ err "no such crate \"$CRATE\""
+ exit 1
+fi
+