189 lines
5.9 KiB
YAML
189 lines
5.9 KiB
YAML
# .gitea/workflows/lighthouse-ci.yml
|
|
# Lighthouse CI for performance and accessibility testing of the StellaOps Web UI
|
|
|
|
name: Lighthouse CI
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
paths:
|
|
- 'src/Web/StellaOps.Web/**'
|
|
- '.gitea/workflows/lighthouse-ci.yml'
|
|
pull_request:
|
|
branches: [main, develop]
|
|
paths:
|
|
- 'src/Web/StellaOps.Web/**'
|
|
schedule:
|
|
# Run weekly on Sunday at 2 AM UTC
|
|
- cron: '0 2 * * 0'
|
|
workflow_dispatch:
|
|
|
|
env:
|
|
NODE_VERSION: '20'
|
|
LHCI_BUILD_CONTEXT__CURRENT_BRANCH: ${{ github.head_ref || github.ref_name }}
|
|
LHCI_BUILD_CONTEXT__COMMIT_SHA: ${{ github.sha }}
|
|
|
|
jobs:
|
|
lighthouse:
|
|
name: Lighthouse Audit
|
|
runs-on: ubuntu-22.04
|
|
defaults:
|
|
run:
|
|
working-directory: src/Web/StellaOps.Web
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: 'npm'
|
|
cache-dependency-path: src/Web/StellaOps.Web/package-lock.json
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Build production bundle
|
|
run: npm run build -- --configuration production
|
|
|
|
- name: Install Lighthouse CI
|
|
run: npm install -g @lhci/cli@0.13.x
|
|
|
|
- name: Run Lighthouse CI
|
|
run: |
|
|
lhci autorun \
|
|
--collect.staticDistDir=./dist/stella-ops-web/browser \
|
|
--collect.numberOfRuns=3 \
|
|
--assert.preset=lighthouse:recommended \
|
|
--assert.assertions.categories:performance=off \
|
|
--assert.assertions.categories:accessibility=off \
|
|
--upload.target=filesystem \
|
|
--upload.outputDir=./lighthouse-results
|
|
|
|
- name: Evaluate Lighthouse Results
|
|
id: lhci-results
|
|
run: |
|
|
# Parse the latest Lighthouse report
|
|
REPORT=$(ls -t lighthouse-results/*.json | head -1)
|
|
|
|
if [ -f "$REPORT" ]; then
|
|
PERF=$(jq '.categories.performance.score * 100' "$REPORT" | cut -d. -f1)
|
|
A11Y=$(jq '.categories.accessibility.score * 100' "$REPORT" | cut -d. -f1)
|
|
BP=$(jq '.categories["best-practices"].score * 100' "$REPORT" | cut -d. -f1)
|
|
SEO=$(jq '.categories.seo.score * 100' "$REPORT" | cut -d. -f1)
|
|
|
|
echo "performance=$PERF" >> $GITHUB_OUTPUT
|
|
echo "accessibility=$A11Y" >> $GITHUB_OUTPUT
|
|
echo "best-practices=$BP" >> $GITHUB_OUTPUT
|
|
echo "seo=$SEO" >> $GITHUB_OUTPUT
|
|
|
|
echo "## Lighthouse Results" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "| Category | Score | Threshold | Status |" >> $GITHUB_STEP_SUMMARY
|
|
echo "|----------|-------|-----------|--------|" >> $GITHUB_STEP_SUMMARY
|
|
|
|
# Performance: target >= 90
|
|
if [ "$PERF" -ge 90 ]; then
|
|
echo "| Performance | $PERF | >= 90 | :white_check_mark: |" >> $GITHUB_STEP_SUMMARY
|
|
else
|
|
echo "| Performance | $PERF | >= 90 | :warning: |" >> $GITHUB_STEP_SUMMARY
|
|
fi
|
|
|
|
# Accessibility: target >= 95
|
|
if [ "$A11Y" -ge 95 ]; then
|
|
echo "| Accessibility | $A11Y | >= 95 | :white_check_mark: |" >> $GITHUB_STEP_SUMMARY
|
|
else
|
|
echo "| Accessibility | $A11Y | >= 95 | :x: |" >> $GITHUB_STEP_SUMMARY
|
|
fi
|
|
|
|
# Best Practices: target >= 90
|
|
if [ "$BP" -ge 90 ]; then
|
|
echo "| Best Practices | $BP | >= 90 | :white_check_mark: |" >> $GITHUB_STEP_SUMMARY
|
|
else
|
|
echo "| Best Practices | $BP | >= 90 | :warning: |" >> $GITHUB_STEP_SUMMARY
|
|
fi
|
|
|
|
# SEO: target >= 90
|
|
if [ "$SEO" -ge 90 ]; then
|
|
echo "| SEO | $SEO | >= 90 | :white_check_mark: |" >> $GITHUB_STEP_SUMMARY
|
|
else
|
|
echo "| SEO | $SEO | >= 90 | :warning: |" >> $GITHUB_STEP_SUMMARY
|
|
fi
|
|
fi
|
|
|
|
- name: Check Quality Gates
|
|
run: |
|
|
PERF=${{ steps.lhci-results.outputs.performance }}
|
|
A11Y=${{ steps.lhci-results.outputs.accessibility }}
|
|
|
|
FAILED=0
|
|
|
|
# Performance gate (warning only, not blocking)
|
|
if [ "$PERF" -lt 90 ]; then
|
|
echo "::warning::Performance score ($PERF) is below target (90)"
|
|
fi
|
|
|
|
# Accessibility gate (blocking)
|
|
if [ "$A11Y" -lt 95 ]; then
|
|
echo "::error::Accessibility score ($A11Y) is below required threshold (95)"
|
|
FAILED=1
|
|
fi
|
|
|
|
if [ "$FAILED" -eq 1 ]; then
|
|
exit 1
|
|
fi
|
|
|
|
- name: Upload Lighthouse Reports
|
|
uses: actions/upload-artifact@v4
|
|
if: always()
|
|
with:
|
|
name: lighthouse-reports
|
|
path: src/Web/StellaOps.Web/lighthouse-results/
|
|
retention-days: 30
|
|
|
|
axe-accessibility:
|
|
name: Axe Accessibility Audit
|
|
runs-on: ubuntu-22.04
|
|
defaults:
|
|
run:
|
|
working-directory: src/Web/StellaOps.Web
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: 'npm'
|
|
cache-dependency-path: src/Web/StellaOps.Web/package-lock.json
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Install Playwright browsers
|
|
run: npx playwright install --with-deps chromium
|
|
|
|
- name: Build production bundle
|
|
run: npm run build -- --configuration production
|
|
|
|
- name: Start preview server
|
|
run: |
|
|
npx serve -s dist/stella-ops-web/browser -l 4200 &
|
|
sleep 5
|
|
|
|
- name: Run Axe accessibility tests
|
|
run: |
|
|
npm run test:a11y || true
|
|
|
|
- name: Upload Axe results
|
|
uses: actions/upload-artifact@v4
|
|
if: always()
|
|
with:
|
|
name: axe-accessibility-results
|
|
path: src/Web/StellaOps.Web/test-results/
|
|
retention-days: 30
|