mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
c0ba2b4d86
package.json has "type": "module" so .js files are treated as ESM. Scripts using require() renamed to .cjs, scripts using import to .mjs. Fixes Test Dashboard CI failure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
393 lines
11 KiB
YAML
393 lines
11 KiB
YAML
name: Optimized CI
|
|
|
|
# Optimized CI workflow targeting < 2 minute execution
|
|
# Runs journey tests first (highest value), then contracts and critical infrastructure
|
|
|
|
on:
|
|
push:
|
|
branches: [main, develop]
|
|
pull_request:
|
|
branches: [main, develop]
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
actions: write
|
|
pull-requests: write
|
|
checks: write
|
|
|
|
jobs:
|
|
# Fast path: Journey + Contract tests (primary quality signal)
|
|
fast-tests:
|
|
name: Fast Tests (Journey + Contract)
|
|
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: '20'
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Build project
|
|
run: npm run build
|
|
|
|
- name: Run Journey Tests
|
|
id: journey-tests
|
|
run: npm run test:journeys || echo "journey_failed=true" >> $GITHUB_OUTPUT
|
|
env:
|
|
NODE_OPTIONS: '--max-old-space-size=1024'
|
|
continue-on-error: true
|
|
|
|
- name: Run Contract Tests
|
|
id: contract-tests
|
|
if: always()
|
|
run: |
|
|
if [ -d "tests/contracts" ] && [ "$(ls -A tests/contracts/*.test.ts 2>/dev/null)" ]; then
|
|
npm run test:contracts
|
|
else
|
|
echo "No contract tests found"
|
|
fi
|
|
env:
|
|
NODE_OPTIONS: '--max-old-space-size=512'
|
|
continue-on-error: true
|
|
|
|
- name: Run Code Intelligence Tests (MinCut/Graph Algorithms)
|
|
id: code-intelligence-tests
|
|
if: always()
|
|
run: npm run test:code-intelligence
|
|
env:
|
|
NODE_OPTIONS: '--max-old-space-size=768'
|
|
SKIP_INTEGRATION_TESTS: 'true'
|
|
continue-on-error: true
|
|
|
|
- name: Upload test results
|
|
uses: actions/upload-artifact@v4
|
|
if: always()
|
|
with:
|
|
name: fast-test-results
|
|
path: junit.xml
|
|
retention-days: 7
|
|
|
|
- name: Check test results
|
|
if: always()
|
|
run: |
|
|
FAILED=0
|
|
if [ "${{ steps.journey-tests.outcome }}" == "failure" ]; then
|
|
echo "Journey tests failed"
|
|
FAILED=1
|
|
fi
|
|
if [ "${{ steps.code-intelligence-tests.outcome }}" == "failure" ]; then
|
|
echo "Code Intelligence tests failed (MinCut/Graph algorithms)"
|
|
FAILED=1
|
|
fi
|
|
if [ "$FAILED" -eq 1 ]; then
|
|
exit 1
|
|
fi
|
|
echo "Fast tests passed (including Code Intelligence)"
|
|
|
|
# Infrastructure tests (can run in parallel)
|
|
infrastructure-tests:
|
|
name: Infrastructure Tests
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Build project
|
|
run: npm run build
|
|
|
|
- name: Run Infrastructure Tests
|
|
run: |
|
|
if [ -d "tests/infrastructure" ] && [ "$(ls -A tests/infrastructure/*.test.ts 2>/dev/null)" ]; then
|
|
npm run test:infrastructure
|
|
else
|
|
echo "No infrastructure tests found"
|
|
fi
|
|
env:
|
|
NODE_OPTIONS: '--max-old-space-size=768'
|
|
continue-on-error: true
|
|
|
|
- name: Run Regression Tests
|
|
run: |
|
|
if [ -d "tests/regression" ] && [ "$(find tests/regression -name '*.test.ts' 2>/dev/null | head -1)" ]; then
|
|
npm run test:regression
|
|
else
|
|
echo "No regression tests found"
|
|
fi
|
|
env:
|
|
NODE_OPTIONS: '--max-old-space-size=512'
|
|
continue-on-error: true
|
|
|
|
# Postgres integration tests
|
|
integration-tests:
|
|
name: Postgres Integration Tests
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
|
|
services:
|
|
postgres:
|
|
image: postgres:16-alpine
|
|
env:
|
|
POSTGRES_DB: aqe_test
|
|
POSTGRES_USER: aqe_test
|
|
POSTGRES_PASSWORD: aqe_test
|
|
ports:
|
|
- 15432:5432
|
|
options: >-
|
|
--health-cmd pg_isready
|
|
--health-interval 10s
|
|
--health-timeout 5s
|
|
--health-retries 5
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Build project
|
|
run: npm run build
|
|
|
|
- name: Run Postgres integration tests
|
|
run: npm run test:integration:pg
|
|
env:
|
|
POSTGRES_URL: postgresql://aqe_test:aqe_test@localhost:15432/aqe_test
|
|
NODE_OPTIONS: '--max-old-space-size=1024'
|
|
|
|
# Performance gates
|
|
performance-gates:
|
|
name: Performance Gates
|
|
runs-on: ubuntu-latest
|
|
needs: fast-tests
|
|
timeout-minutes: 10
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Build project
|
|
run: npm run build
|
|
|
|
- name: Run Performance Gates
|
|
id: perf-gates
|
|
run: |
|
|
npm run performance:gate > perf-report.md 2>&1 || PERF_EXIT=$?
|
|
echo "PERF_EXIT_CODE=${PERF_EXIT:-0}" >> $GITHUB_OUTPUT
|
|
cat perf-report.md
|
|
continue-on-error: true
|
|
|
|
- name: Upload performance report
|
|
uses: actions/upload-artifact@v4
|
|
if: always()
|
|
with:
|
|
name: performance-report
|
|
path: perf-report.md
|
|
retention-days: 30
|
|
|
|
- name: Check performance gate results
|
|
if: always()
|
|
run: |
|
|
EXIT_CODE="${{ steps.perf-gates.outputs.PERF_EXIT_CODE }}"
|
|
if [ "$EXIT_CODE" -eq 0 ]; then
|
|
echo "All performance gates passed"
|
|
elif [ "$EXIT_CODE" -eq 2 ]; then
|
|
echo "Performance gates passed with warnings"
|
|
else
|
|
echo "Performance gates failed (exit code: $EXIT_CODE)"
|
|
# Don't fail the build on performance warnings, only on failures
|
|
if [ "$EXIT_CODE" -eq 1 ]; then
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Coverage analysis (runs after fast tests)
|
|
coverage:
|
|
name: Coverage Analysis
|
|
runs-on: ubuntu-latest
|
|
needs: fast-tests
|
|
timeout-minutes: 10
|
|
if: github.event_name == 'pull_request'
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Build project
|
|
run: npm run build
|
|
|
|
- name: Run tests with coverage (excluding browser E2E)
|
|
run: npm run test:coverage
|
|
env:
|
|
NODE_OPTIONS: '--max-old-space-size=1024'
|
|
CI: 'true'
|
|
continue-on-error: true
|
|
|
|
- name: Upload coverage report
|
|
uses: actions/upload-artifact@v4
|
|
if: always()
|
|
with:
|
|
name: coverage-report
|
|
path: coverage/
|
|
retention-days: 7
|
|
|
|
- name: Check coverage thresholds
|
|
if: always()
|
|
run: |
|
|
if [ -f "coverage/coverage-summary.json" ]; then
|
|
COVERAGE=$(cat coverage/coverage-summary.json | jq '.total.lines.pct')
|
|
echo "Line coverage: ${COVERAGE}%"
|
|
|
|
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
|
|
echo "Coverage below 80% threshold"
|
|
else
|
|
echo "Coverage meets threshold"
|
|
fi
|
|
fi
|
|
|
|
# Test dashboard (summary job)
|
|
dashboard:
|
|
name: Test Dashboard
|
|
runs-on: ubuntu-latest
|
|
needs: [fast-tests, infrastructure-tests]
|
|
if: always()
|
|
timeout-minutes: 2
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
|
|
- name: Generate Dashboard
|
|
run: |
|
|
node scripts/test-dashboard.cjs
|
|
|
|
- name: Generate Migration Metrics
|
|
run: |
|
|
echo "# CI Test Metrics" > ci-metrics.md
|
|
echo "" >> ci-metrics.md
|
|
echo "**Date**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> ci-metrics.md
|
|
echo "**Commit**: ${{ github.sha }}" >> ci-metrics.md
|
|
echo "" >> ci-metrics.md
|
|
|
|
total_files=$(find tests -name "*.test.ts" 2>/dev/null | wc -l || echo "0")
|
|
total_lines=$(find tests -name "*.test.ts" -exec wc -l {} + 2>/dev/null | tail -1 | awk '{print $1}' || echo "0")
|
|
large_files=$(find tests -name "*.test.ts" -exec wc -l {} \; 2>/dev/null | awk '$1 > 600' | wc -l || echo "0")
|
|
skipped=$(grep -r "describe.skip\|it.skip\|test.skip" tests --include="*.test.ts" 2>/dev/null | wc -l || echo "0")
|
|
|
|
echo "## Current State" >> ci-metrics.md
|
|
echo "- Total test files: $total_files (target: 50)" >> ci-metrics.md
|
|
echo "- Total lines: $total_lines (target: 40,000)" >> ci-metrics.md
|
|
echo "- Files > 600 lines: $large_files (target: 0)" >> ci-metrics.md
|
|
echo "- Skipped tests: $skipped (target: 0)" >> ci-metrics.md
|
|
echo "" >> ci-metrics.md
|
|
|
|
# Progress calculation
|
|
baseline_files=426
|
|
baseline_lines=208253
|
|
files_reduced=$((baseline_files - total_files))
|
|
lines_reduced=$((baseline_lines - total_lines))
|
|
|
|
echo "## Progress from Baseline" >> ci-metrics.md
|
|
echo "- Files reduced: $files_reduced (-$((files_reduced * 100 / baseline_files))%)" >> ci-metrics.md
|
|
echo "- Lines reduced: $lines_reduced (-$((lines_reduced * 100 / baseline_lines))%)" >> ci-metrics.md
|
|
|
|
cat ci-metrics.md
|
|
|
|
- name: Upload metrics
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: ci-metrics
|
|
path: ci-metrics.md
|
|
retention-days: 30
|
|
|
|
- name: Comment on PR
|
|
if: github.event_name == 'pull_request'
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
const fs = require('fs');
|
|
|
|
const metrics = fs.readFileSync('ci-metrics.md', 'utf8');
|
|
|
|
const body = `## Test Suite Metrics
|
|
|
|
${metrics}
|
|
|
|
---
|
|
*Generated by Optimized CI*`;
|
|
|
|
// 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(c =>
|
|
c.user?.type === 'Bot' && c.body?.includes('Test Suite Metrics')
|
|
);
|
|
|
|
if (botComment) {
|
|
await github.rest.issues.updateComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
comment_id: botComment.id,
|
|
body
|
|
});
|
|
} else {
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: context.issue.number,
|
|
body
|
|
});
|
|
}
|