GitHub Actions

Workflow automation — CI/CD, testing gates, and deployment pipelines as code

Why

CI/CD is now table stakes for every engineering team. GitHub Actions is the most widely used CI platform for teams already on GitHub. Even if you're not the one writing workflows, you need to read, debug, and extend them — and understand why a workflow failed before you can unblock your own PR.

CI pipelines are central to the "how do you ship code" discussion. Sketching a basic workflow and explaining triggers, jobs, and steps signals production engineering maturity.

Intuition

A workflow is a YAML file in .github/workflows/. It defines triggers (when to run), jobs (what to run — each on its own fresh VM runner), and steps within each job (sequential commands or reusable actions). Jobs run in parallel by default; use needs to chain them.

Think of each job as a fresh VM: spun up, steps run in order, then torn down. No state persists between jobs unless you explicitly share artifacts or cache.

Explanation
Workflow anatomy
name: CI on: # triggers push: branches: [main] pull_request: branches: [main] jobs: test: # runs in parallel with lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: '3.12' - run: pip install -r requirements.txt - run: pytest --tb=short lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: pip install ruff && ruff check .

The test and lint jobs run in parallel, each on a fresh runner. A failed step stops that job — the workflow is marked failed, blocking PR merge when required status checks are enabled.

Key patterns: dependencies, secrets, matrix
# Job dependency — deploy only after tests pass jobs: test: runs-on: ubuntu-latest steps: [...] deploy: needs: test if: github.ref == 'refs/heads/main' # only on main pushes, not PRs steps: [...] # Secrets — stored in repo settings, never in YAML - run: ./deploy.sh env: API_KEY: ${{ secrets.DEPLOY_API_KEY }} # Matrix — test across multiple Python versions strategy: matrix: python-version: ['3.10', '3.11', '3.12'] steps: - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }}

Never hard-code secrets in workflow YAML — always use the secrets context. Matrix builds are the idiomatic way to test across multiple versions without duplicating job definitions.

Common triggers
  • push — on push to specified branches. Use for deploying to staging on merge to main.
  • pull_request — on PR open/sync/reopen. Standard CI gate — tests must pass before merge.
  • schedule — cron syntax. Use for nightly builds, data refreshes, or cleanup jobs.
  • workflow_dispatch — manual trigger from GitHub UI or API. Good for one-off deploys or maintenance tasks.
  • release — on GitHub release creation. Standard trigger for publishing packages to PyPI or Docker Hub.