Skip to main content
Gorilla Tactics

Using Git tags to set a Python package version

·4 mins

I know what you’re thinking; what am I doing talking about Python?

Well, it’s a funny story that started with just wanting a way to know when the batteries in my heating system devices were running low, buying a Raspberry Pi 4 to run Home Assistant, took in a battle to get a spare SSD I had working on it. Next thing I know, I’m learning Python to allow me to update the Home Assistant plugin for my heating system, then putting in pull requests to the Python library it uses to talk to the heating system.

And it ends up with me being asked to take over stewardship of this library! See, hilarious, no?

I’ve actually written a few draft posts about various stages of this process, but they’ve tended to be superceded by events.

One of the things that I’m looking to change about the project is to move it from being built and tested using Circle CI, to doing it all on Github. The code is hosted there anyway. To be fair to the previous custodians of the library, GitHub Actions are a relatively new development, one that this library pre-dates.

Setting up the GitHub Action #

Adding a new action is relatively simple; you put the action yaml file into a .github/workflow folder structure in your project. I’ll be honest, yaml is not my favourite language, as I’m not a fan of having white space be critical to the meaning of code. It’s easy enough to make mistakes in code, without those mistakes possibly being invisible!

The first thing to set is the name and trigger for the action, which I want to be whenever a new release is published:

name: Publish to PyPI.org
on:
  release:
    types: [published]

As you can see, this is simple enough.

With the action triggered, it’s then a case of setting up the jobs you want it to execute.

jobs:
  pypi:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Set up Python 3.10.8
        uses: actions/setup-python@v1
        with:
          python-version: "3.10.8"

      - name: Install build dependencies
        run: python -m pip install build wheel

      - name: Build distributions
        shell: bash -l {0}
        run: python setup.py sdist bdist_wheel

      - name: Publish package
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          password: ${{ secrets.PYPI_API_TOKEN }}

Hopefully this is pretty self-explanatory; checkout the code, setup Python, install the build dependencies, run the build, then publish it to PyPi (a Python package manager). The last step requires setting up an API token for PyPi as a GitHub secret, which you can easily search for instructions on.

The one thing missing from this is the automation of setting the package version. In the course of attempting to get this working, I tried setuptools_scm and versioneer, that use Python tools and libraries to extract the version from a Git tag on the commit, however I had trouble getting them to work, plus I didn’t like the extra dependencies this created.

The one thing this doesn’t do is set the version. The project originally required the version to be set manually, which isn’t something I’m interested in doing if I don’t have to!

I originally tried using setuptools_scm and versioneer, but those both required installation, which did not appeal. I then had the thought to see what environment variables GitHub set for the action context, and, sure enough, they set the tag that kicked off the action as GITHUB_REF_NAME.

Getting the variable is easy enough. In setup.py, you just need to import os, and use that to get the value of the variable:

VERSION = os.environ["GITHUB_REF_NAME"]

You can then use that variable in the setup method:

    version=VERSION,

Creating a release #

The first thing to do is to get the latest version of your main branch. To add a tag and push it to the server, run these commands in your CLI:

git tag v0.7.0
git push --tags

This adds the tag to that commit, and pushes the tag up to GitHub. You can then go to the Releases page on GitHub and create a new release based on the tag you’ve just created. And creating that release will kick off the action to build and publish the release to PyPi.

And with that, I have a system to automatically push a new release to PyPi!