Skip to content

Instantly share code, notes, and snippets.

@mdzhang
Created December 4, 2020 06:59
Show Gist options
  • Save mdzhang/6e74f1f7ba163765f48173f23390f2b2 to your computer and use it in GitHub Desktop.
Save mdzhang/6e74f1f7ba163765f48173f23390f2b2 to your computer and use it in GitHub Desktop.

Revisions

  1. mdzhang created this gist Dec 4, 2020.
    132 changes: 132 additions & 0 deletions release
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,132 @@
    #!/bin/bash

    set -ex

    command -v gh >/dev/null 2>&1 || die "gh is required but not installed. Aborting. See https://github.com/cli/cli"

    usage()
    {
    echo " Usage: ${0}
    -v, Version. Should follow pattern v{major}.{minor}.{patch}
    Alpha versions should end with e.g. a0, a1, a2, etc.
    Beta versions should end with e.g. b0, b1, b2, etc.
    -m, Short message to describe version
    -t, Whether to release to test server
    Tag current commit with given version and build and release package to PyPi and GitHub
    "
    }

    # push test instead of prod pypi release
    # NB: does not affect git tags or github release
    testrelease=1

    while getopts "v:m:t:h" opt; do
    case $opt in
    h) usage && exit 1
    ;;
    v) version=$OPTARG
    ;;
    m) message=$OPTARG
    ;;
    t) testrelease=$OPTARG
    ;;
    \?) echo "Invalid option -$OPTARG" >&2
    ;;
    esac
    done

    if [[ $(git diff --stat) != '' ]]; then
    echo "Git branch is dirty. Can't release"
    exit 1
    fi

    if [ "${PYPI_USER}x" == "x" ]; then
    echo "PYPI_USER env var must be set"
    exit 1
    fi

    if [ "${PYPI_PASSWORD}x" == "x" ]; then
    echo "PYPI_PASSWORD env var must be set"
    exit 1
    fi

    ######################################################################
    # Git tag
    ######################################################################

    # add $ so we don't look like we released 0.1.0 just b/c 0.1.0a1 is out
    alreadygittaggedlocally=$(git tag | { grep -e "$version$" -c || true ; })

    if [[ $alreadygittaggedlocally -eq 1 ]]; then
    echo "Git tag already existed locally. Not adding tag again."
    else
    echo "Tagging locally..."
    # tag current commit
    git tag -a "$version" -m "$message"
    fi

    alreadygittaggedremotely=$(git ls-remote --tags --refs | { grep -e "$version$" -c || true ; })

    if [[ $alreadygittaggedremotely -eq 1 ]]; then
    echo "Git tag already existed remotely. Not adding tag again."
    else
    echo "Pushing tags..."
    # push tag to remote
    git push origin "refs/tags/$version"
    fi

    ######################################################################
    # Python package release
    ######################################################################

    if [ $testrelease -eq 1 ] ; then
    pypi="testpypi"
    else
    pypi="pypi"
    fi

    pypiversion=$(echo "$version" | cut -c 2-)
    echo "Seeing if pypi released..."
    # TODO: this will search production pypi for existing package
    # so may fail if attempting to re-push a published test pypi package
    alreadypypireleased=$(
    pip install dbt_log_parser== 2>&1 \
    | grep versions \
    | awk '{ split($0,a,/versions:/); print a[2] }' \
    | rev | cut -c 2- | rev \
    | tr ',' '\n' | tr -d ' ' \
    | { grep -e "$pypiversion$" -c || true ; }
    )

    if [[ $alreadypypireleased -eq 1 ]]; then
    echo "PyPi release already existed. Not recreating."
    else
    echo "Creating PyPi release"
    rm -rf dist/
    python3 setup.py sdist bdist_wheel
    pip install twine
    python3 -m twine upload --repository "$pypi" dist/* -u "${PYPI_USER}" -p "${PYPI_PASSWORD}"
    fi

    ######################################################################
    # GitHub release
    ######################################################################

    alreadygitreleased=$(gh release list | cut -d\$'\t' -f1 | { grep -e "$version$" -c || true ; })

    if [[ $alreadygitreleased -eq 1 ]]; then
    echo "Github release already existed. Not recreating."
    else
    # split per-version docs into separate files named changes*
    csplit --prefix changes CHANGELOG.md "/^##.*/" '{*}'

    # find the current version's notes
    releasenotesfile=$(find . -type f -iname "changes*" | xargs fgrep -l "$version" | head -1)

    gh release create "$version" -F "$releasenotesfile"

    # cleanup split files
    find . -type f -iname "changes*" -exec rm {} \;
    fi