Skip to content

fix(build): tolerate trailing commas when reading wrangler.jsonc #10

fix(build): tolerate trailing commas when reading wrangler.jsonc

fix(build): tolerate trailing commas when reading wrangler.jsonc #10

Workflow file for this run

name: Main CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
env:
NODE_VERSION: '20.9.0'
PNPM_VERSION: '10.33.2'
jobs:
# Stage 1: Setup & Lint
lint:
name: Lint & Format
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Check formatting
run: pnpm run prettier
- name: Run ESLint
run: pnpm run lint:check
- name: Type checking
run: pnpm run type-check
# Stage 2: Unit & Integration Tests
test:
name: Test
runs-on: ubuntu-latest
timeout-minutes: 20
needs: lint
services:
postgres:
image: postgres:15-alpine
env:
POSTGRES_DB: test_db
POSTGRES_USER: test_user
POSTGRES_PASSWORD: test_password
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
redis:
image: redis:7-alpine
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
env:
DATABASE_URL: postgres://test_user:test_password@localhost:5432/test_db
run: pnpm run migrate
- name: Run unit tests
env:
DATABASE_URL: postgres://test_user:test_password@localhost:5432/test_db
REDIS_URL: redis://localhost:6379
run: pnpm test -- --coverage
- name: Upload coverage reports
uses: codecov/codecov-action@v3
with:
files: ./coverage/coverage-final.json
flags: unittests
fail_ci_if_error: true
- name: Check coverage thresholds
run: |
# Fail if coverage below thresholds
pnpm test:coverage -- --collectCoverageFrom="src/lib/**/*.ts" --coverageThreshold='{"src/lib/":{"branches":80,"functions":80,"lines":80,"statements":80}}'
# Stage 3: Build
build:
name: Build
runs-on: ubuntu-latest
timeout-minutes: 15
needs: test
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Next.js
run: pnpm run build
env:
NODE_ENV: production
- name: Analyze bundle size
run: pnpm run analyze
continue-on-error: true
- name: Check bundle size
run: |
# Warn if bundle exceeds 500KB
SIZE=$(stat -f%z .next/static/chunks/*.js 2>/dev/null | awk '{sum+=$1} END {print sum}')
if [ $SIZE -gt 524288 ]; then
echo "⚠️ Warning: Bundle size is $(( SIZE / 1024 ))KB (target: <500KB)"
fi
continue-on-error: true
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: next-build
path: |
.next
public
retention-days: 1
# Stage 4: Security Scanning
security:
name: Security Scan
runs-on: ubuntu-latest
timeout-minutes: 15
needs: lint
permissions:
contents: read
security-events: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run Snyk security scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
continue-on-error: true
- name: Upload Snyk results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: snyk.sarif
continue-on-error: true
- name: Check npm audit
run: npm audit --audit-level=moderate
continue-on-error: true
# Stage 5: Integration Tests
integration:
name: Integration Tests
runs-on: ubuntu-latest
timeout-minutes: 20
needs: build
services:
postgres:
image: postgres:15-alpine
env:
POSTGRES_DB: test_db
POSTGRES_USER: test_user
POSTGRES_PASSWORD: test_password
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup test database
env:
DATABASE_URL: postgres://test_user:test_password@localhost:5432/test_db
run: pnpm run migrate
- name: Run integration tests
env:
DATABASE_URL: postgres://test_user:test_password@localhost:5432/test_db
run: pnpm test -- --testPathPattern="integration"
# Stage 6: Deploy to Staging
deploy-staging:
name: Deploy to Staging
runs-on: ubuntu-latest
timeout-minutes: 15
needs: [test, build, security, integration]
if: github.ref == 'refs/heads/develop' && github.event_name == 'push'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: next-build
- name: Deploy to Vercel Staging
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
scope: ${{ secrets.VERCEL_ORG_ID }}
production: false
environment-variables: NODE_ENV=staging
- name: Comment on PR with staging URL
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const deployment = context.payload.deployment;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `🚀 Staging deployment: ${deployment.environment_url}`
});
# Stage 7: E2E Tests on Staging
e2e:
name: E2E Tests
runs-on: ubuntu-latest
timeout-minutes: 30
needs: deploy-staging
if: github.ref == 'refs/heads/develop' && github.event_name == 'push'
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 Playwright
run: pnpm install -D @playwright/test
- name: Run E2E tests
env:
BASE_URL: ${{ secrets.STAGING_URL }}
run: pnpm exec playwright test
continue-on-error: true
- name: Upload Playwright report
uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
# Stage 8: Performance Tests
performance:
name: Performance Tests
runs-on: ubuntu-latest
timeout-minutes: 20
needs: deploy-staging
if: github.ref == 'refs/heads/develop' && github.event_name == 'push'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Run Lighthouse CI
uses: treosh/lighthouse-ci-action@v9
with:
configPath: ./lighthouserc.json
uploadArtifacts: true
temporaryPublicStorage: true
env:
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
# Stage 9: Deploy to Production
deploy-production:
name: Deploy to Production
runs-on: ubuntu-latest
timeout-minutes: 15
needs: [test, build, security, integration, e2e, performance]
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: next-build
- name: Deploy to Vercel Production
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
scope: ${{ secrets.VERCEL_ORG_ID }}
production: true
- name: Notify deployment success
uses: actions/github-script@v7
with:
script: |
github.rest.repos.createDeployment({
owner: context.repo.owner,
repo: context.repo.repo,
ref: context.sha,
environment: 'production',
description: 'Deployed to production',
auto_merge: false,
required_contexts: []
});
- name: Health check
run: |
for i in {1..10}; do
if curl -f https://example.com/api/health; then
echo "✅ Health check passed"
exit 0
fi
echo "Attempt $i failed, retrying..."
sleep 10
done
exit 1
# Summary Status
status:
name: CI/CD Status
runs-on: ubuntu-latest
needs: [lint, test, build, security, integration]
if: always()
steps:
- name: Check pipeline status
run: |
if [ "${{ needs.lint.result }}" != "success" ] || \
[ "${{ needs.test.result }}" != "success" ] || \
[ "${{ needs.build.result }}" != "success" ] || \
[ "${{ needs.security.result }}" != "success" ] || \
[ "${{ needs.integration.result }}" != "success" ]; then
echo "❌ Pipeline failed"
exit 1
else
echo "✅ Pipeline passed"
fi