Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
300 changes: 300 additions & 0 deletions .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
name: 'Code Quality & Security Checks'

on:
pull_request:
branches: ['main', 'develop']
push:
branches: ['main']
workflow_dispatch:
inputs:
coverage_threshold:
description: 'Minimum coverage threshold (%)'
required: false
default: '80'
type: string
audit_level:
description: 'Audit severity level (low, moderate, high, critical)'
required: false
default: 'moderate'
type: choice
options:
- low
- moderate
- high
- critical

# Prevent concurrent runs on the same PR
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
code-quality:
name: 'Lint, Audit & Coverage'
runs-on: ubuntu-latest
timeout-minutes: 10

permissions:
contents: read
pull-requests: write

steps:
# =============================================================================
# SETUP
# =============================================================================
- name: 'Checkout Repository'
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: 'Setup Node.js'
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'

- name: 'Install Dependencies'
run: npm ci

# =============================================================================
# LINTING & FORMATTING
# =============================================================================
- name: 'Run Biome Linter'
id: biome_lint
run: |
echo "πŸ” Running Biome lint checks..."
npm run lint 2>&1 | tee biome-lint.log

if [ ${PIPESTATUS[0]} -ne 0 ]; then
echo "❌ Biome lint found errors"
echo "lint_status=failed" >> $GITHUB_OUTPUT
exit 1
else
echo "βœ… Biome lint passed"
echo "lint_status=passed" >> $GITHUB_OUTPUT
fi

- name: 'Run Biome Format Check'
id: biome_format
run: |
echo "🎨 Checking code formatting..."
npm run format 2>&1 | tee biome-format.log

if [ ${PIPESTATUS[0]} -ne 0 ]; then
echo "❌ Code formatting issues detected"
echo "format_status=failed" >> $GITHUB_OUTPUT
exit 1
else
echo "βœ… Code formatting is correct"
echo "format_status=passed" >> $GITHUB_OUTPUT
fi

# =============================================================================
# DEPENDENCY AUDITING
# =============================================================================
- name: 'Run Dependency Audit'
id: audit
continue-on-error: true
run: |
echo "πŸ”’ Running dependency security audit..."

# Determine audit level (from workflow input or default)
AUDIT_LEVEL="${{ github.event.inputs.audit_level || 'moderate' }}"
echo "πŸ“Š Audit level: $AUDIT_LEVEL"

# Run audit-ci with configured level
npx audit-ci --$AUDIT_LEVEL 2>&1 | tee audit-report.log

AUDIT_EXIT_CODE=${PIPESTATUS[0]}

if [ $AUDIT_EXIT_CODE -eq 0 ]; then
echo "βœ… No vulnerabilities found at $AUDIT_LEVEL level or above"
echo "audit_status=passed" >> $GITHUB_OUTPUT
echo "vulnerabilities_found=false" >> $GITHUB_OUTPUT
else
echo "⚠️ Vulnerabilities found at $AUDIT_LEVEL level or above"
echo "audit_status=failed" >> $GITHUB_OUTPUT
echo "vulnerabilities_found=true" >> $GITHUB_OUTPUT

# Extract vulnerability summary
VULN_COUNT=$(grep -oP '\d+(?= vulnerabilities found)' audit-report.log || echo "0")
echo "vulnerability_count=$VULN_COUNT" >> $GITHUB_OUTPUT
fi

- name: 'Upload Audit Report'
if: always()
uses: actions/upload-artifact@v4
with:
name: audit-report
path: audit-report.log
retention-days: 30

# =============================================================================
# TEST COVERAGE
# =============================================================================
- name: 'Run Tests with Coverage'
id: coverage
run: |
echo "πŸ§ͺ Running tests with coverage analysis..."

# Determine coverage threshold (from workflow input, secret, or default)
COVERAGE_THRESHOLD="${{ github.event.inputs.coverage_threshold || secrets.COVERAGE_THRESHOLD || '80' }}"
echo "πŸ“Š Coverage threshold: $COVERAGE_THRESHOLD%"

# Run tests with coverage
npm run test:coverage 2>&1 | tee test-coverage.log

TEST_EXIT_CODE=${PIPESTATUS[0]}

if [ $TEST_EXIT_CODE -ne 0 ]; then
echo "❌ Tests failed or coverage below threshold"
echo "coverage_status=failed" >> $GITHUB_OUTPUT
exit 1
else
echo "βœ… Tests passed with sufficient coverage"
echo "coverage_status=passed" >> $GITHUB_OUTPUT
fi

# Extract coverage percentages from Jest output
if [ -f coverage/coverage-summary.json ]; then
COVERAGE_PCT=$(node -pe "JSON.parse(require('fs').readFileSync('coverage/coverage-summary.json')).total.lines.pct")
echo "coverage_percentage=$COVERAGE_PCT" >> $GITHUB_OUTPUT
echo "πŸ“Š Overall coverage: $COVERAGE_PCT%"
fi

- name: 'Upload Coverage Reports'
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-reports
path: |
coverage/
test-coverage.log
retention-days: 30

- name: 'Upload Coverage to Codecov (Optional)'
if: always() && steps.coverage.outputs.coverage_status == 'passed'
continue-on-error: true
uses: codecov/codecov-action@v4
with:
files: ./coverage/lcov.info
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false

# =============================================================================
# DOCUMENTATION VALIDATION
# =============================================================================
- name: 'Validate Endpoint Documentation'
id: docs_validation
run: |
echo "πŸ“š Validating endpoint documentation consistency..."
npm run lint:docs-endpoints 2>&1 | tee docs-validation.log

if [ ${PIPESTATUS[0]} -ne 0 ]; then
echo "❌ Documentation validation failed"
echo "docs_status=failed" >> $GITHUB_OUTPUT
exit 1
else
echo "βœ… Documentation validation passed"
echo "docs_status=passed" >> $GITHUB_OUTPUT
fi

- name: 'Upload Documentation Validation Report'
if: always()
uses: actions/upload-artifact@v4
with:
name: docs-validation-report
path: docs-validation.log
retention-days: 7

# =============================================================================
# PR COMMENT SUMMARY
# =============================================================================
- name: 'Post PR Comment with Results'
if: always() && github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const lintStatus = '${{ steps.biome_lint.outputs.lint_status }}';
const formatStatus = '${{ steps.biome_format.outputs.format_status }}';
const auditStatus = '${{ steps.audit.outputs.audit_status }}';
const coverageStatus = '${{ steps.coverage.outputs.coverage_status }}';
const docsStatus = '${{ steps.docs_validation.outputs.docs_status }}';
const coveragePct = '${{ steps.coverage.outputs.coverage_percentage }}' || 'N/A';
const vulnCount = '${{ steps.audit.outputs.vulnerability_count }}' || '0';

const statusIcon = (status) => status === 'passed' ? 'βœ…' : '❌';

const body = `## πŸ” Code Quality Report

| Check | Status | Details |
|-------|--------|---------|
| **Biome Lint** | ${statusIcon(lintStatus)} ${lintStatus} | Static code analysis |
| **Code Formatting** | ${statusIcon(formatStatus)} ${formatStatus} | Style consistency |
| **Security Audit** | ${statusIcon(auditStatus)} ${auditStatus} | ${vulnCount} vulnerabilities (if any) |
| **Test Coverage** | ${statusIcon(coverageStatus)} ${coverageStatus} | ${coveragePct}% overall coverage |
| **Documentation** | ${statusIcon(docsStatus)} ${docsStatus} | API docs validation |

---

${auditStatus === 'failed' ? '⚠️ **Security Alert**: Vulnerabilities detected. Review the audit report artifact.' : ''}
${coverageStatus === 'failed' ? '⚠️ **Coverage Warning**: Tests failed or coverage below threshold.' : ''}

πŸ“¦ **Artifacts**: Download detailed reports from the workflow run page.

<sub>Workflow: \`${context.workflow}\` | Run: [#${context.runNumber}](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})</sub>`;

// Find existing comment
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});

const botComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('Code Quality Report')
);

if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: body
});
} else {
// Create new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body
});
}

# =============================================================================
# FINAL STATUS CHECK
# =============================================================================
- name: 'Verify All Checks Passed'
if: always()
run: |
echo "πŸ“‹ Final Status Summary:"
echo " Lint: ${{ steps.biome_lint.outputs.lint_status }}"
echo " Format: ${{ steps.biome_format.outputs.format_status }}"
echo " Audit: ${{ steps.audit.outputs.audit_status }}"
echo " Coverage: ${{ steps.coverage.outputs.coverage_status }}"
echo " Docs: ${{ steps.docs_validation.outputs.docs_status }}"

if [ "${{ steps.biome_lint.outputs.lint_status }}" != "passed" ] || \
[ "${{ steps.biome_format.outputs.format_status }}" != "passed" ] || \
[ "${{ steps.audit.outputs.audit_status }}" != "passed" ] || \
[ "${{ steps.coverage.outputs.coverage_status }}" != "passed" ] || \
[ "${{ steps.docs_validation.outputs.docs_status }}" != "passed" ]; then
echo "❌ One or more quality checks failed"
exit 1
fi

echo "βœ… All quality checks passed successfully"
Loading