Add publishing option to release script

This commit is contained in:
Luke Campagnola 2016-10-06 09:07:22 -07:00
parent 5d0b6aa016
commit 076ffee8cc
2 changed files with 190 additions and 141 deletions

305
tools/build-pg-release.py Executable file → Normal file
View File

@ -19,6 +19,12 @@ Package build is done in several steps:
* Build deb packages (if running on Linux)
* Build Windows exe installers
Release packages may be published by using the --publish flag:
* Uploads release files to website
* Pushes tagged git commit to github
* Uploads source package to pypi
Building source packages requires:
*
@ -31,15 +37,20 @@ Building deb packages requires several dependencies:
* python-all, python3-all
* python-stdeb, python3-stdeb
Building windows .exe files should be possible on any OS. Note, however, that
Debian/Ubuntu systems do not include the necessary wininst*.exe files; these
must be manually copied from the Python source.
"""
path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
build_dir = os.path.join(path, 'release-build')
pkg_dir = os.path.join(path, 'release-packages')
ap = argparse.ArgumentParser(description=description, epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument('version', help='The x.y.z version to generate release packages for. '
'There must be a corresponding pyqtgraph-x.y.z branch in the source repository.')
ap.add_argument('--publish', metavar='', help='Publish previously built package files (must be stored in pkg-dir/version) and tagged release commit (from build-dir).', action='store_const', const=True, default=False)
ap.add_argument('--source-repo', metavar='', help='Repository from which release and master branches will be cloned. Default is the repo containing this script.', default=path)
ap.add_argument('--build-dir', metavar='', help='Directory where packages will be staged and built. Default is source_root/release-build.', default=build_dir)
ap.add_argument('--pkg-dir', metavar='', help='Directory where packages will be stored. Default is source_root/release-packages.', default=pkg_dir)
@ -47,128 +58,192 @@ ap.add_argument('--skip-pip-test', metavar='', help='Skip testing pip install.',
ap.add_argument('--no-deb', metavar='', help='Skip building Debian packages.', action='store_const', const=True, default=False)
ap.add_argument('--no-exe', metavar='', help='Skip building Windows exe installers.', action='store_const', const=True, default=False)
args = ap.parse_args()
args.build_dir = os.path.abspath(args.build_dir)
args.pkg_dir = os.path.join(os.path.abspath(args.pkg_dir), args.version)
if os.path.exists(args.build_dir):
sys.stderr.write("Please remove the build directory %s before proceeding, or specify a different path with --build-dir.\n" % args.build_dir)
sys.exit(-1)
if os.path.exists(args.pkg_dir):
sys.stderr.write("Please remove the package directory %s before proceeding, or specify a different path with --pkg-dir.\n" % args.pkg_dir)
sys.exit(-1)
version = args.version
vars = {
'ver': args.version,
'bld': args.build_dir,
'src': args.source_repo,
'pkgdir': args.pkg_dir,
}
# Clone source repository and tag the release branch
shell('''
# Clone and merge release branch into previous master
mkdir -p {bld}
cd {bld}
rm -rf pyqtgraph
git clone --depth 1 -b master {src} pyqtgraph
cd pyqtgraph
git checkout -b release-{ver}
git pull {src} release-{ver}
git checkout master
git merge --no-ff --no-commit release-{ver}
# Write new version number into the source
sed -i "s/__version__ = .*/__version__ = '{ver}'/" pyqtgraph/__init__.py
sed -i "s/version = .*/version = '{ver}'/" doc/source/conf.py
sed -i "s/release = .*/release = '{ver}'/" doc/source/conf.py
# make sure changelog mentions unreleased changes
grep "pyqtgraph-{ver}.*unreleased.*" CHANGELOG
sed -i "s/pyqtgraph-{ver}.*unreleased.*/pyqtgraph-{ver}/" CHANGELOG
# Commit and tag new release
git commit -a -m "PyQtGraph release {ver}"
git tag pyqtgraph-{ver}
# Build HTML documentation
cd doc
make clean
make html
cd ..
find ./ -name "*.pyc" -delete
# package source distribution
python setup.py sdist
mkdir -p {pkgdir}
cp dist/*.tar.gz {pkgdir}
# source package build complete.
'''.format(**vars))
if args.skip_pip_test:
vars['pip_test'] = 'skipped'
else:
shell('''
# test pip install source distribution
rm -rf release-{ver}-virtenv
virtualenv --system-site-packages release-{ver}-virtenv
. release-{ver}-virtenv/bin/activate
echo "PATH: $PATH"
echo "ENV: $VIRTUAL_ENV"
pip install --no-index --no-deps dist/pyqtgraph-{ver}.tar.gz
deactivate
def build(args):
if os.path.exists(args.build_dir):
sys.stderr.write("Please remove the build directory %s before proceeding, or specify a different path with --build-dir.\n" % args.build_dir)
sys.exit(-1)
if os.path.exists(args.pkg_dir):
sys.stderr.write("Please remove the package directory %s before proceeding, or specify a different path with --pkg-dir.\n" % args.pkg_dir)
sys.exit(-1)
# pip install test passed
'''.format(**vars))
vars['pip_test'] = 'passed'
if 'linux' in sys.platform and not args.no_deb:
# Clone source repository and tag the release branch
shell('''
# build deb packages
cd {bld}/pyqtgraph
python setup.py --command-packages=stdeb.command sdist_dsc
cd deb_dist/pyqtgraph-{ver}
sed -i "s/^Depends:.*/Depends: python (>= 2.6), python-qt4 | python-pyside, python-numpy/" debian/control
dpkg-buildpackage
cd ../../
mv deb_dist {pkgdir}/pyqtgraph-{ver}-deb
# Clone and merge release branch into previous master
mkdir -p {build_dir}
cd {build_dir}
rm -rf pyqtgraph
git clone --depth 1 -b master {source_repo} pyqtgraph
cd pyqtgraph
git checkout -b release-{version}
git pull {source_repo} release-{version}
git checkout master
git merge --no-ff --no-commit release-{version}
# deb package build complete.
'''.format(**vars))
vars['deb_status'] = 'built'
else:
vars['deb_status'] = 'skipped'
# Write new version number into the source
sed -i "s/__version__ = .*/__version__ = '{version}'/" pyqtgraph/__init__.py
sed -i "s/version = .*/version = '{version}'/" doc/source/conf.py
sed -i "s/release = .*/release = '{version}'/" doc/source/conf.py
# make sure changelog mentions unreleased changes
grep "pyqtgraph-{version}.*unreleased.*" CHANGELOG
sed -i "s/pyqtgraph-{version}.*unreleased.*/pyqtgraph-{version}/" CHANGELOG
if not args.no_exe:
# Commit and tag new release
git commit -a -m "PyQtGraph release {version}"
git tag pyqtgraph-{version}
# Build HTML documentation
cd doc
make clean
make html
cd ..
find ./ -name "*.pyc" -delete
# package source distribution
python setup.py sdist
mkdir -p {pkg_dir}
cp dist/*.tar.gz {pkg_dir}
# source package build complete.
'''.format(**args.__dict__))
if args.skip_pip_test:
args.pip_test = 'skipped'
else:
shell('''
# test pip install source distribution
rm -rf release-{version}-virtenv
virtualenv --system-site-packages release-{version}-virtenv
. release-{version}-virtenv/bin/activate
echo "PATH: $PATH"
echo "ENV: $VIRTUAL_ENV"
pip install --no-index --no-deps dist/pyqtgraph-{version}.tar.gz
deactivate
# pip install test passed
'''.format(**args.__dict__))
args.pip_test = 'passed'
if 'linux' in sys.platform and not args.no_deb:
shell('''
# build deb packages
cd {build_dir}/pyqtgraph
python setup.py --command-packages=stdeb.command sdist_dsc
cd deb_dist/pyqtgraph-{version}
sed -i "s/^Depends:.*/Depends: python (>= 2.6), python-qt4 | python-pyside, python-numpy/" debian/control
dpkg-buildpackage
cd ../../
mv deb_dist {pkg_dir}/pyqtgraph-{version}-deb
# deb package build complete.
'''.format(**args.__dict__))
args.deb_status = 'built'
else:
args.deb_status = 'skipped'
if not args.no_exe:
shell("""
# Build windows executables
cd {build_dir}/pyqtgraph
python setup.py build bdist_wininst --plat-name=win32
python setup.py build bdist_wininst
cp dist/*.exe {pkg_dir}
""".format(**args.__dict__))
args.exe_status = 'built'
else:
args.exe_status = 'skipped'
print(unindent("""
======== Build complete. =========
* Source package: built
* Pip install test: {pip_test}
* Debian packages: {deb_status}
* Windows installers: {exe_status}
* Package files in {pkg_dir}
Next steps to publish:
* Test all packages
* Run script again with --publish
""").format(**args.__dict__))
def publish(args):
if not os.path.isfile(os.path.expanduser('~/.pypirc')):
print(unindent("""
Missing ~/.pypirc file. Should look like:
-----------------------------------------
[distutils]
index-servers =
pypi
[pypi]
username:your_username
password:your_password
"""))
sys.exit(-1)
### Upload everything to server
shell("""
# Build windows executables
cd {bld}/pyqtgraph
python setup.py build bdist_wininst --plat-name=win32
python setup.py build bdist_wininst
cp dist/*.exe {pkgdir}
""".format(**vars))
vars['exe_status'] = 'built'
else:
vars['exe_status'] = 'skipped'
# Uploading documentation..
cd {build_dir}/pyqtgraph
rsync -rv doc/build/* pyqtgraph.org:/www/code/pyqtgraph/pyqtgraph/documentation/build/
# Uploading release packages to website
rsync -v {pkg_dir}/{version} pyqtgraph.org:/www/code/pyqtgraph/downloads/
# Push to github
git push --tags https://github.com/pyqtgraph/pyqtgraph master:master
# Upload to pypi..
python setup.py sdist upload
""".format(**args.__dict__))
print(unindent("""
======== Upload complete. =========
Next steps to publish:
- update website
- mailing list announcement
- new conda recipe (http://conda.pydata.org/docs/build.html)
- contact deb maintainer (gianfranco costamagna)
- other package maintainers?
""").format(**args.__dict__))
print("""
def unindent(msg):
ind = 1e6
lines = msg.split('\n')
for line in lines:
if len(line.strip()) == 0:
continue
ind = min(ind, len(line) - len(line.lstrip()))
return '\n'.join([line[ind:] for line in lines])
======== Build complete. =========
* Source package: built
* Pip install test: {pip_test}
* Debian packages: {deb_status}
* Windows installers: {exe_status}
* Package files in {pkgdir}
""".format(**vars))
if __name__ == '__main__':
args = ap.parse_args()
args.build_dir = os.path.abspath(args.build_dir)
args.pkg_dir = os.path.join(os.path.abspath(args.pkg_dir), args.version)
if args.publish:
publish(args)
else:
build(args)

View File

@ -1,26 +0,0 @@
import re, os, sys
version = sys.argv[1]
replace = [
("pyqtgraph/__init__.py", r"__version__ = .*", "__version__ = '%s'" % version),
#("setup.py", r" version=.*,", " version='%s'," % version), # setup.py automatically detects version
("doc/source/conf.py", r"version = .*", "version = '%s'" % version),
("doc/source/conf.py", r"release = .*", "release = '%s'" % version),
#("tools/debian/control", r"^Version: .*", "Version: %s" % version)
]
path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')
for filename, search, sub in replace:
filename = os.path.join(path, filename)
data = open(filename, 'r').read()
if re.search(search, data) is None:
print('Error: Search expression "%s" not found in file %s.' % (search, filename))
os._exit(1)
open(filename, 'w').write(re.sub(search, sub, data))
print("Updated version strings to %s" % version)