Create a gist now

Instantly share code, notes, and snippets.

@smoser /README.md
Last active Nov 22, 2017

What would you like to do?
log2dch: Create debian/changelog entries from a git or bzr log

log2dch: Create debian/changelog log entries from git or bzr logs

log2dch will read git or bzr logs and create debian changelog entries from them. It assumes that the commit messages 'git style' with a summary line like:

This is my summary line

Here is a longer message.
LP: #XXXXXX
LP: #XXXXXX

It has the following features:

  • Bug numbers are pulled out from either bzr --fixes metadata or git commit messages with LP: # entries as shown above.
  • Author of the commit are put into [Author Name] to give attribution.
  • Wraps lines somewhat intelligently at 80 characters wide. Does not break the line inside a (LP: ) or [Author Name].

Examples

  • bzr based simplestreams (bzr branch lp:simplestreams)

    $ bzr log -r-5.. | log2dch
      - Keystone v3 Support (LP: #1686437)
      - tools/ubuntu_versions.py: Exclude old versions by version not name
      - fix flake8
      - tests: change to having http server select its own port
      - flake8: fix style errors reported by pycodestyle 2.1.0
    
  • git based cloud-init (git clone http://git.launchpad.net/cloud-init)

    $ git log HEAD~5.. | log2dch
      - tests: execute: support command as string [Joshua Powers]
      - schema and docs: Add jsonschema to resizefs and bootcmd modules
        [Chad Smith]
      - tools: Add xkvm script, wrapper around qemu-system [Joshua Powers]
      - vmware customization: return network config format
       [Sankar Tanguturi] (LP: #1675063)
     - Ec2: only attempt to operate at local mode on known platforms.
       (LP: #1715128)
    
#!/bin/bash
VERBOSITY=0
TEMP_D=""
COMMIT_URL=${COMMIT_URL:-https://git.launchpad.net/cloud-init/commit/?id=}
error() { echo "$@" 1>&2; }
fail() { local r=$?; [ $r -eq 0 ] && r=1; failrc "$r" "$@"; }
failrc() { local r=$1; shift; [ $# -eq 0 ] || error "$@"; exit "$r"; }
Usage() {
cat <<EOF
Usage: ${0##*/} [ options ] [input-file]
Read input-file which is a git or bzr log and create a
debian/changelog formatted file from the result.
options:
--vcs VCS which log format is this ('git', 'auto', 'bzr')
default: auto
Assuming git style log commit messages, this reads the makes the
summary line into a debian/changelog style entry with author
in [] and mentions bugs fixed (bzr via '--fixes', git via LP: #
in commit messages.)
Examples:
* bzr based simplestreams (bzr branch lp:simplestreams)
$ bzr log -r-5.. | log2dch
- Keystone v3 Support (LP: #1686437)
- tools/ubuntu_versions.py: Exclude old versions by version not name
- fix flake8
- tests: change to having http server select its own port
- flake8: fix style errors reported by pycodestyle 2.1.0
* git based cloud-init (git clone http://git.launchpad.net/cloud-init)
$ git log HEAD~5.. | log2dch
- tests: execute: support command as string [Joshua Powers]
- schema and docs: Add jsonschema to resizefs and bootcmd modules
[Chad Smith]
- tools: Add xkvm script, wrapper around qemu-system [Joshua Powers]
- vmware customization: return network config format
[Sankar Tanguturi] (LP: #1675063)
- Ec2: only attempt to operate at local mode on known platforms.
(LP: #1715128)
EOF
}
bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; return 1; }
cleanup() {
[ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
}
debug() {
local level=${1}; shift;
[ "${level}" -gt "${VERBOSITY}" ] && return
error "${@}"
}
bzr_log_to_dch() {
local line="" commit="" bugs="" bug=""
local func="${1:-print_dch}"
while :; do
read line || break
case "$line" in
revno:\ *)
if [ -n "$commit" ]; then
$func "$commit" "$subject" "$author" "$bugs"
fi
commit=${line#*: }
bugs=""
author=""
subject=""
;;
author:*) author="${line#author: }";;
fixes\ bug:*)
# fixes bug: https://launchpad.net/bugs/1618429
bug="#${line##*/}"
bugs="${bugs:+${bugs}, }${bug}";;
message:)
read subject;;
esac
done
if [ -n "$commit" ]; then
$func "$commit" "$subject" "$author" "$bugs"
fi
}
print_hackio() {
local commit="$1" subject="$2" author="$3" bugs="$4" aname="" abugs=""
local buf="" bug="" t=""
local url="${COMMIT_URL}"
t=${commit#????????}
local bugmd="" pre=""
for bug in ${bugs}; do
bug=${bug%,}
[ -z "$bugmd" ] && pre="LP: "
bugmd="${bugmd}[$pre${bug}](https://pad.lv/$bug),"
done
bugmd=${bugmd%,}
t=${commit#????????}
buf="- ${bugmd:+${bugmd} }${subject}"
buf="${buf} \[[${commit%$t}]($url${commit%$t})\]"
echo "$buf"
}
print_trello() {
local commit="$1" subject="$2" author="$3" bugs="$4" aname="" abugs=""
local buf="" bug="" t=""
local url="${COMMIT_URL}"
t=${commit#????????}
buf="[${commit%$t}](${url}${commit%$t})"
for bug in ${bugs}; do
bug=${bug%,}
buf="${buf:+${buf} }[${bug}](http://pad.lv/$bug)"
done
buf="${buf:+${buf} }$subject"
echo "$buf"
}
print_dch() {
local commit="$1" subject="$2" author="$3" bugs="$4" aname="" abugs=""
local indent=" - " indent2=" " ll=79
local i=""
#( for i in ${bugs}; do echo ${i%,}; done); return
aname=${author% <*}
[ "${aname}" = "Scott Moser" ] && aname=""
abugs="${aname:+ [${aname}]}${bugs:+ (LP: ${bugs})}"
if [ $((${#subject}+${#abugs})) -le $((ll-${#indent})) ]; then
echo "${indent}${subject}${abugs}"
elif [ ${#subject} -ge $((ll-${#indent})) ]; then
echo "${subject}${abugs}" |
fmt --width=$((ll-${#indent})) |
sed -e "1s/^/${indent}/; 1n;" \
-e 's/^[ ]*//' \
-e '/^[ ]*$/d' -e "s/^/$indent2/" -e 's/[ ]\+$//'
else
( echo "${subject}"; echo "${abugs}" ) |
fmt --width=$((ll-${#indent})) |
sed -e "1s/^/${indent}/; 1n;" \
-e 's/^[ ]*//' \
-e '/^[ ]*$/d' -e "s/^/$indent2/" -e 's/[ ]\+$//'
fi
}
git_log_to_dch() {
local line="" commit="" bugs=""
local func=${1:-print_dch}
while :; do
read line || break
case "$line" in
commit\ *)
if [ -n "$commit" ]; then
"$func" "$commit" "$subject" "$author" "$bugs"
fi
commit=${line#commit }
bugs=""
author=""
subject=""
;;
Author:*) author="${line#Author: }";;
LP:*) bugs="${bugs:+${bugs}, }${line#*: }";;
"") [ -z "$subject" ] && read subject;;
esac
done
if [ -n "$commit" ]; then
$func "$commit" "$subject" "$author" "$bugs"
fi
}
assert_temp_d() {
TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") ||
fail "failed creating temp directory";
}
main() {
local short_opts="ht:v"
local long_opts="commit-url:,hackio,help,trello,vcs:,verbose"
local getopt_out=""
getopt_out=$(getopt --name "${0##*/}" \
--options "${short_opts}" --long "${long_opts}" -- "$@") &&
eval set -- "${getopt_out}" ||
{ bad_Usage; return; }
local cur="" next="" vcs="auto" input="-" omode="dch"
while [ $# -ne 0 ]; do
cur="$1"; next="$2";
case "$cur" in
-h|--help) Usage ; exit 0;;
--trello) omode="trello";;
--hackio) omode="hackio";;
--commit-url) COMMIT_URL="$next";;
-t|--vcs) vcs="$next";
case "$vcs" in
auto|git|bzr)
bad_Usage "vcs must be one of auto, git, bzr.";
return;;
esac
;;
-v|--verbose) VERBOSITY=$((VERBOSITY+1));;
--) shift; break;;
esac
shift;
done
[ $# -le 1 ] || { bad_Usage "got $# arguments, expected 0 or 1"; return; }
[ $# -eq 1 ] && { input="$1"; shift; }
trap cleanup EXIT
local oinput="$input"
if [ "$vcs" = "auto" ]; then
if [ "$input" = "-" ]; then
assert_temp_d
input="${TEMP_D}/input"
cat > "$input"
fi
if grep -q '^revno:' "$input"; then
vcs="bzr"
elif grep -q '^commit ' "$input"; then
vcs="git"
else
error "failed to figure out vcs type in $oinput"
return
fi
fi
if [ "$input" != "-" ]; then
exec < "$input" ||
{ error "failed to open $input for reading"; return 1; }
fi
case "$omode" in
trello) printer="print_trello";;
hackio) printer="print_hackio";;
*) printer="print_dch";;
esac
local func="${vcs}_log_to_dch"
"$func" "$printer"
return
}
main "$@"
# vi: ts=4 noexpandtab
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment