#!/bin/bash if [ ! -f ./scripts/run_tests.sh ] then echo "Error: ./scripts/run_tests.sh not found" exit 1 fi if [ ! -f setup.cfg ] then echo "Error: setup.cfg not found" exit 1 fi function warn_todos() { local todos=0 todos="$(grep -nri TODO twnet_parser | wc -l)" if [ "$todos" == "0" ] then return fi echo "<============ TODOS" echo "..." grep --color=always -nri TODO twnet_parser | tail -n2 echo "<============ TODOS" echo "Warning: there are $todos open todos!" echo " doing a major release with open todos" echo " is not recommended!" echo "Do you really want to continue? [y/N]" read -r -n1 yn if ! [[ "$yn" =~ [yY] ]] then echo "aborting ..." exit 0 fi } if ! git diff-index --quiet --cached HEAD -- then echo "Error: dirty git working tree" exit 1 fi if [ "$(git rev-parse --abbrev-ref HEAD)" != "master" ] then echo "Error: can only release from master branch" exit 1 fi echo "This script will create a git tag, git commit and a pypi release" echo "Do you really want to run that? [y/N]" read -r -n1 yn if ! [[ "$yn" =~ [yY] ]] then echo "aborting ..." exit 0 fi if [ ! -f .env ] then ( echo "# get it from https://pypi.org/manage/account/token/" echo 'PYPI_TOKEN=' ) > .env fi if ! pypi_token="$(grep PYPI_TOKEN= .env | cut -d'=' -f2-)" then echo "Error: failed to load env file" exit 1 fi if [ "$pypi_token" == "" ] then echo "Error: pypi token unset check your .env file" exit 1 fi if [ ! -x "$(command -v twine)" ] then echo "Error: command twine not found. Make sure to run:" echo "" echo " pip install -r requirements/dev.txt" echo "" exit 1 fi if ! latest_tag="$(git tag | sort -V | tail -n1)" then echo "Error: failed to get latest tag" exit 1 fi echo "" echo "" echo "" echo "===================================================================" echo "current tag names:" git tag | sort -V | awk '{ print " " $0 }' echo "===================================================================" echo "How to pick a tag name?" echo " - change lib user facing api -> at least minor version bump" echo " - adding a feature or a new api -> does NOT require a minor bump" echo " - change internal (local variables etc) api -> patch version bump" echo " - drastic user affecting change -> major version bump" echo "Only a patch version change should NEVER break a users code" echo "===================================================================" read -r -p "tag name: " -i "$latest_tag" -e tag_name if [ "$tag_name" == "" ] then echo "Error: tag name can not be empty" exit 1 fi if [ "$tag_name" == "$latest_tag" ] then echo "Error: please use a new tag version" exit 1 fi if [ "$(git tag -l "$tag_name")" != "" ] then echo "Error: tag already exists" exit 1 fi if [ "${tag_name::1}" != "v" ] then echo "Error: tag has to start with a v" exit 1 fi if [[ "$tag_name" =~ ^v([0-9]+)\.[0-9]+\.[0-9]+$ ]] then major="${BASH_REMATCH[1]}" if [[ "$latest_tag" =~ ^v([0-9]+)\.[0-9]+\.[0-9]+$ ]] then latest_major="${BASH_REMATCH[1]}" diff="$((major - latest_major))" if [[ "$diff" -gt "1" ]] then echo "Error: new major version is $diff bigger than current" echo " can only jump 1 major version at a time max" echo " $latest_tag -> $tag_name" exit 1 elif [[ "$diff" -lt "0" ]] then echo "Error: new major version is $diff smaller than current" echo " can only increase or stay equal" echo " $latest_tag -> $tag_name" exit 1 fi if [ "$diff" == "1" ] then warn_todos fi else echo "Error: failed to parse latest tag" exit 1 fi else echo "Error: tag has to match vMAJOR.MINOR.PATCH format" exit 1 fi if [[ "$( (git tag;echo "$tag_name") | sort -V | tail -n1)" != "$tag_name" ]] then echo "Error: the tag name you entered '$tag_name' does not seem to be the latest" echo " instead '$( (git tag;echo v0.0.2) | sort -V | tail -n1)' is the latest" echo " ensure a new release has the latest semantic version" exit 1 fi if ! commit="$(git log -n 1 --pretty=format:"%h %s")" then echo "Error: failed to get commit" exit 1 fi echo "=====================================================" echo "commit: $commit" echo "tag: $tag_name (superseding: $latest_tag)" echo "=====================================================" echo "Is that info correct? [y/N]" read -r -n1 yn if ! [[ "$yn" =~ [yY] ]] then echo "aborting ..." exit 0 fi if ! ./scripts/run_tests.sh then echo "Error: tests failed aborting ..." exit 1 fi echo "[*] updating version in setup.cfg ..." # can safely be ran multiple times sed -i "s/^version =.*/version = ${tag_name:1}/" setup.cfg echo "[*] wiping old dist ..." [[ -d dist ]] && rm -rf dist if ! python -m build then echo "Error: build failed" exit 1 fi if [ ! -f dist/twnet_parser-"${tag_name:1}".tar.gz ] then echo "Error: build did not generate expected file" echo " dist/twnet_parser-${tag_name:1}.tar.gz" exit 1 fi if ! pip install dist/twnet_parser-"${tag_name:1}".tar.gz then echo "Error: local test install of package failed" exit 1 fi if ! python -c "import twnet_parser" then echo "Error: local test import failed" exit 1 fi if ! git add setup.cfg then echo "Error: git add failed" exit 1 fi if [ "$(git diff HEAD --name-only)" != "setup.cfg" ] then echo "Error: unexpected files would be included in the commit" git diff HEAD --name-only | grep -v '^setup.cfg$' | awk '{ print " " $0 }' exit 1 fi if ! git commit -m "Release ${tag_name:1}" then echo "Error: git commit failed" exit 1 fi if ! git tag -a "$tag_name" -m "# version ${tag_name:1}" then echo "Error: creating the tag failed" exit 1 fi if ! python -m twine upload -u __token__ -p "$pypi_token" dist/* then echo "Error: upload to pypi failed" exit 1 fi git push origin master git push origin "$tag_name" echo "Create a release on gitlab with a changelog!" echo "./scripts/gen_changelog.sh" echo "https://gitlab.com/teeworlds-network/twnet_parser/-/releases/new?tag_name=$tag_name"