Skip to content

CD Pipeline

CD Pipeline #6

Workflow file for this run

name: CD Pipeline
on:
push:
branches: [ main ]
workflow_run:
workflows: ["CI Pipeline"]
branches: [ main ]
types: [completed]
permissions:
contents: read
deployments: write
issues: write
pull-requests: write
statuses: write
env:
NODE_VERSION: '18'
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
jobs:
# Deploy to Staging (Preview)
deploy-staging:
name: Deploy to Staging
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref != 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install Vercel CLI
run: npm install --global vercel@canary
- name: Pull Vercel Environment Information
run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
- name: Build Project Artifacts
run: vercel build --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy Project Artifacts to Vercel
id: deploy
run: |
url=$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }})
echo "preview_url=$url" >> $GITHUB_OUTPUT
- name: Comment PR with Preview URL
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `🚀 **Preview Deployment Ready!**
Preview URL: ${{ steps.deploy.outputs.preview_url }}
This preview will be automatically updated when you push new changes to this PR.`
})
# Deploy to Production
deploy-production:
name: Deploy to Production
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success'))
environment:
name: production
url: ${{ steps.deploy.outputs.production_url }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install Vercel CLI
run: npm install --global vercel@canary
- name: Pull Vercel Environment Information
run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
- name: Build Project Artifacts
run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy Project Artifacts to Vercel
id: deploy
run: |
url=$(vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }})
echo "production_url=$url" >> $GITHUB_OUTPUT
- name: Create deployment status
uses: actions/github-script@v7
continue-on-error: true
with:
script: |
try {
// Create a deployment record first
const deployment = await github.rest.repos.createDeployment({
owner: context.repo.owner,
repo: context.repo.repo,
ref: context.sha,
environment: 'production',
description: 'Production deployment',
auto_merge: false,
required_contexts: []
});
// Then create the deployment status
if (deployment.data.id) {
await github.rest.repos.createDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: deployment.data.id,
state: 'success',
environment_url: '${{ steps.deploy.outputs.production_url }}',
description: 'Deployment completed successfully'
});
}
} catch (error) {
console.log('Deployment status creation failed:', error.message);
}
# Post-Deployment Tests
post-deploy-tests:
name: Post-Deployment Tests
runs-on: ubuntu-latest
needs: [deploy-production]
if: github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run smoke tests
run: npm run test:smoke
env:
BASE_URL: ${{ needs.deploy-production.outputs.production_url }}
- name: Run accessibility tests
run: npm run test:a11y
env:
BASE_URL: ${{ needs.deploy-production.outputs.production_url }}
- name: Performance audit
uses: treosh/lighthouse-ci-action@v10
with:
urls: |
${{ needs.deploy-production.outputs.production_url }}
${{ needs.deploy-production.outputs.production_url }}/simulator
${{ needs.deploy-production.outputs.production_url }}/dashboard
configPath: './lighthouserc.json'
uploadArtifacts: true
temporaryPublicStorage: true
# Notification
notify:
name: Deployment Notification
runs-on: ubuntu-latest
needs: [deploy-production, post-deploy-tests]
if: always() && github.ref == 'refs/heads/main'
permissions:
contents: write
issues: write
pull-requests: write
steps:
- name: Notify deployment status
uses: actions/github-script@v7
continue-on-error: true
with:
script: |
try {
const deployResult = '${{ needs.deploy-production.result }}';
const testResult = '${{ needs.post-deploy-tests.result }}';
const status = deployResult === 'success' && testResult === 'success' ? '✅ Success' : '❌ Failed';
const url = '${{ needs.deploy-production.outputs.production_url }}' || 'URL not available';
const body = `🚀 **Deployment ${status}**
**Deployment Result**: ${deployResult}
**Tests Result**: ${testResult}
**Production URL**: ${url}
The TOC Simulator deployment process has completed!`;
await github.rest.repos.createCommitComment({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: context.sha,
body: body
});
console.log('Deployment notification sent successfully');
} catch (error) {
console.log('Failed to create deployment notification:', error.message);
// Try alternative notification method
try {
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Deployment Status - ${new Date().toISOString()}`,
body: `Deployment completed with status: ${{ needs.deploy-production.result }}`
});
} catch (fallbackError) {
console.log('Fallback notification also failed:', fallbackError.message);
}
}