Files
openhuman/scripts/ci/vitest-changed-coverage.sh

82 lines
3.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# PR CI frontend unit-test lane — changed-files-only Vitest.
#
# Fast-lane policy (PRs targeting main): run only the tests related to the
# files the PR actually changed, via `vitest related` (static import graph —
# reliable here because dynamic imports are banned in app/src). Coverage is
# still written to app/coverage/lcov.info; the PR CI Gate's diff-cover step
# then enforces >= 80% on changed lines. Untested changed files still appear
# in the lcov report at 0% (vitest coverage.include is explicit), so the gate
# cannot be dodged by having no related tests.
#
# Inputs (env):
# FULL "true" → run the entire suite with coverage (config-level
# change: lockfile, vitest/vite/ts config, test setup, etc.)
# CHANGED_FILES shell-quoted, space-separated repo-relative paths from
# dorny/paths-filter (list-files: shell)
#
# Falls back to the FULL suite whenever scoping is not clearly safe.
set -euo pipefail
FULL="${FULL:-false}"
CHANGED_FILES="${CHANGED_FILES:-}"
# Above this many changed source files a scoped run buys little and the
# argv/related-graph bookkeeping gets silly — just run everything.
MAX_RELATED_FILES="${MAX_RELATED_FILES:-200}"
log() { echo "[ci][vitest-changed] $*"; }
run_full() {
log "running FULL Vitest coverage suite (reason: $1)"
exec bash scripts/ci-cancel-aware.sh pnpm --filter openhuman-app test:coverage
}
if [ "${FULL}" = "true" ]; then
run_full "config/workflow-level change detected by paths-filter"
fi
# CHANGED_FILES is the shell-quoted list from dorny/paths-filter
# (list-files: shell). Filenames are PR-controlled, so never eval it —
# xargs unquotes tokens as data without ever invoking a shell. If xargs
# can't parse it (e.g. hostile quoting), we get an empty list and fall
# back to the full suite.
declare -a files=()
while IFS= read -r f; do
[ -n "${f}" ] && files+=("${f}")
done < <(printf '%s\n' "${CHANGED_FILES}" | xargs -n1 printf '%s\n' 2>/dev/null || true)
log "received ${#files[@]} changed frontend file(s)"
if [ "${#files[@]}" -eq 0 ]; then
run_full "empty changed-file list — scoping unsafe"
fi
declare -a related=()
for f in "${files[@]}"; do
case "${f}" in
app/src/*.ts | app/src/*.tsx) ;;
*)
log "ignoring non-source path: ${f}"
continue
;;
esac
if [ ! -f "${f}" ]; then
log "skipping deleted/renamed file: ${f}"
continue
fi
# vitest runs from app/ (config root) — strip the workspace prefix.
related+=("${f#app/}")
done
if [ "${#related[@]}" -eq 0 ]; then
run_full "no surviving changed .ts/.tsx files under app/src — scoping unsafe"
fi
if [ "${#related[@]}" -gt "${MAX_RELATED_FILES}" ]; then
run_full "${#related[@]} changed files exceed MAX_RELATED_FILES=${MAX_RELATED_FILES}"
fi
log "running 'vitest related' with coverage for ${#related[@]} file(s):"
printf '[ci][vitest-changed] %s\n' "${related[@]}"
cd app
exec bash ../scripts/ci-cancel-aware.sh pnpm exec vitest related --run --coverage --config test/vitest.config.ts "${related[@]}"