Integrating Packagr with Github and Travis CI

How to use Travis CI to deploy your private Python packages to Packagr

In the last tutorial in this series, we looked at how to use Gitlab CI to package your Python code and upload it to Packagr whenever you push new code to your repository. In this tutorial, we are going to look at how to achieve the exact same thing using GitHub and Travis CI.

Setting up your repository

Let’s start by creating a fresh GitHub repository — just click on the big Start project button, and give your repository a name. For the purpose of this example, I created a project called packagr-project, which you can see here.

Important: If you don’t have a paid Travis CI account, then you must create a public Github project
Creating a new project in Github

Next, let’s sign up for TravisCI, by clicking on the big Sign up button and logging in with your Github credentials. From there, go to your Settings and you should see a list of all your Github repositories. To enable Travis CI for our new repository, just flip the switch next to its name:

Linking your Github repository with Travis CI

Finally, if you don’t already have a Packagr account, you’ll need to sign up for one. Make a note of your repository URL for later, which you can find by clicking on the Create new package link at the top of the interface

We’re now ready to start writing some code

The folder structure

Clone your Github repository to your local machine, and let’s get started by creating a simple folder structure like the following:

The folder structure

The folder my-package can be called anything-this is where your actual Python code should live. For the purposes of this tutorial, we’ll just create an extremely simple Python function that returns a “hello,world!” response. Let’s add the following code to the hello.py file:

def hello(*args, **kwargs):
return 'Hello, world!'

Next, let’s take a look at our setup.pyfile. This file defines how our package is built. It should look like this:

from setuptools import setup
setup(name='my-package', version='0.1.0')

We now have the minimum basic code to create a Python package

Testing out the upload

Before we go any further, let’s try and package our code and upload the package to Packagr, just to ensure that everything is working as it should. Open a terminal window from the root folder of your repository, and enter the following four commands, replacing the URL with your own Packagr URL that we made a note of earlier

pip install twine wheel
python setup.py sdist bdist_wheel
cd dist
twine upload --repository-url https://api.packagr.app/63cdQSDO/ *

You’ll be prompted for your Packagr credentials at this stage — once you’ve entered them correctly, the package will upload and you’ll see your new package in the Packagr interface:

Your newly created package

Managing versions

Let’s see what happens when we try to execute that last command one more time:

$ twine upload  --repository-url https://api.packagr.app/63cdQSDO/ *
Enter your username: christopherdavies553@gmail.com
Enter your password:
Uploading distributions to https://api.packagr.app/63cdQSDO/
Uploading my_package-0.1.0-py3-none-any.whl
100%|███████████████████████| 3.57k/3.57k [00:00<00:00, 8.38kB/s]
HTTPError: 409 Client Error: Conflict for url: https://api.packagr.app/63cdQSDO/

This time, although we didn’t change anything, the upload fails with a 409 error code. This is because we’ve attempted to upload the same package with the same version number. If you change the version number in your setup.py file as follows, then recreate the package and reupload it, it should work again:

from setuptools import setup
setup(name='my-package', version='0.2.0')

However, having to manually change the version number every time you push code to your repository is going to get boring very quickly. In order to get around this problem, we can use Git tags to update our package version. These tags are available to Travis CI during the build process via the TRAVIS_TAG environmental variable. So let’s update our setup.py file to dynamically set the version number at run time, like this:

from setuptools import setup
import os
version = os.environ['TRAVIS_TAG']
setup(name='my-package', version=version)

Configuring Travis CI

When you push code to your Travis-connected Github repository, Travis looks for a file called .travis.yml, which defines the steps taken on pushing your code. Let’s add this file to the root folder of our repository now:

language: python
python:
- "3.6"
script:
- python setup.py bdist_wheel
deploy:
provider: pypi
user: $PACKAGR_USERNAME
password: $PACKAGR_PASSWORD
server: $PACKAGR_REPOSITORY_URL
on:
tags: true

Let’s break this down a bit:

  • The script parameter creates our package
  • The deploy stage uses the pypi provider, but defines custom values for server, user and password
  • The on condition means that the deployment will only be run on tagged commits

The server, user and password have been added as environmental variables — for security reasons, you should never include credentials in version control. However, we need to define these environmental variables in Travis in order for them to work. This can be done by clicking the Settings button next to the relevant repository in TravisCI:

Setting the environmental variables in TravisCI

Pushing your code

We’re now ready to go! Let’s commit our files, tag the commit and push it with the following commands:

git add my-package/hello.py setup.py
git tag 1.0.0
git push --tags

This should push your code to your GitHub repository, which in turn will trigger the Travis process (as this is a tagged commit). You can monitor the status of your TravisCI build through the interface — if it all goes well, it will eventually complete and turn green, like this:

TravisCI build success

The package should also now be visible in Packagr:

The version created by TravisCI

That’s it! In future, all your tagged commits will repackage your code on Packagr