Introdução

Objetivo : Acompanhar o leitor na implementação de um pipeline CI/CD minimalista, mas funcional, para uma aplicação Python, com implantação automática no PyPI.

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:

  1. Pipeline CI: executado em cada push e pull request

  2. Pipeline CDAcionado apenas nas releases do GitHub

ci cd overview

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.
----

Articles connexes