Automation & Scripting

CI/CD with GitHub Actions

40 min

Continuous Integration runs your tests on every push so broken code never reaches main. Continuous Delivery/Deployment ships every passing change automatically.

Your first workflow

.github/workflows/ci.yml:

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

permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"
          cache: pip
      - run: pip install -r requirements.txt -r requirements-dev.txt
      - run: pyflakes app
      - run: pytest -q

Every pull request now shows a green tick or a red cross. Combine it with branch protection (Git & GitHub track) so red never merges.

Adding a database service

    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_PASSWORD: postgres
        ports: ["5432:5432"]
        options: >-
          --health-cmd pg_isready --health-interval 5s --health-retries 10
    env:
      DATABASE_URL: postgresql://postgres:postgres@localhost:5432/postgres

Deploying after tests pass

  deploy:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - run: curl -fsS -X POST "$RENDER_DEPLOY_HOOK"
        env:
          RENDER_DEPLOY_HOOK: ${{ secrets.RENDER_DEPLOY_HOOK }}

needs: test means deploy only runs when tests pass. The production environment can require a manual approval.

Secrets in pipelines

  • Store them in Settings → Secrets and variables → Actions, never in the YAML.
  • Give the workflow the least permissions it needs (permissions: block).
  • Do not run workflows with secrets on pull requests from forks.
  • Pin third-party actions to a full commit SHA for supply-chain safety: uses: some/action@3f1c2a....
  • Prefer OIDC to long-lived cloud keys: the cloud trusts GitHub directly and issues short-lived credentials.

Useful extras

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

Matrices test several versions at once. Scheduled workflows (on: schedule: - cron: "0 6 * * 1") can run weekly dependency audits with pip-audit.

Exercise

Add the CI workflow to one of your repositories, make a pull request that breaks a test and watch it fail, fix it, and add a deploy job that runs only on main.

Your progress is saved in this browser only.

Submit for review (10 points)