|
| 1 | +============================================================================= |
| 2 | +Publishing package distribution releases using GitHub Actions CI/CD workflows |
| 3 | +============================================================================= |
| 4 | + |
| 5 | +`GitHub Actions CI/CD`_ allows you to run a series of commands |
| 6 | +whenever an event occurs on the GitHub platform. One |
| 7 | +popular choice is having a workflow that's triggered by a |
| 8 | +``push`` event. |
| 9 | +This guide shows you how to publish a Python distribution |
| 10 | +whenever a tagged commit is pushed. |
| 11 | +It will use the `pypa/gh-action-pypi-publish GitHub Action`_ https://github.com/marketplace/actions/pypi-publish |
| 12 | + |
| 13 | +.. attention:: |
| 14 | + |
| 15 | + This guide *assumes* that you already have a project that |
| 16 | + you know how to build distributions for and *it lives on GitHub*. |
| 17 | + |
| 18 | +.. warning:: |
| 19 | + |
| 20 | + At the time of writing, `GitHub Actions CI/CD`_ |
| 21 | + is in public beta. If you don't have it enabled, |
| 22 | + you should `join the waitlist`_ to gain access. |
| 23 | + |
| 24 | + |
| 25 | +Saving credentials on GitHub |
| 26 | +============================ |
| 27 | + |
| 28 | +In this guide, we'll demonstrate uploading to both |
| 29 | +PyPI and TestPyPI, meaning that we'll have two separate sets |
| 30 | +of credentials. And we'll need to save them in the GitHub repository |
| 31 | +settings. |
| 32 | + |
| 33 | +Let's begin! 🚀 |
| 34 | + |
| 35 | +1. Go to https://pypi.org/manage/account/#api-tokens and |
| 36 | + create a new `API token`_. If you have the project on PyPI |
| 37 | + already, limit the token scope to just that project. |
| 38 | + You can call it something like |
| 39 | + ``GitHub Actions CI/CD — project-org/project-repo`` |
| 40 | + in order for it to be easily distinguishable in the token |
| 41 | + list. |
| 42 | + **Don't close the page just yet — you won't see that token |
| 43 | + again.** |
| 44 | +2. In a separate browser tab or window, go to the ``Settings`` |
| 45 | + tab of your target repository and then click on `Secrets`_ |
| 46 | + in the left sidebar. |
| 47 | +3. Create a new secret called ``pypi_password`` and copy-paste |
| 48 | + the token from the fist step. |
| 49 | +4. Now, go to https://test.pypi.org/manage/account/#api-tokens |
| 50 | + and repeat the steps. Save that TestPyPI token on GitHub |
| 51 | + as ``test_pypi_password``. |
| 52 | + |
| 53 | + .. attention:: |
| 54 | + |
| 55 | + If you don't have a TestPyPI account, you'll need to |
| 56 | + create it. It's not the same as a regular PyPI account. |
| 57 | + |
| 58 | + |
| 59 | +Creating a workflow definition |
| 60 | +============================== |
| 61 | + |
| 62 | +GitHub CI/CD workflows are declared in YAML files stored in the |
| 63 | +``.github/workflows/`` directory of your repository. |
| 64 | + |
| 65 | +Let's create a ``.github/workflows/publish-to-test-pypi.yml`` |
| 66 | +file. |
| 67 | + |
| 68 | +Start it with a meaningful name and define the event that |
| 69 | +should make GitHub run this workflow: |
| 70 | + |
| 71 | +.. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml |
| 72 | + :language: yaml |
| 73 | + :end-before: jobs: |
| 74 | + |
| 75 | + |
| 76 | +Defining a workflow job environment |
| 77 | +=================================== |
| 78 | + |
| 79 | +Now, let's add initial setup for our job. It's a process that |
| 80 | +will execute commands that we'll define later. |
| 81 | +In this guide, we'll use Ubuntu 18.04: |
| 82 | + |
| 83 | +.. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml |
| 84 | + :language: yaml |
| 85 | + :start-after: on: |
| 86 | + :end-before: steps: |
| 87 | + |
| 88 | + |
| 89 | +Checking out the project and building distributions |
| 90 | +=================================================== |
| 91 | + |
| 92 | +Then, add the following under the ``build-n-publish`` section: |
| 93 | + |
| 94 | +.. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml |
| 95 | + :language: yaml |
| 96 | + :start-after: runs-on: |
| 97 | + :end-before: Install pep517 |
| 98 | + |
| 99 | +This will download your repository into the CI runner and then |
| 100 | +install and activate Python 3.7. |
| 101 | + |
| 102 | +And now we can build dists from source. In this example, we'll |
| 103 | +use ``pep517`` package, assuming that your project has a |
| 104 | +``pyproject.toml`` properly set up (see |
| 105 | +:pep:`517`/:pep:`518`). |
| 106 | + |
| 107 | +.. tip:: |
| 108 | + |
| 109 | + You can use any other method for building distributions as long as |
| 110 | + it produces ready-to-upload artifacts saved into the |
| 111 | + ``dist/`` folder. |
| 112 | + |
| 113 | +So add this to the steps list: |
| 114 | + |
| 115 | +.. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml |
| 116 | + :language: yaml |
| 117 | + :start-after: version: 3.7 |
| 118 | + :end-before: Actually publish to PyPI/TestPyPI |
| 119 | + |
| 120 | + |
| 121 | +Publishing the distribution to PyPI and TestPyPI |
| 122 | +================================================ |
| 123 | + |
| 124 | +Finally, add the following steps at the end: |
| 125 | + |
| 126 | +.. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml |
| 127 | + :language: yaml |
| 128 | + :start-after: Actually publish to PyPI/TestPyPI |
| 129 | + |
| 130 | +These two steps use the `pypa/gh-action-pypi-publish`_ GitHub |
| 131 | +Action: the first one uploads contents of the ``dist/`` folder |
| 132 | +into TestPyPI unconditionally and the second does that to |
| 133 | +PyPI, but only if the current commit is tagged. |
| 134 | + |
| 135 | + |
| 136 | +That's all, folks! |
| 137 | +================== |
| 138 | + |
| 139 | +Now, whenever you push a tagged commit to your Git repository remote |
| 140 | +on GitHub, this workflow will publish it to PyPI. |
| 141 | +And it'll publish any push to TestPyPI which is useful for |
| 142 | +providing test builds to your alpha users as well as making |
| 143 | +sure that your release pipeline remains healthy! |
| 144 | + |
| 145 | + |
| 146 | +.. _API token: https://pypi.org/help/#apitoken |
| 147 | +.. _GitHub Actions CI/CD: https://github.com/features/actions |
| 148 | +.. _join the waitlist: https://github.com/features/actions/signup |
| 149 | +.. _pypa/gh-action-pypi-publish: |
| 150 | + https://github.com/pypa/gh-action-pypi-publish |
| 151 | +.. _`pypa/gh-action-pypi-publish GitHub Action`: |
| 152 | + https://github.com/marketplace/actions/pypi-publish |
| 153 | +.. _Secrets: |
| 154 | + https://help.github.com/en/articles/virtual-environments-for-github-actions#creating-and-using-secrets-encrypted-variables |
0 commit comments