Merge pull request #29 from AgentQuantum/fix/heroku-build #71
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
| name: CI | |
| on: | |
| push: | |
| branches: [ main, develop ] | |
| pull_request: | |
| branches: [ main, develop ] | |
| jobs: | |
| backend: | |
| name: Backend Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| cache: 'pip' | |
| - name: Install dependencies | |
| working-directory: ./backend | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -r requirements.txt | |
| pip install pytest pytest-cov flake8 coverage-badge black isort radon | |
| - name: Check code formatting with Black | |
| working-directory: ./backend | |
| run: black --check . | |
| - name: Check import sorting with isort | |
| working-directory: ./backend | |
| run: isort --check-only . | |
| - name: Lint with flake8 | |
| working-directory: ./backend | |
| run: | | |
| # Use .flake8 config for all linting rules | |
| flake8 . --count --show-source --statistics | |
| - name: Check code complexity with Radon | |
| working-directory: ./backend | |
| run: | | |
| echo "## π Code Complexity Analysis" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Cyclomatic Complexity" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| radon cc . --min B --show-complexity >> $GITHUB_STEP_SUMMARY 2>&1 || true | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Maintainability Index" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| radon mi . --min B >> $GITHUB_STEP_SUMMARY 2>&1 || true | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| # Fail if complexity too high (C or worse) | |
| radon cc . --min C && echo "β Complexity check passed" || (echo "β Functions with complexity > 10 found" && exit 1) | |
| - name: Run pytest with 95% branch coverage | |
| working-directory: ./backend | |
| run: | | |
| python -m pytest -v tests \ | |
| --cov=. \ | |
| --cov-config=.coveragerc \ | |
| --cov-branch \ | |
| --cov-report=xml \ | |
| --cov-report=term-missing \ | |
| --cov-fail-under=95 | |
| - name: Extract and enforce branch coverage | |
| working-directory: ./backend | |
| run: | | |
| # Extract branch coverage from coverage.xml | |
| BRANCH_COV=$(python -c "import xml.etree.ElementTree as ET; tree = ET.parse('coverage.xml'); root = tree.getroot(); print(f\"{float(root.attrib['branch-rate']) * 100:.2f}\")") | |
| LINE_COV=$(python -c "import xml.etree.ElementTree as ET; tree = ET.parse('coverage.xml'); root = tree.getroot(); print(f\"{float(root.attrib['line-rate']) * 100:.2f}\")") | |
| echo "BRANCH_COV=$BRANCH_COV" >> $GITHUB_ENV | |
| echo "LINE_COV=$LINE_COV" >> $GITHUB_ENV | |
| echo "Branch Coverage: $BRANCH_COV%" | |
| echo "Line Coverage: $LINE_COV%" | |
| # Fail if branch coverage is below 95% | |
| python -c "import sys; cov = float('$BRANCH_COV'); print(f'Branch coverage: {cov}%'); sys.exit(0 if cov >= 95.0 else 1)" | |
| - name: Coverage Summary | |
| working-directory: ./backend | |
| run: | | |
| BRANCH_COV=${{ env.BRANCH_COV }} | |
| LINE_COV=${{ env.LINE_COV }} | |
| BRANCH_STATUS=$(python -c "import sys; status = 'β PASS' if float('$BRANCH_COV') >= 95.0 else 'β FAIL'; print(status)") | |
| echo "## π Backend Test Coverage" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Metric | Coverage | Status |" >> $GITHUB_STEP_SUMMARY | |
| echo "|--------|----------|--------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| **Branch Coverage** | **$BRANCH_COV%** | $BRANCH_STATUS |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Line Coverage | $LINE_COV% | β |" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Requirement:** Branch coverage must be β₯ 95%" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### π Coverage Report" >> $GITHUB_STEP_SUMMARY | |
| echo "View detailed coverage in the [Actions tab](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY | |
| - name: Upload coverage XML | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-xml | |
| path: backend/coverage.xml | |
| retention-days: 30 | |
| frontend: | |
| name: Frontend Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '18' | |
| cache: 'npm' | |
| cache-dependency-path: frontend/package-lock.json | |
| - name: Install dependencies | |
| working-directory: ./frontend | |
| run: npm ci | |
| - name: Check Prettier formatting | |
| working-directory: ./frontend | |
| run: npm run format:check | |
| - name: Run ESLint | |
| working-directory: ./frontend | |
| run: npm run lint | |
| - name: Run Jest tests with coverage | |
| working-directory: ./frontend | |
| run: npm run test:ci -- --coverageReporters=text --coverageReporters=json-summary | |
| - name: Coverage Summary | |
| working-directory: ./frontend | |
| run: | | |
| echo "## π Frontend Test Coverage" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # Debug: show coverage directory contents | |
| ls -la coverage/ 2>/dev/null || echo "No coverage directory" | |
| # Extract coverage from json-summary | |
| if [ -f coverage/coverage-summary.json ]; then | |
| STMT=$(python3 -c "import json; d=json.load(open('coverage/coverage-summary.json')); print(f\"{d['total']['statements']['pct']:.2f}\")") | |
| BRANCH=$(python3 -c "import json; d=json.load(open('coverage/coverage-summary.json')); print(f\"{d['total']['branches']['pct']:.2f}\")") | |
| FUNC=$(python3 -c "import json; d=json.load(open('coverage/coverage-summary.json')); print(f\"{d['total']['functions']['pct']:.2f}\")") | |
| LINES=$(python3 -c "import json; d=json.load(open('coverage/coverage-summary.json')); print(f\"{d['total']['lines']['pct']:.2f}\")") | |
| echo "| Metric | Coverage | Status |" >> $GITHUB_STEP_SUMMARY | |
| echo "|--------|----------|--------|" >> $GITHUB_STEP_SUMMARY | |
| STMT_STATUS=$(python3 -c "print('β ' if float('$STMT') >= 95 else 'β οΈ')") | |
| BRANCH_STATUS=$(python3 -c "print('β ' if float('$BRANCH') >= 80 else 'β οΈ')") | |
| FUNC_STATUS=$(python3 -c "print('β ' if float('$FUNC') >= 95 else 'β οΈ')") | |
| LINES_STATUS=$(python3 -c "print('β ' if float('$LINES') >= 95 else 'β οΈ')") | |
| echo "| **Statements** | **$STMT%** | $STMT_STATUS |" >> $GITHUB_STEP_SUMMARY | |
| echo "| **Branches** | **$BRANCH%** | $BRANCH_STATUS |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Functions | $FUNC% | $FUNC_STATUS |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Lines | $LINES% | $LINES_STATUS |" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Thresholds:** Statements β₯95%, Branches β₯80%, Functions β₯95%, Lines β₯95%" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "β οΈ Coverage summary not found. Running with Jest thresholds only." >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Thresholds enforced:** Statements β₯95%, Branches β₯80%, Functions β₯95%, Lines β₯95%" >> $GITHUB_STEP_SUMMARY | |
| fi |