Introducing

Test and Publish a Python Package to PyPi using Poetry and GitHub Actions

My Workflow

I created a python package cookiecutter showcasing two GitHub actions workflow files I've seen and used successfully to test and publish a Python package to PyPi using GitHub actions.

The detailed explanation and python cookiecutter wrapper are the novel additions. πŸŽ‰ I found it difficult to just inspect open source projects work and put the pieces together.

So I hope this helps you (no matter your previous experience).

Please let me know what isn't clear!

Getting started with this template

There are two workflow files, each with their named purpose:

  • Test
  • Publish

If you have an existing python project or are starting a new one, you can use your GitHub username and your project name as inputs into my Cookiecutter template!

First, what is cookiecutter?

Cookiecutter

A command-line utility that creates projects from cookiecutters (project templates), e.g. Python package projects, VueJS projects.


A command-line utility that creates projects from cookiecutters (project templates), e.g. creating a Python package project from a Python package project template.

Make sure you have Python3 installed!

Instructions to use iancleary/pypackage

python3 -m pip install cookiecutter
# you can add the flag `--user` if you'd like

$ cookiecutter https://github.com/iancleary/pypackage
# For the sake of brevity, repos on GitHub can just use the 'gh' prefix
$ cookiecutter gh:iancleary/pypackage

Features

  • Poetry (virtual environment and publish to PyPi, all with one tool)
  • black (linting/formatter)
  • autoflake (removing unused packages)
  • isort (dependency organization)
  • mypy (static type checking)
  • pytest (including test coverage)
  • pre-commit (hooks on commit)
  • GitHub Actions for CI/CD
  • mkdocs for documentation (with material theme)

Only Python 3.6+ is supported as required by the black, pydantic packages

Yaml File or Link to Code

My Cookiecutter Python Package is hosted on Github @ https://github.com/iancleary/pypackage

Test

name: Test

on:
  push:
  pull_request:
    types: [opened, synchronize]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: [3.6, 3.7, 3.8]
      fail-fast: false

    steps:
      - uses: actions/checkout@v2
      - name: Set up Python
        uses: actions/setup-python@v1
        with:
          python-version: ${{ matrix.python-version }}
      - name: Get full python version
        id: full-python-version
        run: echo ::set-output name=version::$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))")
      - name: Install poetry
        run: |
          curl -fsS -o get-poetry.py https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py
          python get-poetry.py -y
          echo "::set-env name=PATH::$HOME/.poetry/bin:$PATH"
      - name: Configure poetry
        run: poetry config virtualenvs.in-project true
      - name: Set up cache
        uses: actions/cache@v1
        id: cache
        with:
          path: .venv
          key: venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }}-${{ hashFiles('**/poetry.lock') }}
      - name: Ensure cache is healthy
        if: steps.cache.outputs.cache-hit == 'true'
        run: poetry run pip --version >/dev/null 2>&1 || rm -rf .venv
      - name: Install Dependencies
        run: poetry install
      - name: Test
        run: poetry run bash scripts/test.sh
      - name: Upload coverage
        uses: codecov/codecov-action@v1

Publish

Repo Secrets

Go to your repo settings and add a PYPI_TOKEN environment variable:

GitHub Actions PYPI_TOKEN secrets visual aid

name: Publish

on:
  release:
    types:
      - created

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up Python
        uses: actions/setup-python@v1
        with:
          python-version: "3.7"
      - name: Install poetry
        run: |
          curl -fsS -o get-poetry.py https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py
          python get-poetry.py -y
          echo "::set-env name=PATH::$HOME/.poetry/bin:$PATH"
      - name: Configure poetry
        run: poetry config virtualenvs.in-project true
      - name: Set up cache
        uses: actions/cache@v1
        id: cache
        with:
          path: .venv
          key: venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }}-${{ hashFiles('**/poetry.lock') }}
      - name: Ensure cache is healthy
        if: steps.cache.outputs.cache-hit == 'true'
        run: poetry run pip --version >/dev/null 2>&1 || rm -rf .venv
      - name: Install Dependencies
        run: poetry install
      - name: Publish
        env:
          PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
        run: |
          poetry config pypi-token.pypi $PYPI_TOKEN
          bash scripts/publish.sh

That's it!

When you make a release on GitHub, the publish workflow will run and deploy to PyPi! πŸš€πŸŽ‰πŸ˜Ž

Additional Resources / Info

I have used the cookiecutter successfully in my FastRF project

https://github.com/iancleary/fastrf


Source Link for Banner Image: https://levelup.gitconnected.com/how-to-write-github-actions-30b54ddf6f52

⟡ Back to Home