From f11eaaea6f9f3af237d3cd5cd5ce0e317f15ed8b Mon Sep 17 00:00:00 2001 From: Nicolas Sebrecht Date: Sat, 14 Mar 2015 15:45:56 +0100 Subject: [PATCH] contrib: introduce script to make new releases Signed-off-by: Nicolas Sebrecht --- contrib/release.sh | 432 ++++++++++++++++++++++++++++++++++++++++ docs/website-doc.sh | 1 + offlineimap/__init__.py | 2 +- 3 files changed, 434 insertions(+), 1 deletion(-) create mode 100755 contrib/release.sh diff --git a/contrib/release.sh b/contrib/release.sh new file mode 100755 index 0000000..0bf0444 --- /dev/null +++ b/contrib/release.sh @@ -0,0 +1,432 @@ +#!/bin/sh +# +# Put into Public Domain, by Nicolas Sebrecht +# +# Create new releases in OfflineIMAP. + +# TODO: https://developer.github.com/v3/repos/releases/#create-a-release +# https://developer.github.com/libraries/ +# https://github.com/turnkeylinux/octohub +# https://github.com/michaelliao/githubpy (onefile) +# https://github.com/sigmavirus24/github3.py +# https://github.com/copitux/python-github3 +# https://github.com/PyGithub/PyGithub +# https://github.com/micha/resty (curl) + +# TODO: move configuration out and source it. +# TODO: implement rollback. + +__VERSION__='v0.1' + +SEND_BY_MAIL='git send-email' +SPHINXBUILD=sphinx-build + +MAILING_LIST='offlineimap-project@lists.alioth.debian.org' + +DOCSDIR='docs' +ANNOUNCE_MAGIC='#### Notes ' +CHANGELOG_MAGIC='{:toc}' +CHANGELOG='Changelog.md' +CACHEDIR='.git/offlineimap-release' +WEBSITE='website' +WEBSITE_LATEST="${WEBSITE}/_data/latest.yml" + +TMP_CHANGELOG_EXCERPT="${CACHEDIR}/changelog.excerpt.md" +TMP_CHANGELOG_EXCERPT_OLD="${TMP_CHANGELOG_EXCERPT}.old" +TMP_CHANGELOG="${CACHEDIR}/changelog.md" +TMP_ANNOUNCE="${CACHEDIR}/announce.txt" + +True=0 +False=1 +Yes=$True +No=$False + +DEBUG=$True + +# +# $1: EXIT_CODE +# $2..: message +function die () { + n=$1 + shift + echo $* + exit $n +} + + +function debug () { + if test $DEBUG -eq $True + then + echo "DEBUG: $*" >&2 + fi +} + + + +# +# $1: question +# $2: message on abort +# +function ask () { + echo + echo -n "--- $1 " + read -r ans + test "n$ans" = 'n' -o "n$ans" = 'ny' && return $Yes + test "n$ans" = "ns" -o "n$ans" = 'nn' && return $No + die 1 "! $2" +} + + + +# +# $1: message +# $1: path to file +# +function edit_file () { + ask "Press Enter to $1" + test $? -eq $Yes && { + $EDITOR "$2" + reset + } +} + + + +function fix_pwd () { + debug 'in fix_pwd' + if test ! -d .git -a ! -f offlineimap.py + then + test "$PWD" = '/' && die 2 "You're not in the offlineimap repository..." + cd .. + fix_pwd + fi +} + + +function prepare_env () { + debug 'in prepare_env' + mkdir "$CACHEDIR" 2>/dev/null + test ! -d "$CACHEDIR" && die 5 "Could not make cache directory $CACHEDIR" +} + + +function check_dirty () { + debug 'in check_dirty' + git diff --quiet 2>/dev/null && git diff --quiet --cached 2>/dev/null || { + die 4 "Commit all your changes first!" + } +} + + +function welcome () { + debug 'in welcome' +cat <' : yes, continue +- 'n' : no +- 's' : skip (ONLY where applicable, otherwise continue) + +Any other key will abort the program. +EOF + ask 'Ready?' +} + + +function checkout_next () { + debug 'in checkout_next' + git checkout --quiet next || { + die 6 "Could not checkout 'next' branch" + } +} + + +function get_version () { + debug 'in get_version' + echo "v$(./offlineimap.py --version)" +} + + +function update_offlineimap_version () { + debug 'in update_offlineimap_version' + edit_file 'update the version in __init__.py' offlineimap/__init__.py +} + + +# +# $1: previous version +# +function get_shortlog () { + debug 'in get_shortlog' + git shortlog "${1}.." | grep -v '^[^ ]' | sed -r -e 's,^[ ]*,\- ,' +} + + +# +# $1: new version +# $2: shortlog +function changelog_template () { + debug 'in changelog_template' + cat < "$TMP_CHANGELOG_EXCERPT" + get_shortlog "$2" >> "$TMP_CHANGELOG_EXCERPT" + edit_file "the Changelog excerpt" $TMP_CHANGELOG_EXCERPT + + # Remove comments. + grep -v '//' "$TMP_CHANGELOG_EXCERPT" > "${TMP_CHANGELOG_EXCERPT}.nocomment" + mv -f "${TMP_CHANGELOG_EXCERPT}.nocomment" "$TMP_CHANGELOG_EXCERPT" + fi + + # Write new Changelog. + cat "$CHANGELOG" > "$TMP_CHANGELOG" + debug "include excerpt $TMP_CHANGELOG_EXCERPT to $TMP_CHANGELOG" + sed -i -e "/${CHANGELOG_MAGIC}/ r ${TMP_CHANGELOG_EXCERPT}" "$TMP_CHANGELOG" + debug 'remove trailing whitespaces' + sed -i -r -e 's, +$,,' "$TMP_CHANGELOG" # Remove trailing whitespaces. + debug "copy to $TMP_ANNOUNCE -> $CHANGELOG" + cp -f "$TMP_CHANGELOG" "$CHANGELOG" + + # Check and edit Changelog. + ask "Next step: you'll be asked to review the diff of $CHANGELOG" + action=$No + while test ! $action -eq $Yes + do + git diff -- "$CHANGELOG" | less + ask 'edit Changelog?' $CHANGELOG + action=$? + done +} + + +# +# $1: new version +# +function git_release () { + debug 'in git_release' + git commit -as -m"$1" + git tag -a "$1" -m"$1" + git checkout master + git merge next + git checkout next +} + + +function get_last_rc () { + git tag | grep -E '^v([0-9][\.-]){3}rc' | sort -n | tail -n1 +} + +# +# $1: new version +# +function update_website_releases_info() { + cat > "$WEBSITE_LATEST" < /dev/null 2>&1 && { + cd website || echo "ERROR: cannot go to website" + git diff --quiet 2>/dev/null && git diff --quiet --cached 2>/dev/null || { + echo "There is WIP in the website repository, stashing" + echo "git stash create 'WIP during offlineimap API import'" + git stash create 'WIP during offlineimap API import' + } + cd "../$DOCSDIR" + make websitedoc && { + cd ../website && { + branch_name="import-$1" + git checkout -b "$branch_name" + git add '_doc/versions' + git commit -s -m"doc: import of developer documentation for offlineimap $1" + git checkout master + git merge "$branch_name" + echo "website: master branch ready for a push!" + } + } + } || { + echo "Oops! you don't have $SPHINXBUILD installed?" + echo "Cannot update the webite documentation..." + echo "You should install it and run:" + echo " $ cd docs" + echo " $ make websitedoc" + echo "Then, commit and push changes of the website." + } + ask 'continue' + fi +} + + +function git_username () { + git config --get user.name +} +function git_usermail () { + git config --get user.email +} + +# +# $1: new version +# +function announce_header () { + cat < +Date: $(git log HEAD~1.. --oneline --pretty='%cD') +From: $(git_username) <$(git_usermail)> +To: $MAILING_LIST +Subject: [ANNOUNCE] OfflineIMAP $1 released + +OfflineIMAP $1 is out. + +Downloads: + http://github.com/OfflineIMAP/offlineimap/archive/${1}.tar.gz + http://github.com/OfflineIMAP/offlineimap/archive/${1}.zip + +EOF +} + + +# +# $1: previous version +# +function announce_footer () { + cat < "$TMP_ANNOUNCE" + cat "$TMP_CHANGELOG_EXCERPT" >> "$TMP_ANNOUNCE" + sed -i -r -e "s,^$ANNOUNCE_MAGIC,," "$TMP_ANNOUNCE" + announce_footer "$2" >> "$TMP_ANNOUNCE" +} + + +function edit_announce () { + edit_file 'edit announce' "$TMP_ANNOUNCE" +} + + +function send_announce () { + ask 'Press Enter to to send announce' + test $? -eq $Yes && $SEND_BY_MAIL "$TMP_ANNOUNCE" +} + + +function clear_env () { + rm -f "$TMP_CHANGELOG_EXCERPT" +} + + + +function run () { + debug 'in run' + fix_pwd + check_dirty + prepare_env + checkout_next + clear + welcome + + if test -f "$TMP_CHANGELOG_EXCERPT" + then + head "$TMP_CHANGELOG_EXCERPT" + ask "A previous Changelog excerpt (head above) was found, use it?" + if test ! $? -eq $Yes + then + mv -f "$TMP_CHANGELOG_EXCERPT" "$TMP_CHANGELOG_EXCERPT_OLD" + fi + fi + + previous_version="$(get_version)" + message="Safety check: release after version:" + ask "$message $previous_version ?" + update_offlineimap_version + new_version="$(get_version)" + ask "Safety check: make a new release with version: '$new_version'" "Clear changes and restart" + + update_changelog "$new_version" "$previous_version" + build_announce "$new_version" "$previous_version" + edit_announce + + git_release $new_version + + update_website $new_version + send_announce + clear_env +} + +run +cat < "$VERSIONS_YML" for version in $(ls "$DESTBASE" -1 | sort -nr) do diff --git a/offlineimap/__init__.py b/offlineimap/__init__.py index 441af44..d0bd0b5 100644 --- a/offlineimap/__init__.py +++ b/offlineimap/__init__.py @@ -3,7 +3,7 @@ __all__ = ['OfflineImap'] __productname__ = 'OfflineIMAP' __version__ = "6.5.7" __revision__ = "-rc2" -__bigversion__ = __version__ + __revision__ +__bigversion__ = __version__ + __revision__ __copyright__ = "Copyright 2002-2015 John Goerzen & contributors" __author__ = "John Goerzen" __author_email__= "john@complete.org"