GitHub Actions

GitHub Actions automates testing, building, and deploying on every push. Here's a practical CI/CD setup.

Basic CI Pipeline

# .github/workflows/ci.yml
name: CI

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

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"
          cache: "pip"

      - name: Install dependencies
        run: pip install -r requirements.txt

      - name: Run tests
        run: python manage.py test

      - name: Check migrations
        run: python manage.py makemigrations --check --dry-run

Deploy on Push to Main

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Deploy to server
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /var/www/myproject
            git pull origin main
            source venv/bin/activate
            pip install -r requirements.txt
            python manage.py migrate
            python manage.py seed_content
            python manage.py collectstatic --noinput
            sudo systemctl restart gunicorn

Key Patterns

Cache dependencies to speed up builds:

- uses: actions/setup-python@v5
  with:
    python-version: "3.12"
    cache: "pip"  # Caches ~/.cache/pip

Use secrets for sensitive values — never commit credentials:

env:
  DATABASE_URL: ${{ secrets.DATABASE_URL }}
  SECRET_KEY: ${{ secrets.DJANGO_SECRET_KEY }}

Matrix testing across Python versions:

strategy:
  matrix:
    python-version: ["3.10", "3.11", "3.12"]

Branch protection — require CI to pass before merging: - Settings → Branches → Add rule → Require status checks