Publish Package to PyPI and Release Version Automation Using GitHub Actions
Tags: github, python, package, action
Published: 2022-06-30 09:05:59

Manually creating tags, publishing the package and creating the GitHub release is time consuming repetitive task. Creating the version means, same version should be used to create the release and also to publish the package to PyPI library. In this article, I am going to automate this process. Please follow the following steps to automate such task,

## 1. Create the API token from PyPI

The API token can be created from [PyPI user account setting](https://pypi.org/manage/account/). After creating the token, it will be listed out in the API key section.

![create API token from pypi](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pzct2uchmx3eyhoytvhs.png)

## 2. Add API key to the GitHub secret

Now, you need to add the same to the GitHub repository secret. To add that, you need to go to the repository setting, then click on `Secrets > actions > New repository secret`. Add the name of the secret as `PYPI_API_TOKEN`.


![add GitHub secret](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dtf1ffzx8winrs4j6qpa.png)

## 3. Add the YML file to GitHub Workflow

In the repository, create `.github/workflows/release_to_pypi.yml` file. In this file, you need to write the configuration code for publishing your package. Write the following code into release file to get start,

```yml
name: Publish ${package_name} to PyPI / GitHub

on:
  push:
    tags:
      - "v*"
```

The first name key denotes the name of the task. The second chunk, `on` key denotes on which condition this condition should run. In above case, whenever the tag starting with letter `v` is pushed into GitHub, this action will run. 

Now add the jobs for this action,

```yml
jobs:
  build-n-publish:
    name: Build and publish to PyPI
    runs-on: ubuntu-latest

    steps:
      - name: Checkout source
        uses: actions/checkout@v2

      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: "3.x"

      - name: Build source and wheel distributions
        run: |
          python -m pip install --upgrade build twine
          python -m build
          twine check --strict dist/*
      - name: Publish distribution to PyPI
        uses: pypa/gh-action-pypi-publish@master
        with:
          user: __token__
          password: ${{ secrets.PYPI_API_TOKEN }}

      - name: Create GitHub Release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
        with:
          tag_name: ${{ github.ref }}
          release_name: ${{ github.ref }}
          draft: false
          prerelease: false

      - name: Get Asset name
        run: |
          export PKG=$(ls dist/ | grep tar)
          set -- $PKG
          echo "name=$1" >> $GITHUB_ENV
      - name: Upload Release Asset (sdist) to GitHub
        id: upload-release-asset
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: dist/${{ env.name }}
          asset_name: ${{ env.name }}
          asset_content_type: application/zip
```

These all things are the default things for publishing the package to the PyPI library and to release the GitHub version. You simply copy and paste this code to `release_to_pypi.yml` library. 

> I only want to address two things here, the first one is, in the password key(`password: ${{ secrets.PYPI_API_TOKEN }}`), the secrets we created in previous step is going to use. Make sure the name of the secret creating in the GitHub repository matched to the name of the above variable. Another things is, the GITHUB_TOKEN key (`GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}`), this secret is provided by GitHub actions, you don't need to create your own token. 

If you only want to publish package to PyPI (Do not want to release in GitHub, feel free to remove the last two section from above code, i.e.,

```yml
 - name: Create GitHub Release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
        with:
          tag_name: ${{ github.ref }}
          release_name: ${{ github.ref }}
          draft: false
          prerelease: false

      - name: Get Asset name
        run: |
          export PKG=$(ls dist/ | grep tar)
          set -- $PKG
          echo "name=$1" >> $GITHUB_ENV
      - name: Upload Release Asset (sdist) to GitHub
        id: upload-release-asset
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: dist/${{ env.name }}
          asset_name: ${{ env.name }}
          asset_content_type: application/zip
```

## 4. Test whether it will work or not

Finally, it is time to test our workflow whether it will work or not. To test it, first of all, lets create the version in using `git`,

```git
git tag -a "v0.0.1-beta" -m "beta version testing"
git push --tags
```

After pushing this `tag` to the GitHub, it should trigger your GitHub action something like below,


![GitHub action](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c07irnvkdgh1sn9ywx1k.png)

Congratulations! you are successfully integrated this automation.

If you like this blog, please support me by subscribing to my YouTube channel: https://www.youtube.com/c/iamtekson