GitHub Actions CI/CD

Pipelines de integración y despliegue continuo

Flujo General

Push a main
    │
    ├─► CI: Lint + Test + Type-check
    │       └─► PR Check (en PRs)
    │
    └─► CD: Deploy (solo main, paths específicos)
            └─► Webhook → Server pull + restart

CI Pipeline

Archivo: .github/workflows/ci.yml

name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.10", "3.11"]

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
          pip install -r requirements-test.txt

      - name: Lint with ruff
        run: |
          pip install ruff
          ruff check .

      - name: Type check with mypy
        run: |
          pip install mypy
          mypy app/

      - name: Test with pytest
        run: |
          pytest tests/ -v --cov=app --cov-report=term-missing

CD Pipeline

Archivo: .github/workflows/cd.yml

name: CD

on:
  push:
    branches: [main]
    paths:
      - 'app/**'
      - 'deploy/**'
      - 'requirements.txt'

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger deploy webhook
        run: |
          curl -X POST "${{ secrets.DEPLOY_HOOK_URL }}" \
            -H "Authorization: Bearer ${{ secrets.DEPLOY_TOKEN }}" \
            -H "Content-Type: application/json" \
            -d '{"ref": "${{ github.sha }}", "project": "${{ github.repository }}"}'

Secrets Requeridos

Configurar en GitHub → Settings → Secrets → Actions:

Secret Descripción Ejemplo
DEPLOY_HOOK_URL URL del webhook en el servidor https://admin.illanes00.cl/api/deploy/mi-proyecto
DEPLOY_TOKEN Token de autenticación Token generado en admin

Servidor: Webhook Handler

El servidor tiene un endpoint que recibe el webhook y ejecuta:

cd /srv/projects/$PROJECT
git pull origin main
# Si hay requirements nuevos
venv/bin/pip install -r requirements.txt
# Reiniciar servicio
sudo systemctl restart $PROJECT.service

Paths Filter

El CD solo se ejecuta si hay cambios en rutas específicas:

paths:
  - 'app/**'       # Código fuente
  - 'deploy/**'    # Configuración de deploy
  - 'requirements.txt'  # Dependencias

Para forzar un deploy sin cambios de código:

git commit --allow-empty -m "chore: trigger deploy"
git push

Debug de Pipelines

Ver logs

GitHub → Actions → Seleccionar workflow → Ver logs de cada step

Ejecutar localmente

Usar act:

# Instalar act
brew install act  # macOS

# Ejecutar CI
act -j test

# Con secrets
act -j deploy --secret-file .secrets

Re-ejecutar workflow

GitHub → Actions → Seleccionar run fallido → “Re-run all jobs”

Rollback

Para volver a una versión anterior:

  1. Via commit:
git revert HEAD
git push
  1. Via re-run de workflow anterior:
    • GitHub → Actions
    • Buscar el deploy exitoso anterior
    • “Re-run all jobs”
  2. Manual:
ssh vps-deploy
cd /srv/projects/mi-proyecto
git checkout <commit-sha-anterior>
sudo systemctl restart mi-proyecto.service

Branch Protection

Configuración recomendada en GitHub:

Settings → Branches → main:
├── Require status checks to pass before merging
│   └── CI / test (required)
├── Require branches to be up to date before merging
└── Require linear history (optional)