Some checks failed
CI Pipeline / Test Web Package (push) Waiting to run
CI Pipeline / Test Shared Package (push) Waiting to run
CI/CD Pipeline / Run Tests (push) Failing after 1s
CI/CD Pipeline / Code Quality (push) Failing after 5m39s
Basil CI/CD Pipeline / Code Linting (push) Has been cancelled
Basil CI/CD Pipeline / API Tests (push) Has been cancelled
Basil CI/CD Pipeline / Web Tests (push) Has been cancelled
Basil CI/CD Pipeline / Security Scanning (push) Has been cancelled
Basil CI/CD Pipeline / Build All Packages (push) Has been cancelled
Basil CI/CD Pipeline / E2E Tests (push) Has been cancelled
Basil CI/CD Pipeline / Build & Push Docker Images (push) Has been cancelled
Basil CI/CD Pipeline / Trigger Deployment (push) Has been cancelled
Basil CI/CD Pipeline / Shared Package Tests (push) Has been cancelled
CI Pipeline / Lint Code (push) Failing after 5m37s
CI Pipeline / Test API Package (push) Failing after 1s
E2E Tests / End-to-End Tests (push) Failing after 2s
E2E Tests / E2E Tests (Mobile) (push) Failing after 1s
CI/CD Pipeline / Build and Push Docker Images (push) Has been skipped
Security Scanning / Docker Image Security (push) Failing after 21s
CI Pipeline / Build All Packages (push) Has been cancelled
CI Pipeline / Generate Coverage Report (push) Has been cancelled
Docker Build & Deploy / Push Docker Images (push) Has been cancelled
Docker Build & Deploy / Deploy to Staging (push) Has been cancelled
Docker Build & Deploy / Deploy to Production (push) Has been cancelled
Docker Build & Deploy / Build Docker Images (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
Security Scanning / Dependency License Check (push) Has been cancelled
Security Scanning / NPM Audit (push) Has been cancelled
Security Scanning / Code Quality Scan (push) Has been cancelled
- Merged 5 workflows into single main.yml - Added Harbor registry support for local container storage - Updated deployment script with Harbor login - Enhanced webhook receiver with Harbor password env var - Updated docker-compose.yml to use Harbor images - Archived old workflow files for reference - Added comprehensive workflow documentation Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
418 lines
13 KiB
YAML
418 lines
13 KiB
YAML
name: Basil CI/CD Pipeline
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
- develop
|
|
tags:
|
|
- 'v*'
|
|
pull_request:
|
|
branches:
|
|
- main
|
|
- develop
|
|
|
|
env:
|
|
NODE_VERSION: '20'
|
|
HARBOR_REGISTRY: harbor.pkartchner.com
|
|
HARBOR_PROJECT: basil
|
|
|
|
jobs:
|
|
# ============================================================================
|
|
# STAGE 1: PARALLEL QUALITY CHECKS
|
|
# ============================================================================
|
|
|
|
lint:
|
|
name: Code Linting
|
|
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 }}
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Run linter
|
|
run: npm run lint
|
|
|
|
test-api:
|
|
name: API Tests
|
|
runs-on: ubuntu-latest
|
|
services:
|
|
postgres:
|
|
image: postgres:16-alpine
|
|
env:
|
|
POSTGRES_USER: basil
|
|
POSTGRES_PASSWORD: basil
|
|
POSTGRES_DB: basil_test
|
|
ports:
|
|
- 5432:5432
|
|
options: >-
|
|
--health-cmd pg_isready
|
|
--health-interval 10s
|
|
--health-timeout 5s
|
|
--health-retries 5
|
|
|
|
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: Build shared package
|
|
run: cd packages/shared && npm run build
|
|
|
|
- name: Generate Prisma Client
|
|
run: cd packages/api && npm run prisma:generate
|
|
|
|
- name: Run database migrations
|
|
run: cd packages/api && npm run prisma:migrate
|
|
env:
|
|
DATABASE_URL: postgresql://basil:basil@localhost:5432/basil_test?schema=public
|
|
|
|
- name: Run API tests
|
|
run: cd packages/api && npm run test
|
|
env:
|
|
DATABASE_URL: postgresql://basil:basil@localhost:5432/basil_test?schema=public
|
|
NODE_ENV: test
|
|
|
|
- name: Upload coverage
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: api-coverage
|
|
path: packages/api/coverage/
|
|
retention-days: 14
|
|
|
|
test-web:
|
|
name: Web 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 }}
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Build shared package
|
|
run: cd packages/shared && npm run build
|
|
|
|
- name: Run Web tests
|
|
run: cd packages/web && npm run test
|
|
|
|
- name: Upload coverage
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: web-coverage
|
|
path: packages/web/coverage/
|
|
retention-days: 14
|
|
|
|
test-shared:
|
|
name: Shared Package 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 }}
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Run Shared tests
|
|
run: cd packages/shared && npm run test
|
|
|
|
- name: Upload coverage
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: shared-coverage
|
|
path: packages/shared/coverage/
|
|
retention-days: 14
|
|
|
|
security-scan:
|
|
name: Security Scanning
|
|
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 }}
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: NPM Audit
|
|
run: |
|
|
echo "Running npm audit..."
|
|
npm audit --audit-level=high || true
|
|
cd packages/api && npm audit --audit-level=high || true
|
|
cd ../web && npm audit --audit-level=high || true
|
|
continue-on-error: true
|
|
|
|
- name: Secret Scanning
|
|
run: |
|
|
echo "Scanning for hardcoded secrets..."
|
|
if grep -r -E "(password|secret|api[_-]?key|token)\s*=\s*['\"][^'\"]+['\"]" \
|
|
--include="*.ts" --include="*.js" \
|
|
--exclude-dir=node_modules --exclude-dir=dist .; then
|
|
echo "⚠️ Potential hardcoded secrets found!"
|
|
exit 1
|
|
fi
|
|
echo "✓ No hardcoded secrets detected"
|
|
|
|
- name: Check outdated dependencies
|
|
run: |
|
|
echo "Checking for outdated dependencies..."
|
|
npm outdated || true
|
|
continue-on-error: true
|
|
|
|
# ============================================================================
|
|
# STAGE 2: BUILD VERIFICATION
|
|
# ============================================================================
|
|
|
|
build:
|
|
name: Build All Packages
|
|
runs-on: ubuntu-latest
|
|
needs: [lint, test-api, test-web, test-shared, security-scan]
|
|
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: Build all packages
|
|
run: npm run build
|
|
|
|
- name: Upload build artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: build-artifacts
|
|
path: |
|
|
packages/api/dist/
|
|
packages/web/dist/
|
|
packages/shared/dist/
|
|
retention-days: 7
|
|
|
|
# ============================================================================
|
|
# STAGE 3: E2E TESTING
|
|
# ============================================================================
|
|
|
|
e2e-tests:
|
|
name: E2E Tests
|
|
runs-on: ubuntu-latest
|
|
needs: build
|
|
timeout-minutes: 30
|
|
services:
|
|
postgres:
|
|
image: postgres:16-alpine
|
|
env:
|
|
POSTGRES_USER: basil
|
|
POSTGRES_PASSWORD: basil
|
|
POSTGRES_DB: basil
|
|
ports:
|
|
- 5432:5432
|
|
options: >-
|
|
--health-cmd pg_isready
|
|
--health-interval 10s
|
|
--health-timeout 5s
|
|
--health-retries 5
|
|
|
|
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: Install Playwright browsers
|
|
run: npx playwright install --with-deps
|
|
|
|
- name: Build application
|
|
run: npm run build
|
|
|
|
- name: Run database migrations
|
|
run: cd packages/api && npm run prisma:migrate
|
|
env:
|
|
DATABASE_URL: postgresql://basil:basil@localhost:5432/basil?schema=public
|
|
|
|
- name: Run E2E tests
|
|
run: npm run test:e2e
|
|
env:
|
|
DATABASE_URL: postgresql://basil:basil@localhost:5432/basil?schema=public
|
|
|
|
- name: Upload test results
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: playwright-report
|
|
path: playwright-report/
|
|
retention-days: 14
|
|
|
|
# ============================================================================
|
|
# STAGE 4: DOCKER BUILD & DEPLOYMENT (main branch only)
|
|
# ============================================================================
|
|
|
|
docker-build-and-push:
|
|
name: Build & Push Docker Images
|
|
runs-on: ubuntu-latest
|
|
needs: e2e-tests
|
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
outputs:
|
|
image_tag: ${{ steps.meta.outputs.tag }}
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Log in to Harbor
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.HARBOR_REGISTRY }}
|
|
username: ${{ secrets.HARBOR_USERNAME }}
|
|
password: ${{ secrets.HARBOR_PASSWORD }}
|
|
|
|
- name: Extract metadata
|
|
id: meta
|
|
run: |
|
|
SHA_SHORT=$(echo $GITHUB_SHA | cut -c1-7)
|
|
echo "tag=main-${SHA_SHORT}" >> $GITHUB_OUTPUT
|
|
echo "date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
|
|
|
|
- name: Build and push API image
|
|
uses: docker/build-push-action@v5
|
|
with:
|
|
context: .
|
|
file: ./packages/api/Dockerfile
|
|
push: true
|
|
tags: |
|
|
${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/basil-api:latest
|
|
${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/basil-api:${{ steps.meta.outputs.tag }}
|
|
labels: |
|
|
org.opencontainers.image.created=${{ steps.meta.outputs.date }}
|
|
org.opencontainers.image.revision=${{ github.sha }}
|
|
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|
|
|
|
- name: Build and push Web image
|
|
uses: docker/build-push-action@v5
|
|
with:
|
|
context: .
|
|
file: ./packages/web/Dockerfile
|
|
push: true
|
|
tags: |
|
|
${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/basil-web:latest
|
|
${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/basil-web:${{ steps.meta.outputs.tag }}
|
|
labels: |
|
|
org.opencontainers.image.created=${{ steps.meta.outputs.date }}
|
|
org.opencontainers.image.revision=${{ github.sha }}
|
|
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|
|
|
|
- name: Scan API image for vulnerabilities
|
|
run: |
|
|
docker run --rm \
|
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
|
aquasec/trivy:latest image \
|
|
--exit-code 0 \
|
|
--severity HIGH,CRITICAL \
|
|
--no-progress \
|
|
${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/basil-api:latest || true
|
|
|
|
- name: Scan Web image for vulnerabilities
|
|
run: |
|
|
docker run --rm \
|
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
|
aquasec/trivy:latest image \
|
|
--exit-code 0 \
|
|
--severity HIGH,CRITICAL \
|
|
--no-progress \
|
|
${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/basil-web:latest || true
|
|
|
|
- name: Image build summary
|
|
run: |
|
|
echo "### Docker Images Built & Pushed 🐳" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "**API Image:**" >> $GITHUB_STEP_SUMMARY
|
|
echo "- \`${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/basil-api:latest\`" >> $GITHUB_STEP_SUMMARY
|
|
echo "- \`${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/basil-api:${{ steps.meta.outputs.tag }}\`" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "**Web Image:**" >> $GITHUB_STEP_SUMMARY
|
|
echo "- \`${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/basil-web:latest\`" >> $GITHUB_STEP_SUMMARY
|
|
echo "- \`${{ env.HARBOR_REGISTRY }}/${{ env.HARBOR_PROJECT }}/basil-web:${{ steps.meta.outputs.tag }}\`" >> $GITHUB_STEP_SUMMARY
|
|
|
|
trigger-deployment:
|
|
name: Trigger Deployment
|
|
runs-on: ubuntu-latest
|
|
needs: docker-build-and-push
|
|
if: success()
|
|
steps:
|
|
- name: Trigger webhook
|
|
run: |
|
|
curl -X POST ${{ secrets.WEBHOOK_URL }} \
|
|
-H "Content-Type: application/json" \
|
|
-H "X-Webhook-Secret: ${{ secrets.WEBHOOK_SECRET }}" \
|
|
-d '{
|
|
"branch": "main",
|
|
"commit": "${{ github.sha }}",
|
|
"message": "${{ github.event.head_commit.message }}",
|
|
"tag": "${{ needs.docker-build-and-push.outputs.image_tag }}"
|
|
}' || echo "Webhook call failed, but continuing..."
|
|
|
|
- name: Deployment triggered
|
|
run: |
|
|
echo "### Deployment Triggered 🚀" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "The deployment webhook has been called." >> $GITHUB_STEP_SUMMARY
|
|
echo "Check the server logs to verify deployment status:" >> $GITHUB_STEP_SUMMARY
|
|
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
|
|
echo "tail -f /srv/docker-compose/basil/deploy.log" >> $GITHUB_STEP_SUMMARY
|
|
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "**Application URL:** https://basil.pkartchner.com" >> $GITHUB_STEP_SUMMARY
|