Example: CI/CD Pipeline
Build a complete CI/CD pipeline with multiple stages and secrets.
Goal
- Run linting and unit tests on every push.
- 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.
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
steps:
lint:
image: node:20
environment:
IMAGE_NAME: myapp
commands:
- npm ci
- npm run lint
test:
image: node:20
commands:
- npm ci
- npm test
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]
deploy-staging:
image: alpine
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
Steps run on every push by default. The when: blocks on the build and deploy steps
restrict them to the master branch, while lint and test run on all branches:
steps:
test:
image: node:20
commands:
- npm test
when:
event: [push] 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
- Every push triggers linting and testing.
- Pushes to
masterbuild a Docker image. - Deployments happen automatically after a successful build.
- Secrets are never exposed in logs or configuration files.
- Change requests require passing CI before merge.