From b869257a3b4011f4c26df89a8758305f03764c7f Mon Sep 17 00:00:00 2001 From: chrysle Date: Wed, 24 May 2023 16:11:08 +0200 Subject: [PATCH 01/17] Add guidance for trusted publishing --- ...s-using-github-actions-ci-cd-workflows.rst | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst index 19f70f040..9b4d93dac 100644 --- a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst +++ b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @@ -51,6 +51,31 @@ Let's begin! 🚀 create it. It's not the same as a regular PyPI account. +Using trusted publishing +------------------------ + +It is also possible to authenticate to PyPI without having to provide +an `API token`_. This can be done using +PyPI's `trusted publishing`_ implementation. This is recommended +also for security reasons, since the generated tokens are created for each of your projects +individually and expire automatically. + +The following steps will lead you through creating a "pending" publisher. + +1. Go to https://pypi.org/manage/account/publishing/ +2. Now fill in the name you wish to publish your new project under, + your repository data and the name of the release workflow file + under the ``.github/`` folder, see :ref:`workflow-definition`. + Finally add the name of the GitHub Actions environment + running under your repository. + Add the trusted publisher. +3. Your "pending" publisher is no ready for its first use and will + create your project automatically once you use it + for the first time. + + +.. _workflow-definition: + Creating a workflow definition ============================== @@ -150,3 +175,4 @@ sure that your release pipeline remains healthy! https://github.com/marketplace/actions/pypi-publish .. _Secrets: https://docs.github.com/en/actions/reference/encrypted-secrets +.. _trusted publishing: https://docs.pypi.org/trusted-publishers/ From 17993ef46a407c576722645554277d1115991298 Mon Sep 17 00:00:00 2001 From: chrysle Date: Thu, 25 May 2023 10:24:39 +0200 Subject: [PATCH 02/17] Remove steps to generate and use API token --- .../publish-to-test-pypi.yml | 5 +- ...s-using-github-actions-ci-cd-workflows.rst | 68 +++++++------------ 2 files changed, 25 insertions(+), 48 deletions(-) diff --git a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml index 35a2f653d..527cf4a82 100644 --- a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml +++ b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml @@ -6,6 +6,8 @@ jobs: build-n-publish: name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI runs-on: ubuntu-latest + permissions: + id-token: write steps: - uses: actions/checkout@v3 @@ -31,10 +33,7 @@ jobs: - name: Publish distribution 📦 to Test PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: - password: ${{ secrets.TEST_PYPI_API_TOKEN }} repository-url: https://test.pypi.org/legacy/ - name: Publish distribution 📦 to PyPI if: startsWith(github.ref, 'refs/tags') uses: pypa/gh-action-pypi-publish@release/v1 - with: - password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst index 9b4d93dac..95b83886d 100644 --- a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst +++ b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @@ -17,62 +17,40 @@ It will use the `pypa/gh-action-pypi-publish GitHub Action`_. details of building platform specific projects. If you have binary components, check out :ref:`cibuildwheel`'s GitHub Action examples. -Saving credentials on GitHub -============================ - -In this guide, we'll demonstrate uploading to both -PyPI and TestPyPI, meaning that we'll have two separate sets -of credentials. And we'll need to save them in the GitHub repository -settings. - -Let's begin! 🚀 - -1. Go to https://pypi.org/manage/account/#api-tokens and - create a new `API token`_. If you have the project on PyPI - already, limit the token scope to just that project. - You can call it something like - ``GitHub Actions CI/CD — project-org/project-repo`` - in order for it to be easily distinguishable in the token - list. - **Don't close the page just yet — you won't see that token - again.** -2. In a separate browser tab or window, go to the ``Settings`` - tab of your target repository and then click on `Secrets`_ - in the left sidebar. -3. Create a new secret called ``PYPI_API_TOKEN`` and copy-paste - the token from the first step. -4. Now, go to https://test.pypi.org/manage/account/#api-tokens - and repeat the steps. Save that TestPyPI token on GitHub - as ``TEST_PYPI_API_TOKEN``. - - .. attention:: - - If you don't have a TestPyPI account, you'll need to - create it. It's not the same as a regular PyPI account. - +Configuring trusted publishing +============================== -Using trusted publishing ------------------------- +This guide relies on PyPI's `trusted publishing`_ implementation to connect +to `GitHub Actions CI/CD`_. This is recommended for security reasons, since +the generated tokens are created for each of your projects +individually and expire automatically. Otherwise you'll need to generate an +`API token`_ or provide a username/password combination for both PyPI and +TestPyPI. -It is also possible to authenticate to PyPI without having to provide -an `API token`_. This can be done using -PyPI's `trusted publishing`_ implementation. This is recommended -also for security reasons, since the generated tokens are created for each of your projects -individually and expire automatically. +Since this guide will demonstrate uploading to both +PyPI and TestPyPI, we'll need two trusted publishers configured. +The following steps will lead you through creating the "pending" publishers. -The following steps will lead you through creating a "pending" publisher. +Let's begin! 🚀 1. Go to https://pypi.org/manage/account/publishing/ -2. Now fill in the name you wish to publish your new project under, +2. Fill in the name you wish to publish your new project under, your repository data and the name of the release workflow file under the ``.github/`` folder, see :ref:`workflow-definition`. Finally add the name of the GitHub Actions environment running under your repository. - Add the trusted publisher. -3. Your "pending" publisher is no ready for its first use and will - create your project automatically once you use it + Register the trusted publisher. +3. Now, go to https://test.pypi.org/manage/account/publishing/ and repeat + the second step. +4. Your "pending" publishers are now ready for their first use and will + create your projects automatically once you use them for the first time. + .. attention:: + + If you don't have a TestPyPI account, you'll need to + create it. It's not the same as a regular PyPI account. + .. _workflow-definition: From 4c5786743a9fe1fcb0cf8c57ef6713bef33ae372 Mon Sep 17 00:00:00 2001 From: chrysle Date: Mon, 29 May 2023 09:28:11 +0200 Subject: [PATCH 03/17] Apply feedback from code review --- .../publish-to-test-pypi.yml | 44 +++++++++++-- ...s-using-github-actions-ci-cd-workflows.rst | 63 ++++++++++++------- 2 files changed, 80 insertions(+), 27 deletions(-) diff --git a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml index 527cf4a82..f71b44f27 100644 --- a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml +++ b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml @@ -3,9 +3,45 @@ name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI on: push jobs: - build-n-publish: - name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI + build-n-publish-pypi: + name: Build and publish Python 🐍 distributions 📦 to PyPI runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/ + permissions: + id-token: write + + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.x" + - name: Install pypa/build + run: >- + python3 -m + pip install + build + --user + - name: Build a binary wheel and a source tarball + run: >- + python3 -m + build + --sdist + --wheel + --outdir dist/ + . + # Actually publish to PyPI + - name: Publish distribution 📦 to PyPI + if: startsWith(github.ref, 'refs/tags') + uses: pypa/gh-action-pypi-publish@release/v1 + build-n-publish-testpypi: + name: Build and publish Python 🐍 distributions 📦 to TestPyPI + runs-on: ubuntu-latest + environment: + name: testpypi + url: https://test.pypi.org/p/ permissions: id-token: write @@ -29,11 +65,7 @@ jobs: --wheel --outdir dist/ . - # Actually publish to PyPI/TestPyPI - name: Publish distribution 📦 to Test PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: repository-url: https://test.pypi.org/legacy/ - - name: Publish distribution 📦 to PyPI - if: startsWith(github.ref, 'refs/tags') - uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst index 95b83886d..d8b6b7d2f 100644 --- a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst +++ b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @@ -24,19 +24,23 @@ This guide relies on PyPI's `trusted publishing`_ implementation to connect to `GitHub Actions CI/CD`_. This is recommended for security reasons, since the generated tokens are created for each of your projects individually and expire automatically. Otherwise you'll need to generate an -`API token`_ or provide a username/password combination for both PyPI and -TestPyPI. +`API token`_ for both PyPI and TestPyPI. In case of publishing to third-party +indexes like :doc:`devpi `, you will need to provide a +username/password combination. Since this guide will demonstrate uploading to both PyPI and TestPyPI, we'll need two trusted publishers configured. -The following steps will lead you through creating the "pending" publishers. +The following steps will lead you through creating the "pending" publishers +for your new project. However it is also possible to add `trusted publishing`_ +to any pre-existing project, if you are its owner. Let's begin! 🚀 -1. Go to https://pypi.org/manage/account/publishing/ +1. Go to https://pypi.org/manage/account/publishing/. 2. Fill in the name you wish to publish your new project under, - your repository data and the name of the release workflow file - under the ``.github/`` folder, see :ref:`workflow-definition`. + your GitHub username and repository name and + the name of the release workflow file under + the ``.github/`` folder, see :ref:`workflow-definition`. Finally add the name of the GitHub Actions environment running under your repository. Register the trusted publisher. @@ -74,21 +78,24 @@ should make GitHub run this workflow: Defining a workflow job environment =================================== -Now, let's add initial setup for our job. It's a process that -will execute commands that we'll define later. +We will have to define two jobs to publish to PyPI +and TestPyPI respectively. + +Now, let's add initial setup for our job that will publish to PyPI. +It's a process that will execute commands that we'll define later. In this guide, we'll use the latest stable Ubuntu LTS version provided by GitHub Actions: .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml :start-after: on: - :end-before: steps: + :end-before: environment: Checking out the project and building distributions =================================================== -Then, add the following under the ``build-n-publish`` section: +Then, add the following under the ``build-n-publish-pypi`` section: .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml @@ -96,7 +103,10 @@ Then, add the following under the ``build-n-publish`` section: :end-before: Install pypa/build This will download your repository into the CI runner and then -install and activate the newest available Python 3 release. +install and activate the newest available Python 3 release. It +also defines the package index to publish to, PyPI, and grants +a permission to the action that is mandatory for trusted +publishing. And now we can build dists from source. In this example, we'll use ``build`` package. @@ -114,25 +124,36 @@ So add this to the steps list: .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml :start-after: version: "3.x" - :end-before: Actually publish to PyPI/TestPyPI + :end-before: Actually publish to PyPI -Publishing the distribution to PyPI and TestPyPI -================================================ +Publishing the distribution to PyPI +=================================== Finally, add the following steps at the end: .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml - :start-after: Actually publish to PyPI/TestPyPI - -These two steps use the `pypa/gh-action-pypi-publish`_ GitHub -Action: the first one uploads contents of the ``dist/`` folder -into TestPyPI unconditionally and the second does that to -PyPI, but only if the current commit is tagged. It is recommended -you use the latest release tag; a tool like GitHub's dependabot can keep + :start-after: Actually publish to PyPI + :end-before: build-n-publish-testpypi + +This step uses the `pypa/gh-action-pypi-publish`_ GitHub +Action: It uploads the contents of the ``dist/`` folder +into PyPI unconditionally, but only if the current commit +is tagged. It is recommended you use the latest release +tag; a tool like GitHub's dependabot can keep these updated regularly. +Separate workflow for publishing to TestPyPI +============================================ + +Now, repeat these steps and create another job for +publishing to the TestPyPI package index under the ``jobs`` +section: + +.. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml + :language: yaml + :start-after: uses: pypa/gh-action-pypi-publish@release/v1 That's all, folks! ================== From b998292a30a71ecbf2cc68de58148ef752d2e996 Mon Sep 17 00:00:00 2001 From: chrysle Date: Fri, 2 Jun 2023 16:40:04 +0200 Subject: [PATCH 04/17] Temporary state --- .../publish-to-test-pypi.yml | 57 +++++++++---------- ...s-using-github-actions-ci-cd-workflows.rst | 3 +- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml index f71b44f27..c6e7c5091 100644 --- a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml +++ b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml @@ -3,15 +3,10 @@ name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI on: push jobs: - build-n-publish-pypi: - name: Build and publish Python 🐍 distributions 📦 to PyPI + build: + name: Build the source package runs-on: ubuntu-latest - environment: - name: pypi - url: https://pypi.org/p/ - permissions: - id-token: write - + steps: - uses: actions/checkout@v3 - name: Set up Python @@ -28,11 +23,25 @@ jobs: run: >- python3 -m build - --sdist - --wheel - --outdir dist/ - . - # Actually publish to PyPI + - name: Store the distribution packages + uses: actions/upload-artifact@v3 + with: + name: python-package-distributions + build-n-publish-pypi: + name: Build and publish Python 🐍 distributions 📦 to PyPI + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/ + permissions: + id-token: write + + steps: + - name: Download all the dists + uses: actions/download-artifact@v3 + with: + name: python-package-distributions + path: dist/ - name: Publish distribution 📦 to PyPI if: startsWith(github.ref, 'refs/tags') uses: pypa/gh-action-pypi-publish@release/v1 @@ -46,25 +55,11 @@ jobs: id-token: write steps: - - uses: actions/checkout@v3 - - name: Set up Python - uses: actions/setup-python@v4 + - name: Download all the dists + uses: actions/download-artifact@v3 with: - python-version: "3.x" - - name: Install pypa/build - run: >- - python3 -m - pip install - build - --user - - name: Build a binary wheel and a source tarball - run: >- - python3 -m - build - --sdist - --wheel - --outdir dist/ - . + name: python-package-distributions + path: dist/ - name: Publish distribution 📦 to Test PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: diff --git a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst index d8b6b7d2f..e9b4666da 100644 --- a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst +++ b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @@ -79,7 +79,8 @@ Defining a workflow job environment =================================== We will have to define two jobs to publish to PyPI -and TestPyPI respectively. +and TestPyPI respectively, and an additional job to +build the distribution packages. Now, let's add initial setup for our job that will publish to PyPI. It's a process that will execute commands that we'll define later. From 6c43bf4c6b61dbfb3a9128b7cbe75c26edd63142 Mon Sep 17 00:00:00 2001 From: chrysle Date: Tue, 6 Jun 2023 17:36:26 +0200 Subject: [PATCH 05/17] Move build steps into separate job --- ...s-using-github-actions-ci-cd-workflows.rst | 78 +++++++++---------- 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst index e9b4666da..44e626385 100644 --- a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst +++ b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @@ -8,7 +8,9 @@ popular choice is having a workflow that's triggered by a ``push`` event. This guide shows you how to publish a Python distribution whenever a tagged commit is pushed. -It will use the `pypa/gh-action-pypi-publish GitHub Action`_. +It will use the `pypa/gh-action-pypi-publish GitHub Action`_ for +publishing and `upload-artifact`_ and `download-artifact`_ actions +for temporarily storing and downloading the source packages. .. attention:: @@ -74,59 +76,47 @@ should make GitHub run this workflow: :language: yaml :end-before: jobs: - -Defining a workflow job environment -=================================== +Checking out the project and building distributions +=================================================== We will have to define two jobs to publish to PyPI and TestPyPI respectively, and an additional job to build the distribution packages. -Now, let's add initial setup for our job that will publish to PyPI. -It's a process that will execute commands that we'll define later. -In this guide, we'll use the latest stable Ubuntu LTS version -provided by GitHub Actions: - -.. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml - :language: yaml - :start-after: on: - :end-before: environment: - - -Checking out the project and building distributions -=================================================== - -Then, add the following under the ``build-n-publish-pypi`` section: +First, we'll define the job for building the dist packages of +your project and storing them for later use: .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml - :start-after: runs-on: + :start-after: jobs: :end-before: Install pypa/build This will download your repository into the CI runner and then -install and activate the newest available Python 3 release. It -also defines the package index to publish to, PyPI, and grants -a permission to the action that is mandatory for trusted -publishing. - -And now we can build dists from source. In this example, we'll -use ``build`` package. - -.. tip:: - - You can use any other method for building distributions as long as - it produces ready-to-upload artifacts saved into the - ``dist/`` folder. You can even use ``actions/upload-artifact`` and - ``actions/download-artifact`` to tranfer files between jobs or make them - accessable for download from the web CI interface. +install and activate the newest available Python 3 release. +And now we can build the dists from source and store them. +In this example, we'll use the ``build`` package. So add this to the steps list: .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml :start-after: version: "3.x" - :end-before: Actually publish to PyPI + :end-before: build-n-publish-pypi + +Defining a workflow job environment +=================================== +Now, let's add initial setup for our job that will publish to PyPI. +It's a process that will execute commands that we'll define later. +In this guide, we'll use the latest stable Ubuntu LTS version +provided by GitHub Actions. This also defines the package index +to publish to, PyPI, and grants a permission to the action that +is mandatory for trusted publishing. + +.. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml + :language: yaml + :start-after: name: python-package-distributions + :end-before: steps: Publishing the distribution to PyPI =================================== @@ -135,14 +125,14 @@ Finally, add the following steps at the end: .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml - :start-after: Actually publish to PyPI - :end-before: build-n-publish-testpypi + :lines: 39-47 This step uses the `pypa/gh-action-pypi-publish`_ GitHub -Action: It uploads the contents of the ``dist/`` folder -into PyPI unconditionally, but only if the current commit -is tagged. It is recommended you use the latest release -tag; a tool like GitHub's dependabot can keep +Action: After the stored distribution package has been +downloaded by the `download-artifact`_ action, it uploads +the contents of the ``dist/`` folder into PyPI unconditionally, +but only if the current commit is tagged. It is recommended you +use the latest release tag; a tool like GitHub's dependabot can keep these updated regularly. Separate workflow for publishing to TestPyPI @@ -173,6 +163,10 @@ sure that your release pipeline remains healthy! https://github.com/pypa/gh-action-pypi-publish .. _`pypa/gh-action-pypi-publish GitHub Action`: https://github.com/marketplace/actions/pypi-publish +.. _`download-artifact`: + https://github.com/actions/download-artifact +.. _`upload-artifact`: + https://github.com/actions/upload-artifact .. _Secrets: https://docs.github.com/en/actions/reference/encrypted-secrets .. _trusted publishing: https://docs.pypi.org/trusted-publishers/ From 9fe96b6955da3331e86f9c9068d28c249aad68e9 Mon Sep 17 00:00:00 2001 From: chrysle Date: Tue, 13 Jun 2023 17:10:59 +0200 Subject: [PATCH 06/17] Apply suggestions from code review Co-authored-by: Sviatoslav Sydorenko --- .../publish-to-test-pypi.yml | 7 +++---- ...n-releases-using-github-actions-ci-cd-workflows.rst | 10 +++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml index c6e7c5091..f82ab400a 100644 --- a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml +++ b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml @@ -6,7 +6,6 @@ jobs: build: name: Build the source package runs-on: ubuntu-latest - steps: - uses: actions/checkout@v3 - name: Set up Python @@ -26,8 +25,8 @@ jobs: - name: Store the distribution packages uses: actions/upload-artifact@v3 with: - name: python-package-distributions - build-n-publish-pypi: + name: python-package-distributions + publish-to-pypi: name: Build and publish Python 🐍 distributions 📦 to PyPI runs-on: ubuntu-latest environment: @@ -45,7 +44,7 @@ jobs: - name: Publish distribution 📦 to PyPI if: startsWith(github.ref, 'refs/tags') uses: pypa/gh-action-pypi-publish@release/v1 - build-n-publish-testpypi: + publish-to-testpypi: name: Build and publish Python 🐍 distributions 📦 to TestPyPI runs-on: ubuntu-latest environment: diff --git a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst index 44e626385..d917ca21b 100644 --- a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst +++ b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @@ -9,7 +9,7 @@ popular choice is having a workflow that's triggered by a This guide shows you how to publish a Python distribution whenever a tagged commit is pushed. It will use the `pypa/gh-action-pypi-publish GitHub Action`_ for -publishing and `upload-artifact`_ and `download-artifact`_ actions +publishing. It also uses GitHub's `upload-artifact`_ and `download-artifact`_ actions for temporarily storing and downloading the source packages. .. attention:: @@ -40,11 +40,11 @@ Let's begin! 🚀 1. Go to https://pypi.org/manage/account/publishing/. 2. Fill in the name you wish to publish your new project under, - your GitHub username and repository name and - the name of the release workflow file under - the ``.github/`` folder, see :ref:`workflow-definition`. + your GitHub username and repository name and + the name of the release workflow file under + the ``.github/`` folder, see :ref:`workflow-definition`. Finally add the name of the GitHub Actions environment - running under your repository. + set up under your repository. Register the trusted publisher. 3. Now, go to https://test.pypi.org/manage/account/publishing/ and repeat the second step. From 25ef74516bd1f90289e1aba59cc28b46005dd220 Mon Sep 17 00:00:00 2001 From: chrysle Date: Tue, 13 Jun 2023 17:45:10 +0200 Subject: [PATCH 07/17] Apply more suggestions and fix included fragments --- .../publish-to-test-pypi.yml | 4 +++- ...s-using-github-actions-ci-cd-workflows.rst | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml index f82ab400a..d9812596d 100644 --- a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml +++ b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml @@ -2,6 +2,9 @@ name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI on: push +# Only trigger this for tag changes. +if: startsWith(github.ref, 'refs/tags/') + jobs: build: name: Build the source package @@ -42,7 +45,6 @@ jobs: name: python-package-distributions path: dist/ - name: Publish distribution 📦 to PyPI - if: startsWith(github.ref, 'refs/tags') uses: pypa/gh-action-pypi-publish@release/v1 publish-to-testpypi: name: Build and publish Python 🐍 distributions 📦 to TestPyPI diff --git a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst index d917ca21b..76aba47b6 100644 --- a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst +++ b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @@ -44,10 +44,11 @@ Let's begin! 🚀 the name of the release workflow file under the ``.github/`` folder, see :ref:`workflow-definition`. Finally add the name of the GitHub Actions environment - set up under your repository. + (``pypi``) we're going set up under your repository. Register the trusted publisher. 3. Now, go to https://test.pypi.org/manage/account/publishing/ and repeat - the second step. + the second step, but now enter ``testpypi`` as the name of the + GitHub Actions environment. 4. Your "pending" publishers are now ready for their first use and will create your projects automatically once you use them for the first time. @@ -76,6 +77,11 @@ should make GitHub run this workflow: :language: yaml :end-before: jobs: +This will also assure that the release workflow is only triggered +if the current commit is tagged. It is recommended you use the +latest release tag; a tool like GitHub's dependabot can keep +these updated regularly. + Checking out the project and building distributions =================================================== @@ -101,7 +107,7 @@ So add this to the steps list: .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml :start-after: version: "3.x" - :end-before: build-n-publish-pypi + :end-before: publish-to-pypi Defining a workflow job environment =================================== @@ -125,15 +131,12 @@ Finally, add the following steps at the end: .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml - :lines: 39-47 + :lines: 41-48 This step uses the `pypa/gh-action-pypi-publish`_ GitHub Action: After the stored distribution package has been downloaded by the `download-artifact`_ action, it uploads -the contents of the ``dist/`` folder into PyPI unconditionally, -but only if the current commit is tagged. It is recommended you -use the latest release tag; a tool like GitHub's dependabot can keep -these updated regularly. +the contents of the ``dist/`` folder into PyPI unconditionally. Separate workflow for publishing to TestPyPI ============================================ From 1851d9f5d7841b68dd4384d69b281c56885dee84 Mon Sep 17 00:00:00 2001 From: chrysle Date: Fri, 30 Jun 2023 08:56:18 +0200 Subject: [PATCH 08/17] Apply suggestions from code review Co-authored-by: Sviatoslav Sydorenko --- .../publish-to-test-pypi.yml | 28 +++++++++++++------ ...s-using-github-actions-ci-cd-workflows.rst | 17 ++++++----- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml index d9812596d..3c418017f 100644 --- a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml +++ b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml @@ -2,13 +2,11 @@ name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI on: push -# Only trigger this for tag changes. -if: startsWith(github.ref, 'refs/tags/') - jobs: build: name: Build the source package runs-on: ubuntu-latest + steps: - uses: actions/checkout@v3 - name: Set up Python @@ -22,15 +20,19 @@ jobs: build --user - name: Build a binary wheel and a source tarball - run: >- - python3 -m - build + run: python3 -m build - name: Store the distribution packages uses: actions/upload-artifact@v3 with: name: python-package-distributions + path: dist/ + publish-to-pypi: - name: Build and publish Python 🐍 distributions 📦 to PyPI + name: >- + Publish Python 🐍 distributions 📦 to PyPI + and sign them with Sigstore + needs: + - build runs-on: ubuntu-latest environment: name: pypi @@ -46,8 +48,18 @@ jobs: path: dist/ - name: Publish distribution 📦 to PyPI uses: pypa/gh-action-pypi-publish@release/v1 + - name: Sign the dists with Sigstore + uses: sigstore/gh-action-sigstore-python@v1.2.3 + with: + inputs: >- + ./dist/*.tar.gz + ./dist/*.whl + publish-to-testpypi: name: Build and publish Python 🐍 distributions 📦 to TestPyPI + if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes + needs: + - build runs-on: ubuntu-latest environment: name: testpypi @@ -61,7 +73,7 @@ jobs: with: name: python-package-distributions path: dist/ - - name: Publish distribution 📦 to Test PyPI + - name: Publish distribution 📦 to TestPyPI uses: pypa/gh-action-pypi-publish@release/v1 with: repository-url: https://test.pypi.org/legacy/ diff --git a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst index 76aba47b6..94f35a0dd 100644 --- a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst +++ b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @@ -25,9 +25,9 @@ Configuring trusted publishing This guide relies on PyPI's `trusted publishing`_ implementation to connect to `GitHub Actions CI/CD`_. This is recommended for security reasons, since the generated tokens are created for each of your projects -individually and expire automatically. Otherwise you'll need to generate an +individually and expire automatically. Otherwise, you'll need to generate an `API token`_ for both PyPI and TestPyPI. In case of publishing to third-party -indexes like :doc:`devpi `, you will need to provide a +indexes like :doc:`devpi `, you may need to provide a username/password combination. Since this guide will demonstrate uploading to both @@ -77,7 +77,7 @@ should make GitHub run this workflow: :language: yaml :end-before: jobs: -This will also assure that the release workflow is only triggered +This will also ensure that the release workflow is only triggered if the current commit is tagged. It is recommended you use the latest release tag; a tool like GitHub's dependabot can keep these updated regularly. @@ -115,9 +115,11 @@ Defining a workflow job environment Now, let's add initial setup for our job that will publish to PyPI. It's a process that will execute commands that we'll define later. In this guide, we'll use the latest stable Ubuntu LTS version -provided by GitHub Actions. This also defines the package index -to publish to, PyPI, and grants a permission to the action that -is mandatory for trusted publishing. +provided by GitHub Actions. This also defines a GitHub Environment +for the job to run in its context and a URL to be displayed in GitHub's +UI nicely. Additionally, it allows aqcuiring an OpenID Connect token +which is mandartory that the ``pypi-publish`` actions needs to +implement secretless trusted publishing to PyPI. .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml @@ -134,9 +136,10 @@ Finally, add the following steps at the end: :lines: 41-48 This step uses the `pypa/gh-action-pypi-publish`_ GitHub -Action: After the stored distribution package has been +Action: after the stored distribution package has been downloaded by the `download-artifact`_ action, it uploads the contents of the ``dist/`` folder into PyPI unconditionally. +This job also signs the artifacts with Sigstore right after publishing them to PyPI. Separate workflow for publishing to TestPyPI ============================================ From 3653382278caaf4a9bc49801545d1a24e4973d2c Mon Sep 17 00:00:00 2001 From: chrysle Date: Fri, 30 Jun 2023 14:39:48 +0200 Subject: [PATCH 09/17] Apply further improvements --- .../publish-to-test-pypi.yml | 6 +-- ...s-using-github-actions-ci-cd-workflows.rst | 42 ++++++++++++++----- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml index 3c418017f..898da663e 100644 --- a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml +++ b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml @@ -1,10 +1,10 @@ -name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI +name: Publish Python 🐍 distribution packages 📦 to PyPI and TestPyPI on: push jobs: build: - name: Build the source package + name: Build distribution packages runs-on: ubuntu-latest steps: @@ -29,7 +29,7 @@ jobs: publish-to-pypi: name: >- - Publish Python 🐍 distributions 📦 to PyPI + Publish Python 🐍 distribution packages 📦 to PyPI and sign them with Sigstore needs: - build diff --git a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst index 94f35a0dd..51a3ea598 100644 --- a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst +++ b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @@ -33,13 +33,25 @@ username/password combination. Since this guide will demonstrate uploading to both PyPI and TestPyPI, we'll need two trusted publishers configured. The following steps will lead you through creating the "pending" publishers -for your new project. However it is also possible to add `trusted publishing`_ -to any pre-existing project, if you are its owner. +for your new :term:`PyPI project `. +However it is also possible to add `trusted publishing`_ to any +pre-existing project, if you are its owner. + + .. attention:: + + If you followed earlier versions of this guide, you will + have created the secrets ``PYPI_API_TOKEN`` and ``TEST_PYPI_API_TOKEN`` + for direct PyPI and TestPyPI access. These are obsolete now and + you should remove them from your GitHub repository and revoke + them in your PyPI and TestPyPI account settings. + Let's begin! 🚀 1. Go to https://pypi.org/manage/account/publishing/. -2. Fill in the name you wish to publish your new project under, +2. Fill in the name you wish to publish your new + :term:`PyPI project ` under + (the ``name`` value in your ``setup.cfg`` or ``pyproject.toml``), your GitHub username and repository name and the name of the release workflow file under the ``.github/`` folder, see :ref:`workflow-definition`. @@ -53,12 +65,18 @@ Let's begin! 🚀 create your projects automatically once you use them for the first time. - .. attention:: + .. note:: If you don't have a TestPyPI account, you'll need to create it. It's not the same as a regular PyPI account. + .. hint:: + + For security reasons, you should require manual approval + on each run for the ``pypi`` environment. + + .. _workflow-definition: Creating a workflow definition @@ -79,8 +97,7 @@ should make GitHub run this workflow: This will also ensure that the release workflow is only triggered if the current commit is tagged. It is recommended you use the -latest release tag; a tool like GitHub's dependabot can keep -these updated regularly. +latest release tag. Checking out the project and building distributions =================================================== @@ -123,7 +140,7 @@ implement secretless trusted publishing to PyPI. .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml - :start-after: name: python-package-distributions + :start-after: path: dist/ :end-before: steps: Publishing the distribution to PyPI @@ -133,13 +150,15 @@ Finally, add the following steps at the end: .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml - :lines: 41-48 + :start-after: id-token: write + :end-before: publish-to-testpypi: This step uses the `pypa/gh-action-pypi-publish`_ GitHub Action: after the stored distribution package has been downloaded by the `download-artifact`_ action, it uploads the contents of the ``dist/`` folder into PyPI unconditionally. -This job also signs the artifacts with Sigstore right after publishing them to PyPI. +This job also signs the artifacts with the `sigstore/gh-action-sigstore-python`_ +GitHub Action publishing them to PyPI. Separate workflow for publishing to TestPyPI ============================================ @@ -150,7 +169,8 @@ section: .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml - :start-after: uses: pypa/gh-action-pypi-publish@release/v1 + :start-after: ./dist/*.whl + That's all, folks! ================== @@ -173,6 +193,8 @@ sure that your release pipeline remains healthy! https://github.com/actions/download-artifact .. _`upload-artifact`: https://github.com/actions/upload-artifact +.. _`sigstore/gh-action-sigstore-python`: + https://github.com/marketplace/actions/gh-action-sigstore-python .. _Secrets: https://docs.github.com/en/actions/reference/encrypted-secrets .. _trusted publishing: https://docs.pypi.org/trusted-publishers/ From 4580825dae3209228331334c3d7cd2d57134e533 Mon Sep 17 00:00:00 2001 From: chrysle Date: Mon, 24 Jul 2023 16:22:54 +0200 Subject: [PATCH 10/17] Apply suggestions from code review Co-authored-by: Sviatoslav Sydorenko --- .../github-actions-ci-cd-sample/publish-to-test-pypi.yml | 4 ++-- ...bution-releases-using-github-actions-ci-cd-workflows.rst | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml index 898da663e..7026aad5f 100644 --- a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml +++ b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml @@ -1,4 +1,4 @@ -name: Publish Python 🐍 distribution packages 📦 to PyPI and TestPyPI +name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI on: push @@ -29,7 +29,7 @@ jobs: publish-to-pypi: name: >- - Publish Python 🐍 distribution packages 📦 to PyPI + Publish Python 🐍 distribution 📦 to PyPI and sign them with Sigstore needs: - build diff --git a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst index 51a3ea598..234593670 100644 --- a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst +++ b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @@ -39,11 +39,11 @@ pre-existing project, if you are its owner. .. attention:: - If you followed earlier versions of this guide, you will + If you followed earlier versions of this guide, you have created the secrets ``PYPI_API_TOKEN`` and ``TEST_PYPI_API_TOKEN`` for direct PyPI and TestPyPI access. These are obsolete now and you should remove them from your GitHub repository and revoke - them in your PyPI and TestPyPI account settings. + them in your PyPI and TestPyPI account settings in case you are replacing your old setup with the new one. Let's begin! 🚀 @@ -135,7 +135,7 @@ In this guide, we'll use the latest stable Ubuntu LTS version provided by GitHub Actions. This also defines a GitHub Environment for the job to run in its context and a URL to be displayed in GitHub's UI nicely. Additionally, it allows aqcuiring an OpenID Connect token -which is mandartory that the ``pypi-publish`` actions needs to +which is mandatory that the ``pypi-publish`` actions needs to implement secretless trusted publishing to PyPI. .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml From 1f4a242fc383e276422af9f7168e682d237d3d91 Mon Sep 17 00:00:00 2001 From: chrysle Date: Sat, 26 Aug 2023 11:18:49 +0200 Subject: [PATCH 11/17] Apply further suggestions and improvements Add `sphinx-toolbox` dependency. --- requirements.txt | 1 + source/conf.py | 1 + .../publish-to-test-pypi.yml | 52 +++++++++----- ...s-using-github-actions-ci-cd-workflows.rst | 67 ++++++++++++------- 4 files changed, 79 insertions(+), 42 deletions(-) diff --git a/requirements.txt b/requirements.txt index 125f0cf33..17492e03c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ sphinx-inline-tabs==2021.4.11b9 python-docs-theme==2022.1 sphinx-copybutton==0.5.0 pypa-docs-theme @ git+https://github.com/pypa/pypa-docs-theme.git +sphinx-toolbox==3.5.0 diff --git a/source/conf.py b/source/conf.py index 7ff60c18c..9113b8c68 100644 --- a/source/conf.py +++ b/source/conf.py @@ -36,6 +36,7 @@ 'sphinx.ext.todo', 'sphinx_inline_tabs', 'sphinx_copybutton', + 'sphinx_toolbox.collapse', ] # config for copy button diff --git a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml index 7026aad5f..28663d51f 100644 --- a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml +++ b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml @@ -1,10 +1,10 @@ -name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI +name: Publish Python 🐍 distribution 📦 to PyPI and TestPyPI on: push jobs: build: - name: Build distribution packages + name: Build distribution 📦 runs-on: ubuntu-latest steps: @@ -30,34 +30,52 @@ jobs: publish-to-pypi: name: >- Publish Python 🐍 distribution 📦 to PyPI - and sign them with Sigstore + if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes needs: - build runs-on: ubuntu-latest environment: name: pypi + # Fill in your project (e.g. repository) name + # for url: https://pypi.org/p/ permissions: id-token: write steps: - name: Download all the dists - uses: actions/download-artifact@v3 - with: - name: python-package-distributions - path: dist/ - - name: Publish distribution 📦 to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - - name: Sign the dists with Sigstore - uses: sigstore/gh-action-sigstore-python@v1.2.3 - with: - inputs: >- - ./dist/*.tar.gz - ./dist/*.whl + uses: actions/download-artifact@v3 + with: + name: python-package-distributions + path: dist/ + - name: Publish distribution 📦 to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + + github-release: + name: >- + Sign the Python 🐍 distribution 📦 with Sigstore + and upload them to GitHub Release + needs: + - publish-to-pypi + steps: + - name: Sign the dists with Sigstore + uses: sigstore/gh-action-sigstore-python@v1.2.3 + with: + inputs: >- + ./dist/*.tar.gz + ./dist/*.whl + - name: Upload artifact signatures to GitHub Release + # Confusingly, this action also supports updating releases, not + # just creating them. This is what we want here, since we've manually + # created the release above. + uses: softprops/action-gh-release@v1 + with: + # dist/ contains the built packages, which smoketest-artifacts/ + # contains the signatures and certificates. + files: dist/** publish-to-testpypi: - name: Build and publish Python 🐍 distributions 📦 to TestPyPI - if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes + name: Publish Python 🐍 distribution 📦 to TestPyPI needs: - build runs-on: ubuntu-latest diff --git a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst index 234593670..500379c9f 100644 --- a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst +++ b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @@ -9,7 +9,7 @@ popular choice is having a workflow that's triggered by a This guide shows you how to publish a Python distribution whenever a tagged commit is pushed. It will use the `pypa/gh-action-pypi-publish GitHub Action`_ for -publishing. It also uses GitHub's `upload-artifact`_ and `download-artifact`_ actions +publishing. It also uses GitHub's `upload-artifact`_ and `download-artifact`_ actions for temporarily storing and downloading the source packages. .. attention:: @@ -23,7 +23,7 @@ Configuring trusted publishing ============================== This guide relies on PyPI's `trusted publishing`_ implementation to connect -to `GitHub Actions CI/CD`_. This is recommended for security reasons, since +to `GitHub Actions CI/CD`_. This is recommended for security reasons, since the generated tokens are created for each of your projects individually and expire automatically. Otherwise, you'll need to generate an `API token`_ for both PyPI and TestPyPI. In case of publishing to third-party @@ -31,7 +31,7 @@ indexes like :doc:`devpi `, you may need to provide a username/password combination. Since this guide will demonstrate uploading to both -PyPI and TestPyPI, we'll need two trusted publishers configured. +PyPI and TestPyPI, we'll need two trusted publishers configured. The following steps will lead you through creating the "pending" publishers for your new :term:`PyPI project `. However it is also possible to add `trusted publishing`_ to any @@ -52,8 +52,8 @@ Let's begin! 🚀 2. Fill in the name you wish to publish your new :term:`PyPI project ` under (the ``name`` value in your ``setup.cfg`` or ``pyproject.toml``), - your GitHub username and repository name and - the name of the release workflow file under + the GitHub repository owner's name (org or user) + and repository name and the name of the release workflow file under the ``.github/`` folder, see :ref:`workflow-definition`. Finally add the name of the GitHub Actions environment (``pypi``) we're going set up under your repository. @@ -61,8 +61,8 @@ Let's begin! 🚀 3. Now, go to https://test.pypi.org/manage/account/publishing/ and repeat the second step, but now enter ``testpypi`` as the name of the GitHub Actions environment. -4. Your "pending" publishers are now ready for their first use and will - create your projects automatically once you use them +4. Your "pending" publishers are now ready for their first use and will + create your projects automatically once you use them for the first time. .. note:: @@ -95,23 +95,19 @@ should make GitHub run this workflow: :language: yaml :end-before: jobs: -This will also ensure that the release workflow is only triggered -if the current commit is tagged. It is recommended you use the -latest release tag. - Checking out the project and building distributions =================================================== -We will have to define two jobs to publish to PyPI -and TestPyPI respectively, and an additional job to +We will have to define two jobs to publish to PyPI +and TestPyPI respectively, and an additional job to build the distribution packages. -First, we'll define the job for building the dist packages of +First, we'll define the job for building the dist packages of your project and storing them for later use: .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml - :start-after: jobs: + :start-at: jobs: :end-before: Install pypa/build This will download your repository into the CI runner and then @@ -123,7 +119,7 @@ So add this to the steps list: .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml - :start-after: version: "3.x" + :start-at: Install pypa/build :end-before: publish-to-pypi Defining a workflow job environment @@ -135,14 +131,18 @@ In this guide, we'll use the latest stable Ubuntu LTS version provided by GitHub Actions. This also defines a GitHub Environment for the job to run in its context and a URL to be displayed in GitHub's UI nicely. Additionally, it allows aqcuiring an OpenID Connect token -which is mandatory that the ``pypi-publish`` actions needs to -implement secretless trusted publishing to PyPI. +that the ``pypi-publish`` actions needs to implement secretless +trusted publishing to PyPI. .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml :start-after: path: dist/ :end-before: steps: +This will also ensure that the PyPI publishing workflow is only triggered +if the current commit is tagged. It is recommended you use the +latest release tag. + Publishing the distribution to PyPI =================================== @@ -151,14 +151,24 @@ Finally, add the following steps at the end: .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml :start-after: id-token: write - :end-before: publish-to-testpypi: + :end-before: github-release: This step uses the `pypa/gh-action-pypi-publish`_ GitHub -Action: after the stored distribution package has been -downloaded by the `download-artifact`_ action, it uploads +Action: after the stored distribution package has been +downloaded by the `download-artifact`_ action, it uploads the contents of the ``dist/`` folder into PyPI unconditionally. -This job also signs the artifacts with the `sigstore/gh-action-sigstore-python`_ -GitHub Action publishing them to PyPI. + +Signing the distribution packages +================================= + +This additional job signs the distribution packages with the +`sigstore/gh-action-sigstore-python GitHub Action`_ and then uploads +them to GitHub Release. + +.. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml + :language: yaml + :start-at: github-release: + :end-before: publish-to-testpypi Separate workflow for publishing to TestPyPI ============================================ @@ -169,8 +179,15 @@ section: .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml - :start-after: ./dist/*.whl + :start-at: publish-to-testpypi + +The whole CD workflow +===================== + +.. collapse:: Load file + .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml + :language: yaml That's all, folks! ================== @@ -193,7 +210,7 @@ sure that your release pipeline remains healthy! https://github.com/actions/download-artifact .. _`upload-artifact`: https://github.com/actions/upload-artifact -.. _`sigstore/gh-action-sigstore-python`: +.. _`sigstore/gh-action-sigstore-python GitHub Action`: https://github.com/marketplace/actions/gh-action-sigstore-python .. _Secrets: https://docs.github.com/en/actions/reference/encrypted-secrets From 7b86e9c2d1e6c8cd27f3d3930261526e8ca96b97 Mon Sep 17 00:00:00 2001 From: chrysle Date: Tue, 12 Sep 2023 18:19:47 +0200 Subject: [PATCH 12/17] Apply suggestions from code review Co-authored-by: Sviatoslav Sydorenko --- .../publish-to-test-pypi.yml | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml index 28663d51f..4021ac585 100644 --- a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml +++ b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml @@ -40,16 +40,16 @@ jobs: # for url: https://pypi.org/p/ permissions: - id-token: write + id-token: write # IMPORTANT: mandatory for trusted publishing steps: - - name: Download all the dists - uses: actions/download-artifact@v3 - with: - name: python-package-distributions - path: dist/ - - name: Publish distribution 📦 to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + - name: Download all the dists + uses: actions/download-artifact@v3 + with: + name: python-package-distributions + path: dist/ + - name: Publish distribution 📦 to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 github-release: name: >- @@ -57,6 +57,12 @@ jobs: and upload them to GitHub Release needs: - publish-to-pypi + runs-on: ubuntu-latest + + permissions: + contents: write # IMPORTANT: mandatory for making GitHub Releases + id-token: write # IMPORTANT: mandatory for sigstore + steps: - name: Sign the dists with Sigstore uses: sigstore/gh-action-sigstore-python@v1.2.3 @@ -70,8 +76,8 @@ jobs: # created the release above. uses: softprops/action-gh-release@v1 with: - # dist/ contains the built packages, which smoketest-artifacts/ - # contains the signatures and certificates. + # `dist/` contains the built packages, and the + # sigstore-produced signatures and certificates. files: dist/** publish-to-testpypi: @@ -79,11 +85,13 @@ jobs: needs: - build runs-on: ubuntu-latest + environment: name: testpypi url: https://test.pypi.org/p/ + permissions: - id-token: write + id-token: write # IMPORTANT: mandatory for trusted publishing steps: - name: Download all the dists From 73725c7cda299a0a60ac783362ae22f777e9bfcf Mon Sep 17 00:00:00 2001 From: chrysle Date: Tue, 12 Sep 2023 19:02:42 +0200 Subject: [PATCH 13/17] Address more review comments --- .../publish-to-test-pypi.yml | 36 ++++++++++--------- ...s-using-github-actions-ci-cd-workflows.rst | 16 +++++++-- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml index 4021ac585..5592f7bae 100644 --- a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml +++ b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml @@ -36,8 +36,7 @@ jobs: runs-on: ubuntu-latest environment: name: pypi - # Fill in your project (e.g. repository) name - # for + # Fill in your project (e.g. repository) name for url: https://pypi.org/p/ permissions: id-token: write # IMPORTANT: mandatory for trusted publishing @@ -64,21 +63,24 @@ jobs: id-token: write # IMPORTANT: mandatory for sigstore steps: - - name: Sign the dists with Sigstore - uses: sigstore/gh-action-sigstore-python@v1.2.3 - with: - inputs: >- - ./dist/*.tar.gz - ./dist/*.whl - - name: Upload artifact signatures to GitHub Release - # Confusingly, this action also supports updating releases, not - # just creating them. This is what we want here, since we've manually - # created the release above. - uses: softprops/action-gh-release@v1 - with: - # `dist/` contains the built packages, and the - # sigstore-produced signatures and certificates. - files: dist/** + - name: Download all the dists + uses: actions/download-artifact@v3 + with: + name: python-package-distributions + path: dist/ + - name: Sign the dists with Sigstore + uses: sigstore/gh-action-sigstore-python@v1.2.3 + with: + inputs: >- + ./dist/*.tar.gz + ./dist/*.whl + - name: Upload artifact signatures to GitHub Release + env: + GH_TOKEN: ${{ github.token }} + # Upload to GitHub Release using the `gh` CLI. + # `dist/` contains the built packages, and the + # sigstore-produced signatures and certificates. + run: gh release upload "${{ github.ref_name }}" dist/** --repo "${{ github.repository }}" publish-to-testpypi: name: Publish Python 🐍 distribution 📦 to TestPyPI diff --git a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst index 500379c9f..0c54f282f 100644 --- a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst +++ b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @@ -170,6 +170,14 @@ them to GitHub Release. :start-at: github-release: :end-before: publish-to-testpypi + +.. note:: + + This is a replacement for GPG signatures, for which support has been + `removed `_ by PyPI. + However, this job is not mandatory for defining the workflow. + + Separate workflow for publishing to TestPyPI ============================================ @@ -181,10 +189,12 @@ section: :language: yaml :start-at: publish-to-testpypi -The whole CD workflow -===================== +The whole CI/CD workflow +======================== + +This paragraph showcases the whole workflow after following the above guide. -.. collapse:: Load file +.. collapse:: Click here to display the entire GitHub Actions CI/CD workflow definition .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml From 234b18c1523cd7d0c0780962530d9ab8361eadb4 Mon Sep 17 00:00:00 2001 From: chrysle Date: Wed, 13 Sep 2023 10:54:53 +0200 Subject: [PATCH 14/17] Address more review comments Co-authored-by: Stephen Rosen <1300022+sirosen@users.noreply.github.com> Co-authored-by: Sviatoslav Sydorenko --- .../publish-to-test-pypi.yml | 8 ++--- ...s-using-github-actions-ci-cd-workflows.rst | 33 +++++++++++-------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml index 5592f7bae..70f4d39c7 100644 --- a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml +++ b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: @@ -36,7 +36,7 @@ jobs: runs-on: ubuntu-latest environment: name: pypi - # Fill in your project (e.g. repository) name for + # Replace below with your PyPI project name: url: https://pypi.org/p/ permissions: id-token: write # IMPORTANT: mandatory for trusted publishing @@ -76,11 +76,11 @@ jobs: ./dist/*.whl - name: Upload artifact signatures to GitHub Release env: - GH_TOKEN: ${{ github.token }} + GITHUB_TOKEN: ${{ github.token }} # Upload to GitHub Release using the `gh` CLI. # `dist/` contains the built packages, and the # sigstore-produced signatures and certificates. - run: gh release upload "${{ github.ref_name }}" dist/** --repo "${{ github.repository }}" + run: gh release upload "${{ github.ref_name }}" dist/** publish-to-testpypi: name: Publish Python 🐍 distribution 📦 to TestPyPI diff --git a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst index 719de7455..df9173b5f 100644 --- a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst +++ b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @@ -52,15 +52,15 @@ Let's begin! 🚀 2. Fill in the name you wish to publish your new :term:`PyPI project ` under (the ``name`` value in your ``setup.cfg`` or ``pyproject.toml``), - the GitHub repository owner's name (org or user) - and repository name and the name of the release workflow file under + the GitHub repository owner's name (org or user), + and repository name, and the name of the release workflow file under the ``.github/`` folder, see :ref:`workflow-definition`. - Finally add the name of the GitHub Actions environment + Finally, add the name of the GitHub Environment (``pypi``) we're going set up under your repository. Register the trusted publisher. 3. Now, go to https://test.pypi.org/manage/account/publishing/ and repeat - the second step, but now enter ``testpypi`` as the name of the - GitHub Actions environment. + the second step, but this time, enter ``testpypi`` as the name of the + GitHub Environment. 4. Your "pending" publishers are now ready for their first use and will create your projects automatically once you use them for the first time. @@ -71,9 +71,9 @@ Let's begin! 🚀 create it. It's not the same as a regular PyPI account. - .. hint:: + .. attention:: - For security reasons, you should require manual approval + For security reasons, you must require `manual approval `_ on each run for the ``pypi`` environment. @@ -140,7 +140,7 @@ trusted publishing to PyPI. :end-before: steps: This will also ensure that the PyPI publishing workflow is only triggered -if the current commit is tagged. It is recommended you use the +if the current commit is tagged. It is recommended that you commit using the latest release tag. Publishing the distribution to PyPI @@ -161,9 +161,11 @@ the contents of the ``dist/`` folder into PyPI unconditionally. Signing the distribution packages ================================= -This additional job signs the distribution packages with `Sigstore`_, -using the `sigstore/gh-action-sigstore-python GitHub Action`_, -and then uploads them to GitHub Release. +The following job signs the distribution packages with `Sigstore`_, +the same artifact signing system `used to sign CPython `_. + +It uses the `sigstore/gh-action-sigstore-python GitHub Action`_, +and then uploads them to a GitHub Release. .. literalinclude:: github-actions-ci-cd-sample/publish-to-test-pypi.yml :language: yaml @@ -174,8 +176,8 @@ and then uploads them to GitHub Release. .. note:: This is a replacement for GPG signatures, for which support has been - `removed `_ by PyPI. - However, this job is not mandatory for defining the workflow. + `removed from PyPI `_. + However, this job is not mandatory for uploading to PyPI and can be omitted. Separate workflow for publishing to TestPyPI @@ -189,6 +191,11 @@ section: :language: yaml :start-at: publish-to-testpypi +.. tip:: + + Requiring manual approvals in the ``testpypi`` GitHub Environment is typically unnecessary as it's designed to run on each commit to the main branch and is often used to indicate a healthy release publishing pipeline. + + The whole CI/CD workflow ======================== From 0d71546dfb04d91b61faef06381099082614fbc3 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Wed, 13 Sep 2023 17:45:02 +0200 Subject: [PATCH 15/17] Move the env URL comment inline @ pypi job --- .../github-actions-ci-cd-sample/publish-to-test-pypi.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml index 70f4d39c7..aa207f429 100644 --- a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml +++ b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml @@ -36,8 +36,7 @@ jobs: runs-on: ubuntu-latest environment: name: pypi - # Replace below with your PyPI project name: - url: https://pypi.org/p/ + url: https://pypi.org/p/ # Replace with your PyPI project name permissions: id-token: write # IMPORTANT: mandatory for trusted publishing From 63f738a9ef7a8b0c4e5de54ece427ddd2316563a Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Wed, 13 Sep 2023 17:47:54 +0200 Subject: [PATCH 16/17] Restore passing `--repo` to `gh` @ sigstore job --- .../github-actions-ci-cd-sample/publish-to-test-pypi.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml index aa207f429..20ed37740 100644 --- a/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml +++ b/source/guides/github-actions-ci-cd-sample/publish-to-test-pypi.yml @@ -79,7 +79,10 @@ jobs: # Upload to GitHub Release using the `gh` CLI. # `dist/` contains the built packages, and the # sigstore-produced signatures and certificates. - run: gh release upload "${{ github.ref_name }}" dist/** + run: >- + gh release upload + '${{ github.ref_name }}' dist/** + --repo '${{ github.repository }}' publish-to-testpypi: name: Publish Python 🐍 distribution 📦 to TestPyPI From 922208b72c6b1f1fec8a4c08ce82598271c7ab08 Mon Sep 17 00:00:00 2001 From: chrysle Date: Thu, 14 Sep 2023 08:16:55 +0200 Subject: [PATCH 17/17] Move suggestion to update actions to note block --- ...tion-releases-using-github-actions-ci-cd-workflows.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst index df9173b5f..f5ba918db 100644 --- a/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst +++ b/source/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows.rst @@ -140,8 +140,7 @@ trusted publishing to PyPI. :end-before: steps: This will also ensure that the PyPI publishing workflow is only triggered -if the current commit is tagged. It is recommended that you commit using the -latest release tag. +if the current commit is tagged. Publishing the distribution to PyPI =================================== @@ -215,6 +214,11 @@ And it'll publish any push to TestPyPI which is useful for providing test builds to your alpha users as well as making sure that your release pipeline remains healthy! +.. note:: + + It is recommended to keep the integrated GitHub Actions at their latest + versions, updating them frequently. + .. _API token: https://pypi.org/help/#apitoken .. _GitHub Actions CI/CD: https://github.com/features/actions