{# canonical_base is the OWNING tenant's origin: all 16 Peasy domains serve the same catalogue, so a page rendered by a non-owner points its canonical at the owner instead of competing with it. Falls back to this site for static/self-owned pages. #}
🍋
Menu
How-To Beginner 2 min read 375 words

CI/CD Pipeline Setup: From Code Push to Production Deploy

A well-designed CI/CD pipeline catches bugs early, enforces code quality, and deploys with confidence. This guide walks through building a pipeline from scratch with lint, test, build, and deploy stages.

Key Takeaways

  • Continuous Integration (CI) means every code change triggers automated checks — linting, type checking, unit tests, integration tests.
  • Tools: Ruff (Python), ESLint (JavaScript), Biome (JS/TS), golangci-lint (Go)
  • run: pip install ruff && ruff check .
  • Fail fast — run cheap checks before expensive ones.

What CI/CD Means in Practice

Continuous Integration (CI) means every code change triggers automated checks — linting, type checking, unit tests, integration tests. Broken code is detected within minutes, not days. Continuous Deployment (CD) extends this by automatically deploying code that passes all checks to staging or production.

Pipeline Stages

Stage 1: Lint and Format

The fastest checks run first. Linting catches syntax errors, unused imports, and style violations in seconds. Formatting verification ensures consistent code style across the team. If linting fails, there's no point running slower tests.

Tools: Ruff (Python), ESLint (JavaScript), Biome (JS/TS), golangci-lint (Go)

Stage 2: Type Checking

Static type analysis catches type errors without executing code. This stage runs in parallel with linting since they're independent.

Tools: mypy (Python), TypeScript compiler, Flow (JavaScript)

Stage 3: Unit Tests

Unit tests verify individual functions and classes in isolation. They should complete in under 2 minutes for fast feedback. Mock external dependencies (databases, APIs) to keep unit tests fast and deterministic.

Stage 4: Integration Tests

Integration tests verify that components work together correctly — database queries return expected results, API endpoints respond correctly, and background jobs process as expected. These are slower (5-15 minutes) and may require database fixtures or Docker containers.

Stage 5: Build

Compile the application, build Docker images, bundle frontend assets, and generate static files. The build output is an artifact that can be deployed to any environment.

Stage 6: Deploy

Deploy the build artifact to the target environment. For staging, this may be automatic. For production, add a manual approval gate. Post-deploy, run smoke tests to verify the deployment is healthy.

Pipeline Configuration Example

# GitHub Actions example
name: CI/CD
on: [push, pull_request]
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pip install ruff && ruff check .
  test:
    needs: lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pip install -r requirements.txt
      - run: pytest --cov

Key Principles

Fail fast — run cheap checks before expensive ones. Parallelize where possible — lint and type-check can run simultaneously. Cache aggressivelycache dependencies between runs to avoid re-downloading. Keep it green — a failing pipeline should be treated as a team priority, not background noise.