DEV Community

郑沛沛
郑沛沛

Posted on

CI/CD with GitHub Actions: A Complete Pipeline from Zero to Deploy

A good CI/CD pipeline catches bugs early, runs tests automatically, and deploys with confidence. Here's how to build one with GitHub Actions.

Basic Test Pipeline

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

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

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'

      - name: Cache dependencies
        uses: actions/cache@v4
        with:
          path: ~/.cache/pip
          key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}

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

      - name: Run tests
        run: pytest --cov=app --cov-report=xml -v

      - name: Upload coverage
        uses: codecov/codecov-action@v4
        with:
          file: coverage.xml
Enter fullscreen mode Exit fullscreen mode

Linting and Type Checking

  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Install tools
        run: pip install ruff mypy

      - name: Lint
        run: ruff check .

      - name: Type check
        run: mypy app/ --ignore-missing-imports
Enter fullscreen mode Exit fullscreen mode

Build and Push Docker Image

  build:
    needs: [test, lint]
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          push: true
          tags: |
            myuser/myapp:latest
            myuser/myapp:${{ github.sha }}
Enter fullscreen mode Exit fullscreen mode

Deploy to Production

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment: production
    steps:
      - name: Deploy via SSH
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_KEY }}
          script: |
            docker pull myuser/myapp:${{ github.sha }}
            docker stop myapp || true
            docker rm myapp || true
            docker run -d --name myapp -p 8000:8000 myuser/myapp:${{ github.sha }}
Enter fullscreen mode Exit fullscreen mode

Matrix Testing

Test across multiple versions:

  test:
    strategy:
      matrix:
        python-version: ['3.10', '3.11', '3.12']
        os: [ubuntu-latest, macos-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
      - run: pip install -r requirements.txt && pytest
Enter fullscreen mode Exit fullscreen mode

Secrets Management

# Set secrets via GitHub CLI
gh secret set DOCKER_USERNAME
gh secret set DOCKER_TOKEN
gh secret set SERVER_HOST
gh secret set SSH_KEY < ~/.ssh/deploy_key
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  1. Run tests on every push and PR
  2. Cache dependencies to speed up builds
  3. Use matrix builds for cross-version testing
  4. Build Docker images only after tests pass
  5. Use GitHub environments for deployment approvals

6. Never hardcode secrets — use GitHub Secrets

🚀 Level up your AI workflow! Check out my AI Developer Mega Prompt Pack — 80 battle-tested prompts for developers. $9.99

Top comments (0)