In this article I will show you how to automate your PyPi package releases with Github actions.
This implementation focuses on auto-versioning releases depending on the tag number using semantic versioning (1.0.0, 1.1.0, etc…)
If you just want to to see the code here is the repository with all the needed files https://github.com/Dvelezs94/pypi-auto-release
Goal
We want to create a release on PyPi according to the tag number we push on Github
For this guide I am assuming you already know how to set up a project in PyPi and the basics of Github, I’ll leave some useful links if you have no idea of what I am talking about
Steps
- Generate PyPi API token
- Store PyPi API token in your Github repository Secrets
- Define your
setup.py
file - Define Github workflow file
- Push tags and enjoy
Step by Step
1. Generate PyPi API token
For this you will go to PyPi to create an API token, this is so Github can authenticate against PyPi with your user.
2. Store PyPi API token in your Github repository Secrets
Now that you have your PyPi API token, we need to safely store it so Github can fetch it. For that you will need to go to your repository secrets Repository > Settings > Actions > New Repository Secret
In here you will name your secret PYPI_API_TOKEN
and then paste your PyPi API token
3. Define your setup.py
file
Next is to modify your setup.py
file to dynamically version your releases The important line is the one with VERSION_PLACEHOLDER
string. This string will get updated by Github Actions at run time, so you don’t need to update it every time you make a new release. It will get populated with the value you assign to the tag
i.e. 1.0.0, 1.1.1, etc..
"""
Sample setup.py file
"""
from setuptools import setup, find_packages
import codecs
import os
here = os.path.abspath(os.path.dirname(__file__))
with codecs.open(os.path.join(here, "README.md"), encoding="utf-8") as fh:
long_description = "\\n" + fh.read()
setup(
name="my_package_name",
version='{{VERSION_PLACEHOLDER}}',
author="John Doe",
author_email="johndoe@mail.com",
description="my amazing package",
url = "https://github.com/johndoe/my_package",
long_description_content_type="text/markdown",
long_description=long_description,
packages=find_packages(),
install_requires=['numpy'],
keywords=['pypi', 'cicd', 'python'],
classifiers=[
"Development Status :: 1 - Planning",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Operating System :: Unix",
"Operating System :: MacOS :: MacOS X",
"Operating System :: Microsoft :: Windows"
]
)
4. Define Github workflow file
Just copy and paste the file under repository/.github/workflows/pipy_release.yml
Things you might want to change
– Python version
– Runner (https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners)
name: Publish Python 🐍 distributions 📦 to PyPI
on:
push:
tags:
- '*'
jobs:
build-n-publish:
name: Build and publish Python 🐍 distributions 📦 to PyPI
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@master
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: '3.10'
- name: Install pypa/setuptools
run: >-
python -m
pip install wheel
- name: Extract tag name
id: tag
run: echo ::set-output name=TAG_NAME::$(echo $GITHUB_REF | cut -d / -f 3)
- name: Update version in setup.py
run: >-
sed -i "s/{{VERSION_PLACEHOLDER}}/${{ steps.tag.outputs.TAG_NAME }}/g" setup.py
- name: Build a binary wheel
run: >-
python setup.py sdist bdist_wheel
- name: Publish distribution 📦 to PyPI
uses: pypa/gh-action-pypi-publish@master
with:
password: ${{ secrets.PYPI_API_TOKEN }}
5. Push your code to your main branch and then create a tag by running
git tag 0.0.1 # or whatever version you want
git push origin --tags
After this you will see Github actions in action (I couldn’t resist) and if everything is correct, you package will get deployed to PyPi (even if its for the first time)
You will be able to see your Github actions runs at repository > actions
Project containing files explained in the tutorial here https://github.com/Dvelezs94/pypi-auto-release