Publicando versões de distribuição de pacotes usando fluxos de trabalho de CI/CD do GitHub Actions¶
O CI/CD do GitHub Actions permite que você execute uma série de comandos sempre que ocorrer um evento na plataforma GitHub. Uma escolha popular é ter um fluxo de trabalho que é disparado por um evento push. Este guia mostra como publicar uma distribuição Python sempre que um commit marcado é enviado. Ele usará o GitHub Action pypa/gh-action-pypi-publish para publicação. Ele também usa as actions upload-artifact e download-artifact do GitHub para temporariamente armazenar e baixar os pacotes fontes.
Atenção
Este guia presume que você já tem um projeto para o qual sabe como construir distribuições e ele reside no GitHub. Este guia também evita detalhes da construção de projetos específicos da plataforma. Se você tiver componentes binários, confira os exemplos de GitHub Action do cibuildwheel.
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 API token for both PyPI and TestPyPI. In case of publishing to third-party indexes like 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. The following steps will lead you through creating the “pending” publishers for your new PyPI project. However it is also possible to add Trusted Publishing to any pre-existing project, if you are its owner.
Atenção
Se você seguiu versões anteriores deste guia, você criou os segredos PYPI_API_TOKEN e TEST_PYPI_API_TOKEN para acesso direto ao PyPI e TestPyPI. Eles estão descontinuados agora e você deve removê-los de seu repositório GitHub e revogá-los nas configurações de sua conta PyPI e TestPyPI, caso esteja substituindo sua configuração antiga pela nova.
Vamos começar! 🚀
Preencha o nome com o qual deseja publicar seu novo projeto PyPI em (o valor
nameem seusetup.cfgoupyproject.toml), o nome do proprietário do repositório no GitHub (organização ou usuário), e nome do repositório, e o nome do arquivo de fluxo de trabalho de lançamento na pasta.github/, consulte Criando uma definição de fluxo de trabalho. Por fim, adicione o nome do ambiente do GitHub (pypi) que iremos configurar em seu repositório. Registre o publicador confiável.Agora, acesse https://test.pypi.org/manage/account/publishing/ e repita a segunda etapa, mas desta vez, insira
testpypicomo o nome do ambiente do GitHub.Seus publicadores “pendentes” agora estão prontos para o primeiro uso e criarão seus projetos automaticamente assim que você usá-los pela primeira vez.
Nota
Se você não tiver uma conta TestPyPI, precisará criá-la. Não é o mesmo que uma conta do PyPI comum.
Atenção
For security reasons, you must require manual approval on each run for the
pypienvironment.
Criando uma definição de fluxo de trabalho¶
Os fluxos de trabalho de CI/CD do GitHub são declarados em arquivos YAML armazenados no diretório .github/workflows/ do seu repositório.
Let’s create a .github/workflows/publish-to-pypi.yml
file.
Comece com um nome significativo e defina o evento que deve fazer o GitHub executar este fluxo de trabalho:
name: Publish Python 🐍 distribution 📦 to PyPI and TestPyPI
on: push
Fazendo checkout do projeto e construindo as distribuições¶
Teremos que definir dois trabalhos (“jobs”) para publicar em PyPI e TestPyPI respectivamente, e um trabalho adicional para construir os pacotes de distribuição.
Primeiro, definiremos o trabalho para construir os pacotes dist do seu projeto e armazená-los para uso posterior:
Dica
If you adapt this workflow to build multiple platform-specific wheels, use uniquely named artifacts for each build job and adjust the download step accordingly. The cibuildwheel GitHub Actions examples show a fuller wheel matrix layout.
jobs:
build:
name: Build distribution 📦
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.x"
Isso fará o download do seu repositório no executor de CI e, em seguida, instalará e ativará o lançamento mais recente disponível do Python 3.
E agora podemos construir os dists a partir da fonte e armazená-los. Neste exemplo, usaremos o pacote build. Então, adicione isso à lista de etapas:
- name: Install pypa/build
run: >-
python3 -m
pip install
build
--user
- name: Build a binary wheel and a source tarball
run: python3 -m build
- name: Store the distribution packages
uses: actions/upload-artifact@v5
with:
name: python-package-distributions
path: dist/
Definindo um ambiente de tarefa do fluxo de trabalho¶
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 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 acquiring an OpenID Connect token
that the pypi-publish actions needs to implement secretless
Trusted Publishing to PyPI.
publish-to-pypi:
name: >-
Publish Python 🐍 distribution 📦 to PyPI
if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes
needs:
- build
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/<package-name> # Replace <package-name> with your PyPI project name
permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
Isso também garantirá que o fluxo de trabalho de publicação do PyPI só seja acionado se o commit atual estiver marcado.
Publicando a distribuição para PyPI¶
Finalmente, adicione as seguintes etapas ao final:
steps:
- name: Download all the dists
uses: actions/download-artifact@v6
with:
name: python-package-distributions
path: dist/
- name: Publish distribution 📦 to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
Essa etapa usa a GitHub Action pypa/gh-action-pypi-publish: após o primeiro pacote de distribuição armazenado ter sido baixado pela ação download-artifact, ele envia o conteúdo da pasta dist / para PyPI incondicionalmente.
Dica
Starting with version v1.11.0, pypa/gh-action-pypi-publish generates and uploads PEP 740-compatible attestations for each distribution by default. No additional manual signing steps are required.
Fluxo de trabalho separado para publicação no TestPyPI¶
Agora, repita essas etapas e crie outro trabalho para publicação no índice do pacote TestPyPI na seção jobs:
publish-to-testpypi:
name: Publish Python 🐍 distribution 📦 to TestPyPI
needs:
- build
runs-on: ubuntu-latest
environment:
name: testpypi
url: https://test.pypi.org/p/<package-name>
permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
steps:
- name: Download all the dists
uses: actions/download-artifact@v6
with:
name: python-package-distributions
path: dist/
- name: Publish distribution 📦 to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
Dica
Exigir aprovações manuais no ambiente GitHub testpypi normalmente é desnecessário, pois ele é projetado para ser executado em cada commit no branch principal e é frequentemente usado para indicar um pipeline de publicação de lançamento íntegro.
O fluxo de trabalho de CI/CD completo¶
Este parágrafo mostra todo o fluxo de trabalho após seguir o guia acima.
Click here to display the entire GitHub Actions CI/CD workflow definition
name: Publish Python 🐍 distribution 📦 to PyPI and TestPyPI
on: push
jobs:
build:
name: Build distribution 📦
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v6
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
- name: Store the distribution packages
uses: actions/upload-artifact@v5
with:
name: python-package-distributions
path: dist/
publish-to-pypi:
name: >-
Publish Python 🐍 distribution 📦 to PyPI
if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes
needs:
- build
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/<package-name> # Replace <package-name> with your PyPI project name
permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
steps:
- name: Download all the dists
uses: actions/download-artifact@v6
with:
name: python-package-distributions
path: dist/
- name: Publish distribution 📦 to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
publish-to-testpypi:
name: Publish Python 🐍 distribution 📦 to TestPyPI
needs:
- build
runs-on: ubuntu-latest
environment:
name: testpypi
url: https://test.pypi.org/p/<package-name>
permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
steps:
- name: Download all the dists
uses: actions/download-artifact@v6
with:
name: python-package-distributions
path: dist/
- name: Publish distribution 📦 to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
Isso é tudo, pessoal!¶
Agora, sempre que você fizer um push de um commit com tag para seu repositório Git remoto no GitHub, este fluxo de trabalho irá publicá-lo no PyPI. E publicará qualquer push para TestPyPI que seja útil para fornecer construções de teste para seus usuários alfa, bem como garantir que sua versão pipeline permaneça saudável!
Atenção
Se o seu repositório tiver atividade de commit frequente e cada push for carregado no TestPyPI conforme descrito, o projeto poderá exceder o limite de tamanho do projeto PyPI. O limite poderia ser aumentado, mas uma solução melhor pode consistir em usar um servidor compatível com PyPI como pypiserver no CI para fins de teste.
Nota
Recomenda-se manter o GitHub Actions integrado em suas versões mais recentes, atualizando-as frequentemente.