Parte 1: Configurar um pipeline CI/CD simples para Python e PyPI
Publié le 17 July 2025
Introdução
A automação dos processos de desenvolvimento tornou-se indispensável nos projetos modernos. Um pipeline CI/CD bem projetado permite não apenas detectar as regressões cedo no ciclo de desenvolvimento, mas também automatizar totalmente o processo de implantação.
Neste artigo, vamos explorar como configurar um pipeline completo com GitHub Actions para uma aplicação Python, da integração contínua (CI) à implantação contínua (CD) no PyPI.
Arquitetura do Pipeline
Nosso pipeline consiste em dois fluxos de trabalho distintos:
-
Pipeline CI: executado em cada push e pull request
-
Pipeline CDAcionado apenas nas releases do GitHub
Configuração do Pipeline de Integração Contínua (CI)
Estrutura do workflow CI
O fluxo de trabalho CI é projetado para validar cada contribuição ao código. Eis a sua configuração completa :
name: CI/CD Pipeline
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install ruff pytest pytest-mock
- name: Run Linting (Ruff)
run: ruff check .
- name: Run Tests (Pytest)
run: pytest
Análise das Etapas CI
Gatilhos (on)
----
----
on:
push:
branches:
- main
pull_request:
branches:
- main
----
O pipeline é disparado em: - Cada push na branch`main` - Cada pull request para`main`
Esta abordagem garante que o código principal permaneça estável e que toda contribuição seja validada antes da integração.
==== 2. Ambiente de Execução
----
runs-on: ubuntu-latest
Ubuntu Latest oferece um bom equilíbrio entre desempenho, custo e compatibilidade para a maioria dos projetos Python.
==== 3. Checkout do Código
```yaml
----
----
- name: Checkout code
uses: actions/checkout@v4
----
A ação`checkout@v4`Recupera o código-fonte do repositório. A versão v4 traz melhorias de desempenho e de segurança.
==== 4. Configuração Python
----
- name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.x'
O uso de`'3.x'`permite usar automaticamente a última versão estável do Python 3, simplificando a manutenção.
==== 5. Instalação das Dependências
```yaml
----
----
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install ruff pytest pytest-mock
----
Esta etapa: - Atualiza o pip para a última versão - Instala as dependências do projeto - Adiciona as ferramentas de desenvolvimento (linting e testes)
==== 6. Linting com Ruff
----
- name: Run Linting (Ruff) run: ruff check .
**Ruff**é um linter Python ultra-rápido escrito em Rust. Ele combina as funcionalidades de várias ferramentas (Flake8, Black, isort) em uma única ferramenta performante.
==== 7. Execução dos Testes
```yaml
----
----
- name: Run Tests (Pytest)
run: pytest
----
O Pytest executa todo o conjunto de testes, garantindo que as alterações não introduzam regressões.
== Configuração do Pipeline de Implantação (CD)
=== Estrutura do Workflow CD
O workflow CD é acionado apenas durante os releases do GitHub e automatiza a publicação no PyPI:
[source,yaml]
----
name: Publish to PyPI
on:
release:
types:
- published
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
----
=== Análise das Etapas CD
==== 1. Gatilho Release
----
on: release: types: - published
O pipeline CD é acionado apenas quando uma release do GitHub é publicada. Essa abordagem garante um controle preciso das implantações.
==== 2. Instalação das Ferramentas de Build
```yaml
----
----
pip install setuptools wheel twine
----
- **setuptools**: Ferramentas de empacotamento Python - **roda**: Formato de distribuição Python moderno - **barbante**Ferramenta segura para fazer upload para o PyPI
==== 3. Configuração da Autenticação
----
env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
A autenticação utiliza um token de API PyPI armazenado como segredo GitHub, mais seguro que as credenciais tradicionais.
==== 4. Build e Publicação
```yaml
----
----
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
----
- `sdist`: Crie uma distribuição fonte - `bdist_wheel`Cria uma wheel (distribuição binária) - `twine upload`Publica as distribuições no PyPI
== Configuração do Pacote Python
=== Estrutura do setup.py
Para que o pipeline funcione, seu projeto deve incluir um arquivo`setup.py`:
[source,python]
----
from setuptools import setup, find_packages
with open("README.adoc", "r", encoding="utf-8") as fh:
long_description = fh.read()
setup(
name="playlist-downloader",
version="1.0.0",
author="Votre Nom",
author_email="[email protected]",
description="CLI tool for managing YouTube playlists",
long_description=long_description,
long_description_content_type="text/plain",
url="https://github.com/cheroliv/playlist-downloader",
packages=find_packages(),
classifiers=[
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
],
python_requires=">=3.8",
install_requires=[
"typer>=0.9.0",
"yt-dlp>=2023.1.6",
"google-api-python-client>=2.70.0",
"google-auth-oauthlib>=0.7.1",
"pymonad>=2.4.0",
"pyyaml>=6.0",
],
entry_points={
"console_scripts": [
"playlist-downloader=cli:app",
],
},
)
----
=== Pontos-chave do setup.py
1. **Metadados**: Nome, versão, autor, descrição
2. **Dependências**Lista de pacotes necessários
3. **Pontos de entrada**: Comandos CLI expostos
4. **Classificadores**: Metadados para PyPI
== Segurança com os GitHub Secrets
=== Configuração do Token PyPI
1. **Criar um token API no PyPI** :
- Conecte-se ao PyPI - Vá para Account Settings > API tokens - Crie um novo token com as permissões adequadas
1. **Adicionar o segredo no GitHub**:
- Configurações do repositório > Segredos e variáveis > Ações - Crie um novo segredo chamado`PYPI_API_TOKEN` - Cole seu token PyPI
[plantuml, secrets-flow, svg]
----
@startuml
!theme plain
actor Developer as dev
participant "Repositório GitHub" as repo
participant "GitHub Actions" as actions
participant PyPI
dev -> repo : Configure PYPI_API_TOKEN secret
repo -> actions : Trigger CD pipeline on release
actions -> actions : Access secret securely
actions -> PyPI : Authenticate with token
PyPI -> PyPI : Validate and publish package
note over actions, PyPI
Token never exposed in logs
Automatic rotation possible
end note
@enduml
----
== Workflow de Implantação Completa
=== Sequência de Implantação
[plantuml, deployment-sequence, svg]
----
@startuml
!theme plain
actor Developer as dev
participant "Git local" as git
participant "GitHub" as github
participant "GitHub Actions" as actions
participant PyPI
participant "Utilizadores finais" as users
dev -> git : git tag v1.0.0
dev -> git : git push origin v1.0.0
git -> github : Push tag
dev -> github : Create release from tag
github -> actions : Trigger CD pipeline
actions -> actions : Checkout code
actions -> actions : Setup Python environment
actions -> actions : Install build tools
actions -> actions : Build distributions (sdist + wheel)
actions -> PyPI : Upload to PyPI with token
PyPI -> PyPI : Validate and publish
users -> PyPI : pip install playlist-downloader
note over dev, github
Release creation can be automated
or done manually through GitHub UI
end note
@enduml
----
=== Estados do Pipeline
[plantuml, pipeline-states, svg]
----
@startuml
!theme plain
[*] --> Idle
Idle --> CI_Running : Push/PR created
CI_Running --> CI_Success : All checks pass
CI_Running --> CI_Failed : Linting/Tests fail
CI_Success --> Idle : Merge completed
CI_Failed --> Idle : Fix and retry
Idle --> CD_Running : Release published
CD_Running --> CD_Success : Package published
CD_Running --> CD_Failed : Build/Upload error
CD_Success --> Idle : Package available on PyPI
CD_Failed --> Idle : Fix and retry release
note on link #red : Blocks merge
note on link #green : Allows deployment
@enduml
----
== Boas Práticas e Otimizações
=== Gestão de Versões
Use tags Git semânticos:
----
git tag -a v1.2.3 -m "Release version 1.2.3" git push origin v1.2.3
=== 2. Testes de matriz
Para testar em várias versões do Python :
```yaml
----
----
strategy:
matrix:
python-version: [3.8, 3.9, "3.10", "3.11"]
----
=== 3. Cache de dependências
Acelere os builds com o cache:
----
- name: Cache pip dependencies uses: actions/cache@v3 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
=== 4. Ambientes de Implantação
Use os ambientes GitHub para implantações controladas:
```yaml
----
----
jobs:
deploy:
environment: production
runs-on: ubuntu-latest
----
== Caso de Uso e Arquitetura
=== Diagrama de Casos de Uso
[plantuml, use-cases, svg]
----
@startuml
!theme plain
left to right direction
actor "desenvolvedor" as dev
actor "Ações do GitHub" as ga
actor "Usuário Final" as user
package "Sistema CI/CD" {
usecase "Executar Linting" as lint
usecase "Executar testes" as test
usecase "Construir Pacote" as build
usecase "Publicar no PyPI" as publish
usecase "Criar Lançamento" as release
}
dev --> lint : Pushes code
dev --> test : Pushes code
dev --> release : Creates release
ga --> build : On release trigger
ga --> publish : After successful build
user --> publish : Downloads package
lint .> test : triggers
test .> build : on success
build .> publish : on success
@enduml
----
=== Arquitetura de Implantação
[plantuml, deployment-architecture, svg]
----
@startuml
!theme plain
cloud "GitHub" {
[Source Repository]
[GitHub Actions]
[Secrets Store]
}
cloud "PyPI" {
[Package Registry]
[Distribution Files]
}
node "pipeline CI/CD" {
[Linting]
[Testing]
[Building]
[Publishing]
}
[Source Repository] --> [GitHub Actions] : Triggers
[GitHub Actions] --> [Linting]
[Linting] --> [Testing]
[Testing] --> [Building]
[Building] --> [Publishing]
[Publishing] --> [Package Registry] : Uploads
[Secrets Store] --> [Publishing] : Provides token
note as N1
Secure token-based
authentication
end note
[Secrets Store] .. N1
@enduml
----
== Monitorização e Depuração
=== Logs e Monitoring
GitHub Actions fornece logs detalhados para cada etapa. Para depurar :
1. **Examine os logs**de cada step
2. **Ative o debug**com`ACTIONS_STEP_DEBUG`
3. **Use artefatos**para salvar os arquivos de build
----
- name: Upload build artifacts uses: actions/upload-artifact@v3 if: failure() with: name: build-logs path: build/
=== Notificações
Adicione notificações do Slack ou e‑mail :
```yaml
----
----
- name: Notify on failure
if: failure()
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
----
== Conclusão
A implementação de um pipeline CI/CD robusto com GitHub Actions transforma radicalmente a experiência de desenvolvimento. Ao automatizar o linting, os testes e a implantação, você :
- **Reduza os erros**em produção - **Acelere os ciclos**de desenvolvimento - **Melhore a confiança**em seus releases - **Facilite a colaboração**em equipe
Este pipeline pode ser adaptado a diferentes tipos de projetos Python ajustando as ferramentas de linting, os frameworks de teste ou os destinos de implantação.
O investimento inicial na configuração desses fluxos de trabalho é rapidamente amortizado pelo ganho de tempo e pela redução de erros manuais durante as implantações.
== Recursos complementares
- https://docs.github.com/en/actions[Documentação GitHub Actions] - https://packaging.python.org/[Guia de Empacotamento do Python] - https://docs.pytest.org/[Documentação Pytest] - https://docs.astral.sh/ruff/[Documentação Ruff] - https://twine.readthedocs.io/[Documentação Twine]
✅ Pipeline funcional alcançado! Você agora tem um pipeline CI/CD simples que permite automatizar seus testes e publicar seu pacote Python no PyPI diretamente do GitHub Actions.
No entanto, este pipeline permanece intencionalmente minimalista. Ainda não cobre alguns aspectos essenciais em um contexto profissional :
Testes multi-versões do Python,
Análise automática de segurança,
Implantação progressiva via Test PyPI,
Monitoramento e métricas do pipeline,
Automatização do versioning e integração das boas práticas modernas (pyproject.toml).
Na próxima parte, vamos passar para o próximo nível. Você aprenderá a transformar esse pipeline básico em uma verdadeira cadeia de implantação industrial, robusta e segura, pronta para projetos Python de produção.
----