Skip to main content

CI/CD Pipeline

Set up robust continuous integration and deployment pipelines for your Refract applications to ensure code quality, automated testing, and reliable deployments.

GitHub Actions Workflow​

Complete CI/CD pipeline using GitHub Actions:

.github/workflows/ci-cd.yml
name: CI/CD Pipeline

on:
push:
branches: [main, develop]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [16.x, 18.x, 20.x]

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Run linting
run: npm run lint

- name: Run type checking
run: npm run type-check

- name: Run unit tests
run: npm run test:unit

- name: Run integration tests
run: npm run test:integration

- name: Upload test coverage
uses: codecov/codecov-action@v3
with:
file: ./coverage/lcov.info

build:
needs: test
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18.x'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build application
run: npm run build
env:
NODE_ENV: production

- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: build-files
path: dist/

deploy-staging:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/develop'

steps:
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: build-files
path: dist/

- name: Deploy to staging
run: |
# Deploy to your staging environment
npm run deploy:staging
env:
STAGING_API_KEY: ${{ secrets.STAGING_API_KEY }}

deploy-production:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'

steps:
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: build-files
path: dist/

- name: Deploy to production
run: |
# Deploy to your production environment
npm run deploy:production
env:
PRODUCTION_API_KEY: ${{ secrets.PRODUCTION_API_KEY }}

Package.json Scripts​

Configure your package.json with comprehensive scripts:

package.json scripts
{
"scripts": {
"dev": "vite",
"build": "vite build",
"build:analyze": "vite build --mode analyze",
"preview": "vite preview",

"lint": "eslint src --ext .js,.jsx,.ts,.tsx",
"lint:fix": "eslint src --ext .js,.jsx,.ts,.tsx --fix",
"format": "prettier --write src/**/*.{js,jsx,ts,tsx,json,css,md}",
"format:check": "prettier --check src/**/*.{js,jsx,ts,tsx,json,css,md}",

"type-check": "tsc --noEmit",

"test": "vitest",
"test:unit": "vitest run --coverage",
"test:integration": "vitest run --config vitest.integration.config.ts",
"test:e2e": "playwright test",
"test:smoke": "playwright test --config playwright.smoke.config.ts",
"test:performance": "lighthouse-ci",

"analyze:bundle": "npx vite-bundle-analyzer dist/stats.json",
"analyze:deps": "npx depcheck",

"deploy:staging": "aws s3 sync dist/ s3://staging-bucket --delete",
"deploy:production": "aws s3 sync dist/ s3://production-bucket --delete",

"security:audit": "npm audit",
"security:fix": "npm audit fix",

"prepare": "husky install"
}
}

Quality Gates Configuration​

Set up quality gates to prevent bad code from reaching production:

.eslintrc.js
module.exports = {
extends: [
'eslint:recommended',
'@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended'
],
rules: {
// Performance rules
'react-hooks/exhaustive-deps': 'error',
'no-unused-vars': 'error',

// Code quality rules
'complexity': ['error', 10],
'max-depth': ['error', 4],
'max-lines-per-function': ['error', 50],

// Security rules
'no-eval': 'error',
'no-implied-eval': 'error',
'no-new-func': 'error'
},
overrides: [
{
files: ['**/*.test.{js,jsx,ts,tsx}'],
rules: {
'max-lines-per-function': 'off'
}
}
]
};

Docker Integration​

Containerize your application for consistent deployments:

Dockerfile
# Multi-stage build for production
FROM node:18-alpine AS builder

WORKDIR /app

# Copy package files
COPY package*.json ./
RUN npm ci --only=production

# Copy source code
COPY . .

# Build application
RUN npm run build

# Production stage
FROM nginx:alpine AS production

# Copy built application
COPY --from=builder /app/dist /usr/share/nginx/html

# Copy nginx configuration
COPY nginx.conf /etc/nginx/nginx.conf

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost/ || exit 1

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]
docker-compose.yml
version: '3.8'

services:
app:
build: .
ports:
- "3000:80"
environment:
- NODE_ENV=production
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped

nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- app
restart: unless-stopped

Automated Testing Strategy​

Comprehensive testing pipeline:

vitest.config.ts
import { defineConfig } from 'vitest/config';

export default defineConfig({
test: {
environment: 'jsdom',
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html', 'lcov'],
thresholds: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80
}
},
exclude: [
'node_modules/',
'dist/',
'**/*.test.{js,jsx,ts,tsx}',
'**/*.config.{js,ts}'
]
},
setupFiles: ['./src/test/setup.ts'],
globals: true
}
});
playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
testDir: './e2e',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,

reporter: [
['html'],
['junit', { outputFile: 'test-results/junit.xml' }]
],

use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure'
},

projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] }
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] }
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] }
}
],

webServer: {
command: 'npm run preview',
port: 3000,
reuseExistingServer: !process.env.CI
}
});

Deployment Strategies​

Different deployment approaches:

blue-green-deploy.sh
#!/bin/bash

# Blue-Green deployment script
BUCKET_BLUE="your-app-blue"
BUCKET_GREEN="your-app-green"
DISTRIBUTION_ID="your-cloudfront-id"

# Determine current active environment
CURRENT=$(aws s3api get-bucket-tagging --bucket $BUCKET_BLUE --query 'TagSet[?Key==`Environment`].Value' --output text 2>/dev/null || echo "green")

if [ "$CURRENT" = "blue" ]; then
TARGET_BUCKET=$BUCKET_GREEN
TARGET_ENV="green"
else
TARGET_BUCKET=$BUCKET_BLUE
TARGET_ENV="blue"
fi

echo "Deploying to $TARGET_ENV environment..."

# Deploy to target environment
aws s3 sync dist/ s3://$TARGET_BUCKET --delete

# Run smoke tests
curl -f https://$TARGET_ENV.yourapp.com/health || exit 1

# Switch traffic
aws cloudfront create-invalidation --distribution-id $DISTRIBUTION_ID --paths "/*"

# Tag the new active environment
aws s3api put-bucket-tagging --bucket $TARGET_BUCKET --tagging 'TagSet=[{Key=Environment,Value='$TARGET_ENV'}]'

echo "Deployment to $TARGET_ENV completed successfully!"

Monitoring and Alerting​

Set up monitoring for your CI/CD pipeline:

monitoring-alerts.yml
# Slack notification for deployment status
- name: Notify deployment status
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
channel: '#deployments'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
fields: repo,message,commit,author,action,eventName,ref,workflow
if: always()

# PagerDuty integration for critical failures
- name: Trigger PagerDuty alert
if: failure()
run: |
curl -X POST https://events.pagerduty.com/v2/enqueue \
-H 'Content-Type: application/json' \
-d '{
"routing_key": "${{ secrets.PAGERDUTY_ROUTING_KEY }}",
"event_action": "trigger",
"payload": {
"summary": "CI/CD Pipeline Failed",
"source": "GitHub Actions",
"severity": "critical"
}
}'

Best Practices​

  • Fail fast: Run quick checks (linting, type checking) before expensive operations
  • Parallel execution: Run independent jobs in parallel to reduce pipeline time
  • Caching: Cache dependencies and build artifacts to speed up subsequent runs
  • Security scanning: Include security audits and dependency checks
  • Environment parity: Keep staging and production environments as similar as possible
  • Rollback strategy: Always have a plan to quickly rollback deployments
  • Monitoring: Monitor pipeline performance and success rates
  • Documentation: Keep deployment procedures well-documented