Continuous deployment of Python packages with Wercker
Continuous delivery isn't just for web applications, it's valuable to be able to quickly get feedback from real users for any kind of software project. Also, I'm lazy, so automating the release process for any software to the point that I only have to merge a branch into master is great.
I recently set up continuous deployment of my npTDMS Python package to PyPI (the Python package index) using Wercker. Wercker is a continuous integration and deployment solution built on Docker. You build your code inside a Docker container and can specify a Docker image to use that contains the build dependencies for your project. This Docker image can come from any public or private registry, so you can use your own Docker image and have complete control over the build environment. I created a Python image containing everything needed to build and test my library and hosted it on Docker Hub. The Dockerfile looks like this:
FROM ubuntu:14.04
RUN sudo apt-get update && \
sudo apt-get install -y \
python3 python3-numpy python3-setuptools python3-nose python3-pandas \
python python-numpy python-setuptools python-nose python-pandas \
pep8 python-pip python-wheel
This Dockerfile lives in a git repository on GitHub. Any commits to this repository trigger a new Docker image build using Docker Hub's auto-build feature.
In wercker.yml
I set the Docker image to use, pointing it at my
image on Docker Hub:
box: adreeve/python-numpy
The test section in my wercker.yml
defines what to run to build and test my code,
and looks like:
build:
steps:
- script:
name: PEP8 Check
code: |
pep8 ./nptdms
- script:
name: Test on Python 2.7
code: |
python2.7 setup.py install
nosetests
- script:
name: Test on Python 3
code: |
python3 setup.py install
nosetests3
This tells Wercker to run pep8 to check code style, then run tests on Python 2.7 and Python 3 using nose.
Wercker lets you define deployment steps and you can optionally enable
automatic deployment from specific branches after successful builds.
The deployment step in my wercker.yml
file is pretty simple, it looks like this:
deploy:
steps:
- script:
name: Deploy to PyPI
code: |
echo "[pypirc]
servers = pypi
[server-login]
username:$PYPI_USER
password:$PYPI_PASSWORD" > ~/.pypirc
python setup.py sdist upload
python setup.py bdist_wheel upload
This simply configures my PyPI credentials then runs the commands to upload a new release
as a source package and a Python wheel.
The PYPI_USER
and PYPI_PASSWORD
variables are configured in the Wercker UI and are kept secret.
Now after any successful build on master, Wercker will automatically deploy a new release to PyPI!
One thing to note with this approach is that PyPI will reject an upload of a new release if the version number has not changed, so if you enable automatic deployment from your master branch, you should ensure any pull request into that branch increments the version number. Remember to follow semantic versioning!
The complete wercker.yml
file for npTDMS can be found in the
GitHub repository.