CI para Python com GitHub Actions
CI para Python garante que cada pull request passa por testes automáticos, verificação de tipos e lint antes de entrar no branch principal. Com pytest, ruff e mypy no GitHub Actions, você tem um pipeline robusto em menos de 50 linhas de YAML que roda em qualquer projeto Python moderno.
Workflow de CI completo para Python
Pipeline com testes, lint, tipagem e cobertura:
# .github/workflows/ci.yml
name: CI Python
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
ci:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.11', '3.12']
steps:
- uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- name: Instalar dependências
run: |
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: Lint com ruff
run: ruff check .
- name: Formatação com ruff format
run: ruff format --check .
- name: Type check com mypy
run: mypy app/ --ignore-missing-imports
- name: Testes com pytest e cobertura
run: pytest --cov=app --cov-report=xml --cov-report=term-missing
- name: Upload cobertura
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}requirements-dev.txt para o CI
Separe dependências de desenvolvimento das de produção:
# requirements.txt — produção
fastapi==0.115.0
uvicorn[standard]==0.32.0
sqlalchemy==2.0.36
asyncpg==0.30.0
pydantic-settings==2.6.0
# requirements-dev.txt — apenas desenvolvimento e CI
pytest==8.3.3
pytest-asyncio==0.24.0
pytest-cov==6.0.0
httpx==0.28.0 # cliente HTTP para testar FastAPI
ruff==0.8.0 # lint e formatter
mypy==1.13.0 # type checker
factory-boy==3.3.1 # factories para testes
# pyproject.toml — configuração centralizada
[tool.ruff]
line-length = 100
select = ["E", "F", "I", "N", "W", "UP"]
ignore = ["E501"]
[tool.mypy]
python_version = "3.12"
strict = true
ignore_missing_imports = true
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
addopts = "--strict-markers"Testes de integração com PostgreSQL
Use services para subir PostgreSQL no CI e testar com banco real:
jobs:
integration-tests:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: testuser
POSTGRES_PASSWORD: testpass
POSTGRES_DB: testdb
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 5s
--health-retries 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pip'
- run: pip install -r requirements.txt -r requirements-dev.txt
- name: Aplicar migrações
env:
DATABASE_URL: postgresql+asyncpg://testuser:testpass@localhost:5432/testdb
run: alembic upgrade head
- name: Testes de integração
env:
DATABASE_URL: postgresql+asyncpg://testuser:testpass@localhost:5432/testdb
ENVIRONMENT: test
run: pytest tests/integration/ -v --tb=shortTestar API FastAPI no CI
Use TestClient do httpx para testar endpoints FastAPI sem servidor externo:
# tests/test_api.py
import pytest
from httpx import AsyncClient, ASGITransport
from app.main import app
@pytest.fixture
async def client():
async with AsyncClient(
transport=ASGITransport(app=app),
base_url="http://test"
) as ac:
yield ac
@pytest.mark.asyncio
async def test_health_check(client):
response = await client.get("/health")
assert response.status_code == 200
assert response.json() == {"status": "ok"}
@pytest.mark.asyncio
async def test_criar_usuario(client):
response = await client.post("/users", json={
"name": "Test User",
"email": "test@example.com"
})
assert response.status_code == 201
data = response.json()
assert data["email"] == "test@example.com"
assert "id" in dataPre-commit hooks para CI local
Use pre-commit para rodar as mesmas verificações do CI antes do commit:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.13.0
hooks:
- id: mypy
additional_dependencies: [types-all]
# Instalar e ativar:
pip install pre-commit
pre-commit install
# Rodar manualmente em todos os arquivos:
pre-commit run --all-files
# No CI — verificar que pre-commit passa:
- name: Pre-commit checks
uses: pre-commit/action@v3.0.1$ runstack deploy --plan starter
Não quer configurar manualmente?
Não quer configurar manualmente? Implante o VPS em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.