mk-changelog: small changelog script
Introduction
Cogitri approached me with a problem, he is writing amazing projects such as gxi and tmplgen and he is a big fan of the AngularJS git commit guidelines.
So he adopted those guidelines for his projects and so far it has been working out fine for him, but he now wants to create release notes using those commits, but sadly all generators he found were heavyweight and feature-packed, he wanted something simple he could stick in his new release script and be done with it.
Requirements
He asked me for it to be:
- Simple
- Light
- Apply to all commits between 2 tags or master and 1 tag
- Output content similar to markdown
- Easy to embed in his script
- Deal with the 'fix' and 'feat' fields only
Writing it down
Seems easy enough, i decided to use bash
and git
to deal with it,
knowing it would be run from his release scripts.
Dealing with arguments
I'm not going to assume a bad input will be sent, it is inside a script that will be called with known values.
#!/usr/bin/env bash # # Takes 2 tags and get all commits between them and turns # it into a release notes based on AngularJS style if [ -z "$1" ]; then echo "Need a starting tag" >&2 exit 1 fi stag="$1" if [ "$2" ]; then ftag="$2" else ftag=master fi
Getting all the commits
Now we get all the commit between the 2 tags and make use of the fact that AngularJS commit guidelines dictate what is written at the start to get the correct commit categories.
commits="$(git log --pretty='%s' ${ftag}...${stag})" feats=() # New Features fixes=() # Fixes while read -r c; do # Add all features to the array if grep -q '^feat(.*): ' <<< "$c"; then feats+=("${c#*feat}") continue fi if grep -q '^fix(.*): ' <<< "$c"; then fixes+=("${c#*fix}") continue fi done <<< "$commits"
Notice the use of arrays and variable substitution, it is such a nice underused thing that saves a lot of writing and the fact bash can do a while-do-done loop without needing to create a subshell.
Writing it out
We now write out the results in the markdown-like format it was required of us.
if [ ${#feats[@]} -eq 0 ]; then echo " - No new features" else for c in "${feats[@]}"; do printf "%s\\n" " - $c" done fi echo "" printf "%s\\n\\n" "## Bugfixes" if [ ${#fixes[@]} -eq 0 ]; then echo " - No bugfixes" else for c in "${fixes[@]}"; do printf "%s\\n" " - $c" done fi
Commits vs Results.
Here is a comparison of the commits to the result given to us.
git log --pretty='%s' master...v0.4.6
feat(edit_view): add newline to end of the file if it doesn't terminate with one chore(deps): bump serde{,_derive} from 1.0.86 to 1.0.87 feat(edit_view): only draw trailing spaces fix(pref_storage): don't implement Clone for Config<T> fix(main): fix loading config fix(main): don't load config twice chore(deps): bump serde_json from 1.0.37 to 1.0.38 chore(deps): bump serde_derive from 1.0.85 to 1.0.86 chore(deps): bump proc-macro2 from 0.4.26 to 0.4.27 chore(deps): bump rand_jitter from 0.1.1 to 0.1.2 fix(linecache): fix linecount for wrapped lines chore(deps): bump serde from 1.0.85 to 1.0.86 fix(ui): re-enable word wrapping, it's pretty complete now fix(pref_storage): DO NOT clone Config to make sure it's consistent across different windows fix(edit_view): send 'resize' to xi upon allocating a new size fix(rpc): correctly handle measure_width feat(shared_queue): also use for sending stuff to xi feat(gettext): build against system gettext chore(README): add travis build badge fix(meson): only validate appstream if appstream-util is recent enough chore(ci): use meson instead of cargo
mk-changelog v0.4.6
## Feature changes - (edit_view): add newline to end of the file if it doesn't terminate with one - (edit_view): only draw trailing spaces - (shared_queue): also use for sending stuff to xi - (gettext): build against system gettext ## Bugfixes - (pref_storage): don't implement Clone for Config<T> - (main): fix loading config - (main): don't load config twice - (linecache): fix linecount for wrapped lines - (ui): re-enable word wrapping, it's pretty complete now - (pref_storage): DO NOT clone Config to make sure it's consistent across different windows - (edit_view): send 'resize' to xi upon allocating a new size - (rpc): correctly handle measure_width - (meson): only validate appstream if appstream-util is recent enough
Working just fine.
The script
Here is the whole script if you want it, i consider it done, unless bug appears i won't touch it, it is licensed under the MIT license.
#!/usr/bin/env bash # # Takes 2 tags and get all commits between them and turns # it into a release notes based on AngularJS style if [ -z "$1" ]; then echo "Need a starting tag" >&2 exit 1 fi stag="$1" if [ "$2" ]; then ftag="$2" else ftag=master fi commits="$(git log --pretty='%s' ${ftag}...${stag})" feats=() # New Features fixes=() # Fixes while read -r c; do # Add all features to the array if grep -q '^feat(.*): ' <<< "$c"; then feats+=("${c#*feat}") continue fi if grep -q '^fix(.*): ' <<< "$c"; then fixes+=("${c#*fix}") continue fi done <<< "$commits" printf "%s\\n\\n" "## Feature changes" if [ ${#feats[@]} -eq 0 ]; then echo " - No new features" else for c in "${feats[@]}"; do printf "%s\\n" " - $c" done fi echo "" printf "%s\\n\\n" "## Bugfixes" if [ ${#fixes[@]} -eq 0 ]; then echo " - No bugfixes" else for c in "${fixes[@]}"; do printf "%s\\n" " - $c" done fi