Skip to content

feat: implemented phase 5 of dashboard plan #5

feat: implemented phase 5 of dashboard plan

feat: implemented phase 5 of dashboard plan #5

Workflow file for this run

# =============================================================================
# Continuous Integration and Deployment Pipeline
# Event Management Portal - Enhanced CI/CD with TypeScript Migration Support
# =============================================================================
name: CI/CD Pipeline
on:
push:
branches: [main, migration/typescript-monorepo, develop]
paths-ignore:
- '**.md'
- 'docs/**'
- 'documentation/**'
- '.gitignore'
- 'LICENSE'
- 'CODE_OF_CONDUCT.md'
pull_request:
branches: [main, migration/typescript-monorepo, develop]
paths-ignore:
- '**.md'
- 'docs/**'
- 'documentation/**'
- '.gitignore'
- 'LICENSE'
- 'CODE_OF_CONDUCT.md'
# Enhanced permissions for security and package management
permissions:
contents: read
security-events: write
actions: read
checks: write
pull-requests: write
packages: write
issues: read
statuses: write
deployments: write
env:
NODE_VERSION: '20'
PNPM_VERSION: '10.18.3'
REGISTRY: ghcr.io
IMAGE_NAME: event-management-portal
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
# Concurrency configuration to prevent duplicate runs
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# ============================================================================
# Code Quality & Testing
# ============================================================================
lint-and-test:
name: Lint & Test
runs-on: ubuntu-latest
services:
mongodb:
image: mongo:6.0
env:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: password
MONGO_INITDB_DATABASE: event_management_test
ports:
- 27017:27017
options: >-
--health-cmd "mongosh --eval 'db.adminCommand({ping: 1})'"
--health-interval 10s
--health-timeout 5s
--health-retries 3
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 3
strategy:
matrix:
package: [frontend, backend, shared]
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 pnpm
uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: Setup pnpm cache
uses: actions/cache@v3
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Environment validation
run: |
cp .env.example .env.test
node scripts/validate-env.js test || echo "Environment validation skipped in CI"
- name: Lint code
run: pnpm turbo run lint --filter=${{ matrix.package }}
- name: Type check
run: pnpm turbo run type-check --filter=${{ matrix.package }}
- name: Run unit tests
run: pnpm turbo run test:unit --filter=${{ matrix.package }}
env:
NODE_ENV: test
MONGODB_URI: mongodb://root:password@localhost:27017/event_management_test?authSource=admin
REDIS_URL: redis://localhost:6379
JWT_SECRET: test-secret-key-not-for-production
CLOUDINARY_CLOUD_NAME: test-cloud
CLOUDINARY_API_KEY: test-key
CLOUDINARY_API_SECRET: test-secret
- name: Generate test coverage
run: pnpm turbo run test:coverage --filter=${{ matrix.package }}
continue-on-error: true
- name: Upload coverage reports
uses: codecov/codecov-action@v3
with:
file: ./packages/${{ matrix.package }}/coverage/lcov.info
flags: ${{ matrix.package }}
name: ${{ matrix.package }}-coverage
fail_ci_if_error: false
# ============================================================================
# Security Scanning
# ============================================================================
security-scan:
name: Security Scan
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run security audit
run: pnpm audit --audit-level moderate
continue-on-error: true
- name: Run Snyk security scan
uses: snyk/actions/node@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
- name: CodeQL Analysis
uses: github/codeql-action/init@v2
with:
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
# ============================================================================
# Build & Package
# ============================================================================
build:
name: Build Application
runs-on: ubuntu-latest
needs: [lint-and-test, security-scan]
if: github.event_name == 'push'
outputs:
frontend-image: ${{ steps.meta-frontend.outputs.tags }}
backend-image: ${{ steps.meta-backend.outputs.tags }}
frontend-digest: ${{ steps.build-frontend.outputs.digest }}
backend-digest: ${{ steps.build-backend.outputs.digest }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build packages
run: pnpm turbo run build
env:
NODE_ENV: production
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Extract frontend metadata
id: meta-frontend
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ github.repository }}-frontend
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Extract backend metadata
id: meta-backend
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ github.repository }}-backend
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Frontend image
id: build-frontend
uses: docker/build-push-action@v5
with:
context: .
file: packages/frontend/Dockerfile
push: true
tags: ${{ steps.meta-frontend.outputs.tags }}
labels: ${{ steps.meta-frontend.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
target: production
build-args: |
NODE_ENV=production
NEXT_PUBLIC_APP_URL=${{ vars.NEXT_PUBLIC_APP_URL || 'https://localhost' }}
NEXT_PUBLIC_API_URL=${{ vars.NEXT_PUBLIC_API_URL || 'https://localhost/api/v1' }}
- name: Build and push Backend image
id: build-backend
uses: docker/build-push-action@v5
with:
context: .
file: packages/backend/Dockerfile
push: true
tags: ${{ steps.meta-backend.outputs.tags }}
labels: ${{ steps.meta-backend.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
target: production
# ============================================================================
# Integration Testing
# ============================================================================
integration-test:
name: Integration Tests
runs-on: ubuntu-latest
needs: [build]
if: github.event_name == 'push'
services:
mongodb:
image: mongo:6.0
env:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: password
MONGO_INITDB_DATABASE: event_management_test
ports:
- 27017:27017
options: >-
--health-cmd "mongosh --eval 'db.adminCommand({ping: 1})'"
--health-interval 10s
--health-timeout 5s
--health-retries 3
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 3
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run integration tests
run: pnpm turbo run test:integration
env:
NODE_ENV: test
MONGODB_URI: mongodb://root:password@localhost:27017/event_management_test?authSource=admin
REDIS_URL: redis://localhost:6379
JWT_SECRET: test-secret-key-not-for-production
CLOUDINARY_CLOUD_NAME: test-cloud
CLOUDINARY_API_KEY: test-key
CLOUDINARY_API_SECRET: test-secret
- name: Upload integration test results
uses: actions/upload-artifact@v3
if: always()
with:
name: integration-test-results
path: |
packages/*/test-results/
packages/*/coverage/
# ============================================================================
# Deploy to Staging
# ============================================================================
deploy-staging:
name: Deploy to Staging
runs-on: ubuntu-latest
needs: [build, integration-test]
if: github.ref == 'refs/heads/develop' && github.event_name == 'push'
environment:
name: staging
url: https://staging.eventmanagement.com
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Deploy to staging server
uses: appleboy/[email protected]
with:
host: ${{ secrets.STAGING_HOST }}
username: ${{ secrets.STAGING_USER }}
key: ${{ secrets.STAGING_SSH_KEY }}
script: |
cd /opt/event-management-portal
git pull origin develop
docker-compose -f docker-compose.prod.yml pull
docker-compose -f docker-compose.prod.yml up -d --remove-orphans
docker system prune -f
- name: Run staging health checks
run: |
sleep 30
curl -f https://staging.eventmanagement.com/health || exit 1
- name: Notify deployment
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
channel: '#deployments'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
# ============================================================================
# Deploy to Production
# ============================================================================
deploy-production:
name: Deploy to Production
runs-on: ubuntu-latest
needs: [build, integration-test]
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
environment:
name: production
url: https://eventmanagement.com
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Create deployment
uses: actions/github-script@v6
id: create-deployment
with:
script: |
const { data: 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: []
});
return deployment.id;
- name: Deploy to production server
uses: appleboy/[email protected]
with:
host: ${{ secrets.PRODUCTION_HOST }}
username: ${{ secrets.PRODUCTION_USER }}
key: ${{ secrets.PRODUCTION_SSH_KEY }}
script: |
cd /opt/event-management-portal
# Backup before deployment
./scripts/backup.sh
# Pull latest code
git pull origin main
# Deploy with zero-downtime
docker-compose -f docker-compose.prod.yml pull
docker-compose -f docker-compose.prod.yml up -d --remove-orphans
# Cleanup
docker system prune -f
- name: Run production health checks
run: |
sleep 60
curl -f https://eventmanagement.com/health || exit 1
curl -f https://eventmanagement.com/api/v1/health || exit 1
- name: Update deployment status - Success
if: success()
uses: actions/github-script@v6
with:
script: |
await github.rest.repos.createDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: '${{ steps.create-deployment.outputs.result }}',
state: 'success',
environment_url: 'https://eventmanagement.com',
description: 'Deployment succeeded'
});
- name: Update deployment status - Failure
if: failure()
uses: actions/github-script@v6
with:
script: |
await github.rest.repos.createDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: '${{ steps.create-deployment.outputs.result }}',
state: 'failure',
description: 'Deployment failed'
});
- name: Notify production deployment
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
channel: '#production'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
message: |
🚀 Production Deployment ${{ job.status }}
Branch: ${{ github.ref }}
Commit: ${{ github.sha }}
Author: ${{ github.actor }}
# ============================================================================
# Cleanup
# ============================================================================
cleanup:
name: Cleanup
runs-on: ubuntu-latest
needs: [deploy-staging, deploy-production]
if: always()
steps:
- name: Cleanup old images
uses: actions/delete-package-versions@v4
with:
package-name: event-management-portal-frontend
package-type: container
min-versions-to-keep: 10
- name: Cleanup old images
uses: actions/delete-package-versions@v4
with:
package-name: event-management-portal-backend
package-type: container
min-versions-to-keep: 10