You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

245 lines
6.2 KiB

#!/bin/bash
set -eu
cd "$( dirname "${BASH_SOURCE[0]}" )/.."
version=
version_next=
main() {
local opt_auto=0
while [[ $# -gt 0 ]] ; do
case $1 in
-auto)
opt_auto=1
;;
*)
echo "Usage: $0 [-auto]" >&2
exit 0
;;
esac
shift
done
if [[ "$opt_auto" -eq 1 ]] ; then
auto_prepare_release
else
interactive
fi
}
auto_prepare_release() {
echo 'script/release: auto mode for CI, will check or modify version based on tag' >&2
assert_tree_clean
local is_tag=0
local version_tag=
if version_tag=$(git describe --candidates=0 --tags HEAD 2>/dev/null) ; then
is_tag=1
version_tag=${version_tag##v}
version_check "$version_tag"
fi
local last_tag=
local version_replace=
if [[ "$is_tag" -eq 0 ]] ; then
last_tag=$(git tag --sort=-version:refname |head -n1)
last_tag=${last_tag##v}
version_replace="${last_tag}.post$(date -u +%y%m%d%H%M)"
update_version "setup.py" "s/VERSION =.+/VERSION = \"$version_replace\"/"
update_version "python2/httplib2/__init__.py" "s/__version__ =.+/__version__ = \"$version_replace\"/"
update_version "python3/httplib2/__init__.py" "s/__version__ =.+/__version__ = \"$version_replace\"/"
version_check "$version_replace"
fi
}
interactive() {
echo 'script/release: interactive mode for creating new tagged releases with human assistance' >&2
local branch="${1-$(git symbolic-ref --short HEAD)}"
version="$(PYTHONPATH=$PWD/python3 python3 -c 'import httplib2; print(httplib2.__version__)')"
printf "\nbranch: %s httplib2.__version__: '%s'\n" $branch $version >&2
if [[ "$branch" != "master" ]] ; then
echo "Must be on master" >&2
exit 1
fi
assert_tree_clean
last_commit_message=$(git show --format="%s" --no-patch HEAD)
expect_commit_message="v$version release"
if [[ "$last_commit_message" != "$expect_commit_message" ]] ; then
printf "Last commit message: '%s' expected: '%s'\n" "$last_commit_message" "$expect_commit_message" >&2
if confirm "Create release commit? [yN] " ; then
create_commit
elif ! confirm "Continue without proper release commit? [yN] " ; then
exit 1
fi
fi
confirm "Continue? [yN] " || exit 1
echo "Creating tag v$version" >&2
if ! git tag "v$version" ; then
echo "git tag failed " >&2
confirm "Continue still? [yN] " || exit 1
fi
echo "Building package" >&2
find . -name '*.pyc' -o -name '*.pyo' -o -name '*.orig' -delete
rm -rf python{2,3}/.cache
rm -rf build dist
local venv=./venv-release
if [[ ! -d "$venv" ]] ; then
virtualenv $venv
$venv/bin/pip install -U check-manifest pip 'setuptools>=43.0' wheel twine
fi
$venv/bin/python setup.py clean --all
$venv/bin/python setup.py sdist bdist_wheel
$venv/bin/check-manifest || echo "FIXME check-manifest" >&2
if confirm "Upload to PyPI? Use in special situation, normally CI (Travis) will upload to PyPI. [yN] " ; then
$venv/bin/twine upload dist/* || exit 1
fi
git push --tags
}
create_commit() {
echo "" >&2
echo "Plan:" >&2
echo "1. bump version" >&2
echo "2. update CHANGELOG" >&2
echo "3. commit" >&2
echo "4. run bin/release again" >&2
echo "" >&2
bump_version
edit_news
git diff
confirm "Ready to commit? [Yn] " || exit 1
git commit -a -m "v$version_next release"
echo "Re-exec $0 to continue" >&2
exec $0
}
bump_version() {
local current=$version
echo "Current version: '$current'" >&2
echo -n "Enter next version (empty to abort): " >&2
read version_next
if [[ -z "$version_next" ]] ; then
exit 1
fi
echo "Next version: '$version_next'" >&2
update_version "python3/httplib2/__init__.py" "s/__version__ =.+/__version__ = \"$version_next\"/"
update_version "python2/httplib2/__init__.py" "s/__version__ =.+/__version__ = \"$version_next\"/"
update_version "setup.py" "s/VERSION =.+/VERSION = \"$version_next\"/"
confirm "Confirm changes? [yN] " || exit 1
}
update_version() {
local path="$1"
local sed_expr="$2"
# sed -E --in-place='' -e "s/VERSION =.+/VERSION = \"$version_replace\"/" setup.py
# sed -E --in-place='' -e "s/__version__ =.+/__version__ = \"$version_replace\"/" python2/httplib2/__init__.py python3/httplib2/__init__.py
echo "Updating file '$path'" >&2
if ! sed -E --in-place='' -e "$sed_expr" "$path" ; then
echo "sed error $?" >&2
exit 1
fi
assert_modified "$path"
echo "" >&2
}
edit_news() {
echo "Changes since last release:" >&2
git log --format='%h %an %s' "v$version"^.. -- || exit 1
echo "" >&2
patch -p1 <<EOT
diff a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -0,0 +1,4 @@
+$version_next
+
+ EDIT HERE. Describe important changes and link to more information.
+
EOT
local editor=$(which edit 2>/dev/null)
[[ -z "$editor" ]] && editor="$EDITOR"
if [[ -n "$editor" ]] ; then
if confirm "Open default editor for CHANGELOG? [Yn] " ; then
$editor CHANGELOG
else
confirm "Edit CHANGELOG manually and press any key"
fi
else
echo "Unable to determine default text editor." >&2
confirm "Edit CHANGELOG manually and press any key"
fi
echo "" >&2
assert_modified CHANGELOG
echo "" >&2
confirm "Confirm changes? [yN] " || exit 1
}
assert_modified() {
local path="$1"
if git diff --exit-code "$path" ; then
echo "File '$path' is not modified" >&2
exit 1
fi
}
assert_tree_clean() {
if [[ -n "$(git status --short -uall)" ]] ; then
echo "Tree must be clean. git status:" >&2
echo "" >&2
git status --short -uall
echo "" >&2
exit 1
fi
}
version_check() {
local need=$1
local version_setup=$(fgrep 'VERSION =' setup.py |tr -d " '\"" |cut -d\= -f2)
local version_py2=$(cd python2 ; python2 -Es -c 'import httplib2;print(httplib2.__version__)')
local version_py3=$(cd python3 ; python3 -Es -c 'import httplib2;print(httplib2.__version__)')
if [[ "$version_setup" != "$need" ]] ; then
echo "error: setup.py VERSION=$version_setup expected=$need" >&1
exit 1
fi
if [[ "$version_py2" != "$need" ]] ; then
echo "error: python2/httplib2/__init__.py:__version__=$version_py2 expected=$need" >&1
exit 1
fi
if [[ "$version_py3" != "$need" ]] ; then
echo "error: python3/httplib2/__init__.py:__version__=$version_py3 expected=$need" >&1
exit 1
fi
}
confirm() {
local reply
local prompt="$1"
read -n1 -p "$prompt" reply >&2
echo "" >&2
rc=0
local default_y=" \[Yn\] $"
if [[ -z "$reply" ]] && [[ "$prompt" =~ $default_y ]] ; then
reply="y"
fi
[[ "$reply" != "y" ]] && rc=1
return $rc
}
main "$@"