Create a GitHub Actions CI workflow for a Python Package

Hi all,

In this post I’m going to show you how to create a GitHub Actions CI workflow that runs on a Python package project and:

  • Triggers on every sucesfull commit in the main branch
  • Run the tests and generates the code coverage report
  • Generate the package and makes it available through an artifact

You can check the result in my GitHub repository

As the source package, I’ve created a very simple Python project for a calculator class, (hey, I know, It’s not a really awesome calculator project, in fact, it’s a really poor one , but it shows an example of how to create and organize a python package project folder and how to set up unit tests and generate code coverage report for it, so I’m quite happy with it as I see it as a good starting point for any new project :) )

So, these were the steps I did to get the workflow up and running:

Creating the template file

First of all I had to create the GitHub Actions template, so I needed to create a folder path like “.github/workflows” inside the project root directory, and after that I created a YAML file inside that directory with the workflow template.

After creating the folder, I just created an empty YAML file called build.pipeline.yml

To start adding content to the template, I used this example in the GitHub documentation page which I found really inspiring.

Firing the workflow automatically

To fire the workflow with every commit in the (main/master) branch I just had to specify the “on” event in the workflow template, defining how I wanted the workflow to be triggered:

This way I told GitHub that I wanted to run the worklow not only with every commit on (master/main) branch but with every pull request on this branch too.

Running tests and generating the coverage report

This project uses unittest as the testing framework and for generating code coverage results. As unittest ships with python, I only needed to install in the agent before running the tests.

It is also a good recommendation to update pip before any package installation so upgrading pip was also in my list.

And finally, I wanted my workflow to be ready If I add a requirements.txt file in the near future, so I added a condition in the step to install the libraries in the requirements.txt file if necessary

After installing I was ready to run the tests, so I added a new script in my workflow template that executes following steps:

  1. go to src directory (that’s where my source code is located inside my repository)
  2. run unit tests
  3. run coverage based on unittests results
  4. generate coverage report and show it on the screen

5. generate coverage report in html format

The last line of the previous script generated an Html version of the code coverage report, so I wanted to download it when the workflow ends, to do so I used the upload artifact action:

I know that when you run the command “coverage html”, a htmlcov folder gets created with all the coverage report formatted as html, so I just needed to archive that folder and upload it as an artifact, which the actions does it at once (lucky me! :) )

Generating the package

Ok! this is the last step of the workflow, as I followed the official python documentation about package creation I knew that for packaging my project I just needed to:

  1. Install PyPA’s build
  2. Execute build

So that’s what I did! after executing this step I just added another one to create and upload the package output as a workflow artifact, same as I did with the code coverage report:

After all these steps, I just uploaded my template to my GitHub repo and I checked out the results, and after some adjustments (nothing works at first try, huh?) I got the results I expected :)

Here you have my entire workflow template:

# GitHub CI build pipeline
name: Awesome Calculator CI build

- master
- main
- master
- main
runs-on: ubuntu-latest
- uses: actions/checkout@v2
- name: Set up python 3.7
uses: actions/setup-python@v2
python-version: 3.7
- name: Install dependencies
run: |
cd src
python -m pip install --upgrade pip
pip install coverage
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Run Unit Tests and generate coverage report
run: |
cd src
python -m unittest -v
coverage run -m unittest
coverage report
coverage html
- name: Archive code coverage html report
uses: actions/upload-artifact@v2
name: code-coverage-report
path: src/htmlcov
- name: Run package creation
run: |
cd src
python -m pip install --user --upgrade build
python -m build
- name: Archive package
uses: actions/upload-artifact@v2
name: awesome-calculator
path: src/dist

developer, cloud based, DevOps enthusiast,cats fan . . .