GitHub Actions — CI/CD from scratch

CI/CD in brief

CI (Continuous Integration) automatically builds and tests every change before it reaches main. CD (Continuous Delivery/Deployment) automates the release. At ProfessNet we use GitHub Actions — pipelines live in the repo, in the .github/workflows/ directory.

Anatomy of a workflow

ConceptWhat it is
WorkflowA YAML file with the whole process
Event (on)What triggers it (push, pull_request, schedule)
JobA group of steps on one machine (runner)
StepA single command or action
RunnerThe machine that runs the job (e.g. ubuntu-latest)

Your first CI pipeline

The file .github/workflows/ci.yml — lint, tests, and build on every PR:

name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

      - name: Install
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Test
        run: npm test

      - name: Build
        run: npm run build

Tip: Use npm ci, not npm install, in CI. ci installs exactly the versions from package-lock.json and is faster — it is what the build on Vercel does too, so the environments stay consistent.

Version matrix

Want to test against several Node versions at once? A matrix parallelizes the jobs:

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node: [18, 20, 22]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci && npm test

Cache and speed

actions/setup-node with cache: npm remembers downloaded packages between runs, shortening install time. Each job starts on a clean machine, so cache and artifacts are the way to pass data along.

Dependencies between jobs

A job can wait for another via needs — e.g. deploy only after green tests:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm test

  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - run: echo "Deploy tylko z main po zielonych testach"

Status checks and protecting main

A green workflow becomes a status check visible in the PR. By enabling branch protection on main and requiring that check, you block the merge until CI passes. This ties in with the code review lesson.

Summary

GitHub Actions is YAML in .github/workflows/: an event triggers jobs, jobs have steps. Start with checkout → setup-node → npm ci → lint → test → build. Add a cache for speed, needs for ordering, and a required status check on main so that nothing non-compliant reaches production.