ci: enforce test requirements and coverage thresholds on PRs
Add two CI gates to enforce CONTRIBUTING.md test requirements: 1. File-matching check (lint job): fails PRs that change source files without including test file changes. Exempts docs/chore/ci branches. 2. Coverage gate (build job): wires existing `npm run test:coverage` into CI with c8 thresholds (40% statements/lines, 20% branches/functions). Previously defined in package.json but never ran in CI. Lowers coverage thresholds from 50% to 40% for statements/lines to match current codebase reality (~44%) — prevents the gate from blocking every PR on day one while still catching coverage regressions.
This commit is contained in:
parent
bc9b12bb90
commit
13bad4f4e9
3 changed files with 77 additions and 1 deletions
9
.github/workflows/ci.yml
vendored
9
.github/workflows/ci.yml
vendored
|
|
@ -102,6 +102,12 @@ jobs:
|
|||
- name: Validate skill references
|
||||
run: node scripts/check-skill-references.mjs
|
||||
|
||||
- name: Require tests with source changes
|
||||
if: github.event_name == 'pull_request'
|
||||
env:
|
||||
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
run: bash scripts/require-tests.sh
|
||||
|
||||
build:
|
||||
timeout-minutes: 15
|
||||
needs: detect-changes
|
||||
|
|
@ -145,6 +151,9 @@ jobs:
|
|||
- name: Run integration tests
|
||||
run: npm run test:integration
|
||||
|
||||
- name: Check test coverage thresholds
|
||||
run: npm run test:coverage
|
||||
|
||||
windows-portability:
|
||||
timeout-minutes: 15
|
||||
needs: detect-changes
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
"test:unit": "node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --experimental-test-isolation=process --test src/resources/extensions/gsd/tests/*.test.ts src/resources/extensions/gsd/tests/*.test.mjs src/tests/*.test.ts",
|
||||
"test:packages": "node --test packages/pi-coding-agent/dist/core/*.test.js",
|
||||
"test:marketplace": "GSD_TEST_CLONE_MARKETPLACES=1 node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/claude-import-tui.test.ts src/resources/extensions/gsd/tests/plugin-importer-live.test.ts src/tests/marketplace-discovery.test.ts",
|
||||
"test:coverage": "c8 --reporter=text --reporter=lcov --exclude='src/resources/extensions/gsd/tests/**' --exclude='src/tests/**' --exclude='scripts/**' --exclude='native/**' --exclude='node_modules/**' --check-coverage --statements=50 --lines=50 --branches=20 --functions=20 node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --experimental-test-isolation=process --test src/resources/extensions/gsd/tests/*.test.ts src/resources/extensions/gsd/tests/*.test.mjs src/tests/*.test.ts",
|
||||
"test:coverage": "c8 --reporter=text --reporter=lcov --exclude='src/resources/extensions/gsd/tests/**' --exclude='src/tests/**' --exclude='scripts/**' --exclude='native/**' --exclude='node_modules/**' --check-coverage --statements=40 --lines=40 --branches=20 --functions=20 node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --experimental-test-isolation=process --test src/resources/extensions/gsd/tests/*.test.ts src/resources/extensions/gsd/tests/*.test.mjs src/tests/*.test.ts",
|
||||
"test:integration": "node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --experimental-test-isolation=process --test src/resources/extensions/gsd/tests/*integration*.test.ts src/tests/integration/*.test.ts",
|
||||
"pretest": "npm run typecheck:extensions",
|
||||
"test": "npm run test:unit && npm run test:integration",
|
||||
|
|
|
|||
67
scripts/require-tests.sh
Executable file
67
scripts/require-tests.sh
Executable file
|
|
@ -0,0 +1,67 @@
|
|||
#!/usr/bin/env bash
|
||||
# GSD-2 — Require tests with source changes
|
||||
# Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
||||
#
|
||||
# Fails CI if a PR changes source files but includes no test file changes.
|
||||
# Exemptions: docs-only, CI/config, test-only, and chore branches.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# --- resolve base ref ---
|
||||
if [ -n "${PR_BASE_SHA:-}" ]; then
|
||||
BASE="$PR_BASE_SHA"
|
||||
elif [ -n "${PUSH_BEFORE_SHA:-}" ]; then
|
||||
BASE="$PUSH_BEFORE_SHA"
|
||||
else
|
||||
BASE="origin/main"
|
||||
fi
|
||||
|
||||
FILES=$(git diff --name-only "$BASE" HEAD 2>/dev/null || git diff --name-only HEAD~1)
|
||||
|
||||
# --- exempt branch types that don't need tests ---
|
||||
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
|
||||
if [[ "$BRANCH" =~ ^(docs|chore|ci)/ ]]; then
|
||||
echo "✓ Branch type '${BRANCH%%/*}/' is exempt from test requirements"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# --- classify changed files ---
|
||||
# Source files: .ts/.mts/.mjs/.js in src/ or packages/, excluding tests and type declarations
|
||||
SRC_FILES=$(echo "$FILES" | grep -E '^(src|packages)/.*\.(ts|mts|mjs|js)$' \
|
||||
| grep -vE '\.(test|spec)\.' \
|
||||
| grep -vE '\.d\.ts$' \
|
||||
| grep -vE '__tests__/' \
|
||||
| grep -vE '/tests/' \
|
||||
|| true)
|
||||
|
||||
# Test files: anything with .test. or .spec. or inside __tests__/ or tests/
|
||||
TEST_FILES=$(echo "$FILES" | grep -E '\.(test|spec)\.(ts|mts|mjs|js|cjs)$' || true)
|
||||
|
||||
# --- no source changes? nothing to enforce ---
|
||||
if [ -z "$SRC_FILES" ]; then
|
||||
echo "✓ No source file changes detected — test requirement does not apply"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# --- source changes exist — require test changes ---
|
||||
SRC_COUNT=$(echo "$SRC_FILES" | wc -l | tr -d ' ')
|
||||
|
||||
if [ -z "$TEST_FILES" ]; then
|
||||
echo "──────────────────────────────────────────────────────"
|
||||
echo "✗ FAILED: Source files changed but no tests included"
|
||||
echo "──────────────────────────────────────────────────────"
|
||||
echo ""
|
||||
echo "Changed source files ($SRC_COUNT):"
|
||||
echo "$SRC_FILES" | sed 's/^/ /'
|
||||
echo ""
|
||||
echo "Per CONTRIBUTING.md:"
|
||||
echo " • Bug fixes must include a regression test"
|
||||
echo " • Features must include tests covering primary success + one failure path"
|
||||
echo " • Behavior changes must update existing tests"
|
||||
echo ""
|
||||
echo "Add or update test files (*.test.ts) to proceed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TEST_COUNT=$(echo "$TEST_FILES" | wc -l | tr -d ' ')
|
||||
echo "✓ Test requirement satisfied: $SRC_COUNT source file(s), $TEST_COUNT test file(s) changed"
|
||||
Loading…
Add table
Reference in a new issue