Project113

Example: CI/CD Pipeline

Build a complete CI/CD pipeline with multiple stages, path-based triggering, and secrets.

Goal

  • Run linting and unit tests only when source files change (skip for docs-only commits).
  • Build a Docker image on pushes to master.
  • Deploy to a staging environment on pushes to master.
  • Store API keys as secrets, not in the config file.
  • Use skip_clone for deployment steps that don't need source code.

Step 1: Create Secrets

Add the following secrets in your repository settings:

  • DEPLOY_KEY — SSH key for deployment access.
  • API_KEY — Third-party API key used during build.

Step 2: Write the Pipeline Config

# Skip clone for deployment steps that don't need source
skip_clone: true

steps:
  lint:
    image: node:20
    environment:
      IMAGE_NAME: myapp
    commands:
      - npm ci
      - npm run lint
    # Only run when source files change, not for docs-only commits
    when:
      path:
        include:
          - 'src/**'
          - 'lib/**'
          - 'package*.json'
        exclude:
          - '**/*.md'
          - 'docs/**'

  test:
    image: node:20
    commands:
      - npm ci
      - npm test
    when:
      path:
        include:
          - 'src/**'
          - 'lib/**'
          - '*_test.*'
          - 'package*.json'
        exclude:
          - '**/*.md'
          - 'docs/**'

  build:
    image: docker
    environment:
      IMAGE_NAME: myapp
      API_KEY:
        from_secret: API_KEY
    commands:
      - docker build -t $IMAGE_NAME:${CI_COMMIT_SHA:0:10} .
    when:
      branch: [master]
      path:
        include:
          - 'src/**'
          - 'lib/**'
          - 'Dockerfile'
          - 'package*.json'

  deploy-staging:
    image: alpine
    # No clone needed for deployment
    environment:
      DEPLOY_KEY:
        from_secret: DEPLOY_KEY
    commands:
      - ssh -i $DEPLOY_KEY deploy@staging.example.com "cd /app && docker compose pull && docker compose up -d"
    when:
      branch: [master]

Step 3: Configure Triggers

The when: blocks with path: ensure tests and linting only run when relevant source files change. Documentation-only commits (e.g., *.md files in docs/) will skip these steps entirely.

Manual Re-run

If you need to force a pipeline run (e.g., after a flaky test failure or infrastructure issue), use the Re-run button in the Flows tab or pipeline detail page. The re-run uses the exact same configuration and commit.

Step 4: Set Up Merge Requirements

In repository settings, enable Require CI to pass so merges to master are blocked until the pipeline succeeds:

  • Require CI to pass: Yes

Result

  • Source changes trigger linting and testing; docs-only changes skip CI.
  • Pushes to master build and deploy a Docker image.
  • Deployments skip clone for faster execution.
  • Secrets are never exposed in logs or configuration files.
  • Change requests require passing CI before merge.
  • Failed pipelines can be re-run from the UI.