-
-
Notifications
You must be signed in to change notification settings - Fork 148
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(release): generate changelogs with
git-cliff
(#416)
We maintain separate changelogs for the `tokio-console`, `console-api`, and `console-subscriber` crates. Currently, changelogs are generated using the [`clog`] CLI tool. However, `clog` does not support generating separate changelogs for different subdirectories of a repo, so the current release process for a given crate requires generating a changelog for the whole repo since the last tag, and then manually editing it to remove changes to other crates. This is a pain. The [`git-cliff`] changelog-generating tool supports generating a changelog that only includes commits that modified specific paths in the repo. This means it can be used to generate separate changelogs for each crate automatically, unlike `clog`. It's also much more configurable, and we can use it to generate changelogs that have somewhat nicer formatting (IMO). This branch changes changelog generation from using `clog` to use `git-cliff`, and regenerates all the existing changelogs. The included `bin/update-changelog.sh` shell script updates the changelog for a given crate to the provided tag. This will make the release process much less complicated. A subsequent PR will add a shell script that handles updating crate versions, generating the changelog, and publishing the crate and tag, so that a release can be published by running a single command. [`clog`]: https://github.com/clog-tool/clog-cli [`git-cliff`]: https://git-cliff.org/
- Loading branch information
Showing
6 changed files
with
550 additions
and
144 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
#!/usr/bin/env bash | ||
# utility functions used in other shell scripts. | ||
# | ||
# currently, this includes: | ||
# - cargo-style stderr logging (`err`, `note`, and `status` functions) | ||
# - confirmation prompts (`confirm` function) | ||
set -euo pipefail | ||
|
||
# Log an error to stderr | ||
# | ||
# Args: | ||
# $1: message to log | ||
err() { | ||
echo -e "\e[31m\e[1merror:\e[0m" "$@" 1>&2; | ||
} | ||
|
||
# Log a note to stderr | ||
# | ||
# Args: | ||
# $1: message to log | ||
note() { | ||
echo -e "\e[31m\e[1mnote:\e[0m" "$@" 1>&2; | ||
} | ||
|
||
# Log a cargo-style status message to stderr | ||
# | ||
# Args: | ||
# $1: a "tag" for the log message (should be 12 characters or less in | ||
# length) | ||
# $2: message to log | ||
status() { | ||
local width=12 | ||
local tag="$1" | ||
local msg="$2" | ||
printf "\e[32m\e[1m%${width}s\e[0m %s\n" "$tag" "$msg" | ||
} | ||
|
||
# Prompt the user to confirm an action | ||
# | ||
# Args: | ||
# $1: message to display to the user along with the `[y/N]` prompt | ||
# | ||
# Returns: | ||
# 0 if the user confirmed, 1 otherwise | ||
confirm() { | ||
while read -r -p "$1 [Y/n] " input | ||
do | ||
case "$input" in | ||
[yY][eE][sS]|[yY]) | ||
return 0 | ||
;; | ||
[nN][oO]|[nN]) | ||
return 1 | ||
;; | ||
*) | ||
err "invalid input $input" | ||
;; | ||
esac | ||
done | ||
} | ||
|
||
# Returns the path to a Mycelium crate. | ||
# | ||
# Args: | ||
# $1: crate name | ||
# | ||
# Returns: | ||
# 0 if the crate exists, 0 if it does not exist. | ||
crate_path() { | ||
local crate="$1" | ||
local mycoprefix='mycelium-'; | ||
if [[ -d $crate ]]; then | ||
echo "$crate" | ||
elif [[ -d "${crate#"$mycoprefix"}" ]]; then | ||
echo "${crate#"$mycoprefix"}" | ||
else | ||
err "unknown crate $crate" | ||
return 1; | ||
fi | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
#!/usr/bin/env bash | ||
usage="Updates the changelog for a Tokio Console crate. | ||
USAGE: | ||
$(basename "$0") [FLAGS] <CRATE_PATH> <TAG> | ||
FLAGS: | ||
-h, --help Show this help text and exit. | ||
-v, --verbose Enable verbose output." | ||
|
||
set -euo pipefail | ||
|
||
bindir=$( cd "${BASH_SOURCE[0]%/*}" && pwd ) | ||
rootdir=$( cd "$bindir"/.. && pwd ) | ||
|
||
# shellcheck source=_util.sh | ||
. "$bindir"/_util.sh | ||
|
||
cd "$rootdir" | ||
|
||
verbose='' | ||
|
||
for arg in "$@" | ||
do | ||
case "$arg" in | ||
-h|--help) | ||
echo "$usage" | ||
exit 0 | ||
;; | ||
-v|--verbose) | ||
verbose="--verbose" | ||
;; | ||
-*) | ||
err "unknown flag $arg" | ||
echo "$usage" | ||
exit 1 | ||
;; | ||
*) # crate or version | ||
if [[ -z "${path+path}" ]]; then | ||
path="$arg" | ||
elif [[ -z "${tag+tag}" ]]; then | ||
tag="$arg" | ||
else | ||
err "unknown positional argument \"$arg\"" | ||
echo "$usage" | ||
exit 1 | ||
fi | ||
;; | ||
esac | ||
done | ||
|
||
if [[ -z "${path+path}" ]]; then | ||
err "no version specified!" | ||
errexit=1 | ||
fi | ||
|
||
if [[ -z "${tag+tag}" ]]; then | ||
err "no tag specified!" | ||
errexit=1 | ||
fi | ||
|
||
if [[ "${errexit+errexit}" ]]; then | ||
echo "$usage" | ||
exit 1 | ||
fi | ||
|
||
if ! [[ -x "$(command -v git-cliff)" ]]; then | ||
err "missing git-cliff executable" | ||
if confirm " install it?"; then | ||
cargo install git-cliff | ||
else | ||
echo "okay, exiting" | ||
exit 0 | ||
fi | ||
fi | ||
|
||
changelog_path="${path}/CHANGELOG.md" | ||
|
||
status "Updating" "$changelog_path for tag $tag" | ||
|
||
git_cliff=( | ||
git-cliff | ||
--include-path "${path}/**" | ||
--output "$changelog_path" | ||
--config cliff.toml | ||
--tag "$tag" | ||
) | ||
if [[ "$verbose" ]]; then | ||
git_cliff+=("$verbose") | ||
fi | ||
|
||
export GIT_CLIFF__GIT__TAG_PATTERN="${path}-v[0-9]*" | ||
"${git_cliff[@]}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
# git-cliff ~ default configuration file | ||
# https://git-cliff.org/docs/configuration | ||
# | ||
# Lines starting with "#" are comments. | ||
# Configuration options are organized into tables and keys. | ||
# See documentation for more information on available options. | ||
|
||
[changelog] | ||
# changelog header | ||
header = """ | ||
# Changelog\n | ||
All notable changes to this project will be documented in this file. | ||
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n | ||
""" | ||
# template for the changelog body | ||
# https://tera.netlify.app/docs/#introduction | ||
body = """ | ||
{% if version %}\ | ||
## {{ version | trim_start_matches(pat="v") }} - ({{ timestamp | date(format="%Y-%m-%d") }}) | ||
{% else %}\ | ||
## Unreleased | ||
{% endif %}\ | ||
{% if previous %}\ | ||
{% if previous.commit_id %} | ||
[{{ previous.commit_id | truncate(length=7, end="") }}](https://github.com/tokio-rs/console/commit/{{ previous.commit_id }})...\ | ||
[{{ commit_id | truncate(length=7, end="") }}](https://github.com/tokio-rs/console/commit/{{ commit_id }}) | ||
{% endif %}\ | ||
{% endif %} | ||
{% set has_breaking = false -%} | ||
{% for commit in commits -%} | ||
{% if commit.breaking -%} | ||
{% set_global has_breaking = true -%} | ||
{% endif -%} | ||
{% endfor -%} | ||
{% if has_breaking -%} | ||
### <a id = "{{ version }}-breaking"></a>Breaking Changes | ||
{% for commit in commits -%} | ||
{% if commit.breaking -%} | ||
- **{{ commit.message | upper_first }}** ([{{ commit.id | truncate(length=7, end="") }}](https://github.com/tokio-rs/console/commit/{{ commit.id }}))<br />{{ commit.breaking_description }} | ||
{% endif -%} | ||
{% endfor -%} | ||
{% endif -%} | ||
{% for group, commits in commits | group_by(attribute="group") %} | ||
### {{ group | upper_first }} | ||
{% for commit in commits %} | ||
- {% if commit.breaking %}[**breaking**](#{{ version }}-breaking) {% endif -%} {{ commit.message | upper_first }} (\ | ||
[{{ commit.id | truncate(length=7, end="") }}](https://github.com/tokio-rs/console/commit/{{ commit.id }})\ | ||
{% for link in commit.links -%} | ||
, {{ link.text }}({{ link.href }})\ | ||
{% endfor -%} | ||
)\ | ||
{% endfor %} | ||
{% endfor %}\n | ||
""" | ||
# remove the leading and trailing whitespace from the template | ||
trim = true | ||
# changelog footer | ||
footer = """ | ||
<!-- generated by git-cliff --> | ||
""" | ||
|
||
[git] | ||
# parse the commits based on https://www.conventionalcommits.org | ||
conventional_commits = true | ||
# filter out the commits that are not conventional | ||
filter_unconventional = true | ||
# process each line of a commit as an individual commit | ||
split_commits = false | ||
# regex for preprocessing the commit messages | ||
commit_preprocessors = [ | ||
{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](https://github.com/tokio-rs/console/issues/${2}))"}, # replace issue numbers | ||
] | ||
# regex for parsing and grouping commits | ||
commit_parsers = [ | ||
{ message = "^feat", group = "Added" }, | ||
{ message = "^fix", group = "Fixed" }, | ||
{ message = "^doc", group = "Documented" }, | ||
{ message = "^perf", group = "Performance" }, | ||
{ message = "^refactor", skip = true }, | ||
{ message = "^refac", skip = true }, | ||
{ message = "^style", skip = true }, | ||
{ message = "^test", skip = true }, | ||
{ message = "^chore\\(release\\)", skip = true }, | ||
{ message = "[Pp]repare to release", skip = true }, | ||
{ message = "^chore", skip = true }, | ||
{ body = ".*security", group = "Security" }, | ||
{ body = ".*[dD]eprecate.*", group = "Deprecated" }, | ||
# older non-conventional commits | ||
{ message = "^subscriber:", group = "Added" }, | ||
{ message = "^console:", group = "Added" }, | ||
{ message = "^api:", group = "Added" }, | ||
{ message = "^example:", group = "Documented" }, | ||
] | ||
# protect breaking changes from being skipped due to matching a skipping commit_parser | ||
protect_breaking_commits = false | ||
# filter out the commits that are not matched by commit parsers | ||
filter_commits = false | ||
# regex for skipping tags | ||
# skip_tags = "v0.1.0-beta.1" | ||
# regex for ignoring tags | ||
ignore_tags = "" | ||
# sort the tags topologically | ||
topo_order = false | ||
# sort the commits inside sections by oldest/newest order | ||
sort_commits = "oldest" | ||
# limit the number of commits included in the changelog. | ||
# limit_commits = 42 | ||
|
||
link_parsers = [ | ||
{ pattern = "[fF]ixes #(\\d+)", text = "fixes [#${1}]", href = "https://github.com/tokio-rs/console/issues/$1"}, | ||
{ pattern = "[cC]loses #(\\d+)", text = "closes [#${1}]", href = "https://github.com/tokio-rs/console/issues/$1"}, | ||
{ pattern = "[sS]ee #(\\d+)", text = "see [#${1}]", href = "https://github.com/tokio-rs/console/issues/$1"}, | ||
] |
Oops, something went wrong.