update #128
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Club Pengu CI/CD Pipeline | |
| # Runs tests on every push and PR, blocks deployment on test failures | |
| name: CI/CD | |
| on: | |
| push: | |
| branches: [main, develop] | |
| pull_request: | |
| branches: [main, develop] | |
| env: | |
| NODE_VERSION: '18' | |
| jobs: | |
| # ==================== CLIENT TESTS ==================== | |
| test-client: | |
| name: Client 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 client tests | |
| run: npm test -- --coverage | |
| - name: Upload client coverage | |
| uses: codecov/codecov-action@v4 | |
| if: always() | |
| with: | |
| files: ./coverage/lcov.info | |
| flags: client | |
| name: client-coverage | |
| fail_ci_if_error: false | |
| env: | |
| CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | |
| - name: Check coverage thresholds | |
| run: | | |
| echo "📊 Checking client coverage thresholds..." | |
| npm test -- --coverage --coverageReporters=json-summary | |
| node -e " | |
| const coverage = require('./coverage/coverage-summary.json'); | |
| const total = coverage.total; | |
| const minCoverage = 70; | |
| console.log('Coverage Summary:'); | |
| console.log(' Lines:', total.lines.pct + '%'); | |
| console.log(' Statements:', total.statements.pct + '%'); | |
| console.log(' Functions:', total.functions.pct + '%'); | |
| console.log(' Branches:', total.branches.pct + '%'); | |
| if (total.lines.pct < minCoverage) { | |
| console.error('❌ Line coverage (' + total.lines.pct + '%) is below threshold (' + minCoverage + '%)'); | |
| process.exit(1); | |
| } | |
| console.log('✅ Coverage meets minimum threshold of ' + minCoverage + '%'); | |
| " | |
| continue-on-error: true | |
| # ==================== SERVER TESTS ==================== | |
| test-server: | |
| name: Server Tests | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: server | |
| 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' | |
| cache-dependency-path: server/package-lock.json | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run server tests | |
| run: npm test -- --coverage | |
| env: | |
| NODE_ENV: test | |
| JWT_SECRET: test-secret-for-ci | |
| - name: Upload server coverage | |
| uses: codecov/codecov-action@v4 | |
| if: always() | |
| with: | |
| files: ./server/coverage/lcov.info | |
| flags: server | |
| name: server-coverage | |
| fail_ci_if_error: false | |
| env: | |
| CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | |
| - name: Check coverage thresholds | |
| run: | | |
| echo "📊 Checking server coverage thresholds..." | |
| npm test -- --coverage --coverageReporters=json-summary | |
| node -e " | |
| const coverage = require('./coverage/coverage-summary.json'); | |
| const total = coverage.total; | |
| const minCoverage = 70; | |
| console.log('Coverage Summary:'); | |
| console.log(' Lines:', total.lines.pct + '%'); | |
| console.log(' Statements:', total.statements.pct + '%'); | |
| console.log(' Functions:', total.functions.pct + '%'); | |
| console.log(' Branches:', total.branches.pct + '%'); | |
| if (total.lines.pct < minCoverage) { | |
| console.error('❌ Line coverage (' + total.lines.pct + '%) is below threshold (' + minCoverage + '%)'); | |
| process.exit(1); | |
| } | |
| console.log('✅ Coverage meets minimum threshold of ' + minCoverage + '%'); | |
| " | |
| continue-on-error: true | |
| # ==================== LINT CHECK ==================== | |
| lint: | |
| name: Lint Check | |
| 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 ESLint | |
| run: npm run lint | |
| continue-on-error: true | |
| # ==================== BUILD CHECK ==================== | |
| build: | |
| name: Build Check | |
| runs-on: ubuntu-latest | |
| needs: [test-client, test-server] | |
| 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 application | |
| run: npm run build | |
| - name: Upload build artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: dist | |
| path: dist/ | |
| retention-days: 7 | |
| # ==================== DEPLOYMENT GATE ==================== | |
| deploy-gate: | |
| name: Deployment Gate | |
| runs-on: ubuntu-latest | |
| needs: [test-client, test-server, build] | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| steps: | |
| - name: Deployment Check | |
| run: | | |
| echo "✅ All tests passed!" | |
| echo "✅ Build successful!" | |
| echo "🚀 Ready for deployment to production" | |
| echo "" | |
| echo "Summary:" | |
| echo " - Client tests: PASSED" | |
| echo " - Server tests: PASSED" | |
| echo " - Build: PASSED" | |
| # ==================== NOTIFY ON FAILURE ==================== | |
| notify-failure: | |
| name: Notify on Failure | |
| runs-on: ubuntu-latest | |
| needs: [test-client, test-server, build] | |
| if: failure() | |
| steps: | |
| - name: Report Failure | |
| run: | | |
| echo "❌ CI Pipeline Failed!" | |
| echo "" | |
| echo "One or more checks failed. Deployment is blocked." | |
| echo "Please review the failed jobs above and fix the issues." | |
| exit 1 | |