OnyxlMunkey's picture
c618549
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
env:
PYTHON_VERSION: "3.11"
NODE_VERSION: "18"
jobs:
# Backend Tests
backend-test:
name: Backend Tests
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: audioforge_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: Install dependencies
run: |
cd backend
python -m pip install --upgrade pip
pip install -e ".[dev]"
- name: Run linter
run: |
cd backend
ruff check app/ tests/
- name: Run type checker
run: |
cd backend
mypy app/ --ignore-missing-imports
- name: Run tests
env:
DATABASE_URL: postgresql+asyncpg://postgres:postgres@localhost:5432/audioforge_test
REDIS_URL: redis://localhost:6379/0
MUSICGEN_DEVICE: cpu
BARK_DEVICE: cpu
run: |
cd backend
pytest tests/ -v --cov=app --cov-report=xml --cov-report=term
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
file: ./backend/coverage.xml
flags: backend
name: backend-coverage
# Frontend Tests
frontend-test:
name: Frontend Tests
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Get pnpm store directory
id: pnpm-cache
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- name: Setup pnpm cache
uses: actions/cache@v3
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: |
cd frontend
pnpm install --frozen-lockfile
- name: Run linter
run: |
cd frontend
pnpm run lint
- name: Run type checker
run: |
cd frontend
pnpm run type-check
- name: Run tests
run: |
cd frontend
pnpm run test:coverage
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
file: ./frontend/coverage/coverage-final.json
flags: frontend
name: frontend-coverage
- name: Build
env:
NEXT_PUBLIC_API_URL: http://localhost:8000
run: |
cd frontend
pnpm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: frontend-build
path: frontend/.next
retention-days: 7
# Integration Tests
integration-test:
name: Integration Tests
runs-on: ubuntu-latest
needs: [backend-test, frontend-test]
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: audioforge_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Install backend dependencies
run: |
cd backend
pip install -e ".[dev]"
- name: Install frontend dependencies
run: |
cd frontend
pnpm install --frozen-lockfile
- name: Start backend
env:
DATABASE_URL: postgresql+asyncpg://postgres:postgres@localhost:5432/audioforge_test
REDIS_URL: redis://localhost:6379/0
MUSICGEN_DEVICE: cpu
run: |
cd backend
uvicorn app.main:app --host 0.0.0.0 --port 8000 &
sleep 10
- name: Start frontend
env:
NEXT_PUBLIC_API_URL: http://localhost:8000
run: |
cd frontend
pnpm run build
pnpm run start &
sleep 10
- name: Run integration tests
run: |
python scripts/launch_verification.py --section integration --json integration-results.json
- name: Upload integration results
uses: actions/upload-artifact@v3
with:
name: integration-results
path: integration-results.json
retention-days: 30
# Security Scan
security-scan:
name: Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy results to GitHub Security
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
- name: Run Snyk security scan
uses: snyk/actions/python@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --file=backend/pyproject.toml
# Docker Build
docker-build:
name: Docker Build
runs-on: ubuntu-latest
needs: [backend-test, frontend-test]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push backend
uses: docker/build-push-action@v5
with:
context: ./backend
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/audioforge-backend:latest
${{ secrets.DOCKER_USERNAME }}/audioforge-backend:${{ github.sha }}
cache-from: type=registry,ref=${{ secrets.DOCKER_USERNAME }}/audioforge-backend:buildcache
cache-to: type=registry,ref=${{ secrets.DOCKER_USERNAME }}/audioforge-backend:buildcache,mode=max
- name: Build and push frontend
uses: docker/build-push-action@v5
with:
context: ./frontend
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/audioforge-frontend:latest
${{ secrets.DOCKER_USERNAME }}/audioforge-frontend:${{ github.sha }}
cache-from: type=registry,ref=${{ secrets.DOCKER_USERNAME }}/audioforge-frontend:buildcache
cache-to: type=registry,ref=${{ secrets.DOCKER_USERNAME }}/audioforge-frontend:buildcache,mode=max
# Performance Tests
performance-test:
name: Performance Tests
runs-on: ubuntu-latest
needs: [integration-test]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run Lighthouse CI
uses: treosh/lighthouse-ci-action@v10
with:
urls: |
http://localhost:3000
uploadArtifacts: true
temporaryPublicStorage: true
# Deployment (Production)
deploy-production:
name: Deploy to Production
runs-on: ubuntu-latest
needs: [docker-build, security-scan, performance-test]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
environment:
name: production
url: https://audioforge.com
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Deploy to production
run: |
echo "Deploying to production..."
# Add your deployment script here
# Example: kubectl apply -f k8s/
# Or: ansible-playbook deploy.yml
- name: Verify deployment
run: |
curl -f https://api.audioforge.com/health || exit 1
curl -f https://audioforge.com || exit 1
- name: Notify team
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: 'AudioForge deployed to production!'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
if: always()
# Notification
notify:
name: Notify Results
runs-on: ubuntu-latest
needs: [backend-test, frontend-test, integration-test, security-scan]
if: always()
steps:
- name: Check job statuses
run: |
echo "Backend Test: ${{ needs.backend-test.result }}"
echo "Frontend Test: ${{ needs.frontend-test.result }}"
echo "Integration Test: ${{ needs.integration-test.result }}"
echo "Security Scan: ${{ needs.security-scan.result }}"
- name: Send notification
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
fields: repo,message,commit,author,action,eventName,ref,workflow
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
if: always()