1#!/bin/bash 2 3set -ex 4 5function get_source_version() { 6 grep "__version__ = '.*'" python/google/protobuf/__init__.py | sed -r "s/__version__ = '(.*)'/\1/" 7} 8 9function run_install_test() { 10 local VERSION=$1 11 local PYTHON=$2 12 local PYPI=$3 13 14 # Setuptools 45.0 removed support for Python 2, so to test with Python 2 we 15 # pass --no-setuptools here and then install an older setuptools version 16 # below. 17 virtualenv -p `which $PYTHON` --no-setuptools test-venv 18 19 # Intentionally put a broken protoc in the path to make sure installation 20 # doesn't require protoc installed. 21 touch test-venv/bin/protoc 22 chmod +x test-venv/bin/protoc 23 24 source test-venv/bin/activate 25 pip install "setuptools<45" 26 pip install -i ${PYPI} protobuf==${VERSION} --no-cache-dir 27 deactivate 28 rm -fr test-venv 29} 30 31 32[ $# -lt 1 ] && { 33 echo "Usage: $0 VERSION [" 34 echo "" 35 echo "Examples:" 36 echo " Test 3.3.0 release using version number 3.3.0.dev1:" 37 echo " $0 3.0.0 dev1" 38 echo " Actually release 3.3.0 to PyPI:" 39 echo " $0 3.3.0" 40 exit 1 41} 42VERSION=$1 43DEV=$2 44 45# Make sure we are in a protobuf source tree. 46[ -f "python/google/protobuf/__init__.py" ] || { 47 echo "This script must be ran under root of protobuf source tree." 48 exit 1 49} 50 51# Make sure all files are world-readable. 52find python -type d -exec chmod a+r,a+x {} + 53find python -type f -exec chmod a+r {} + 54umask 0022 55 56# Check that the supplied version number matches what's inside the source code. 57SOURCE_VERSION=`get_source_version` 58 59[ "${VERSION}" == "${SOURCE_VERSION}" -o "${VERSION}.${DEV}" == "${SOURCE_VERSION}" ] || { 60 echo "Version number specified on the command line ${VERSION} doesn't match" 61 echo "the actual version number in the source code: ${SOURCE_VERSION}" 62 exit 1 63} 64 65TESTING_ONLY=1 66TESTING_VERSION=${VERSION}.${DEV} 67if [ -z "${DEV}" ]; then 68 read -p "You are releasing ${VERSION} to PyPI. Are you sure? [y/n]" -r 69 echo 70 if [[ ! $REPLY =~ ^[Yy]$ ]]; then 71 exit 1 72 fi 73 TESTING_ONLY=0 74 TESTING_VERSION=${VERSION} 75else 76 # Use dev version number for testing. 77 sed -i -r "s/__version__ = '.*'/__version__ = '${VERSION}.${DEV}'/" python/google/protobuf/__init__.py 78fi 79 80cd python 81 82# Run tests locally. 83python setup.py build 84python setup.py test 85 86# Deploy source package to testing PyPI 87python setup.py sdist 88twine upload --skip-existing -r testpypi -u protobuf-wheel-test dist/* 89 90# Test locally with different python versions. 91run_install_test ${TESTING_VERSION} python2.7 https://test.pypi.org/simple 92run_install_test ${TESTING_VERSION} python3 https://test.pypi.org/simple 93 94# Deploy egg/wheel packages to testing PyPI and test again. 95python setup.py clean build bdist_wheel 96twine upload --skip-existing -r testpypi -u protobuf-wheel-test dist/* 97 98run_install_test ${TESTING_VERSION} python2.7 https://test.pypi.org/simple 99run_install_test ${TESTING_VERSION} python3 https://test.pypi.org/simple 100 101echo "All install tests have passed using testing PyPI." 102 103if [ $TESTING_ONLY -eq 0 ]; then 104 read -p "Publish to PyPI? [y/n]" -r 105 echo 106 if [[ ! $REPLY =~ ^[Yy]$ ]]; then 107 exit 1 108 fi 109 echo "Publishing to PyPI..." 110 # Be sure to run build before sdist, because otherwise sdist will not include 111 # well-known types. 112 python setup.py clean build sdist 113 twine upload --skip-existing -u protobuf-packages dist/* 114 # Be sure to run clean before bdist_xxx, because otherwise bdist_xxx will 115 # include files you may not want in the package. E.g., if you have built 116 # and tested with --cpp_implemenation, bdist_xxx will include the _message.so 117 # file even when you no longer pass the --cpp_implemenation flag. See: 118 # https://github.com/protocolbuffers/protobuf/issues/3042 119 python setup.py clean build bdist_wheel 120 twine upload --skip-existing -u protobuf-packages dist/* 121else 122 # Set the version number back (i.e., remove dev suffix). 123 sed -i -r "s/__version__ = '.*'/__version__ = '${VERSION}'/" google/protobuf/__init__.py 124fi 125