mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-11-10 23:07:13 +01:00
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (flutter, flutter-analyze, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (mypy, mypy, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (pylint, pylint, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (rest, , mypy,pylint,flutter-analyze) (push) Waiting to run
Tests / test (push) Waiting to run
Tests / lock-popup-safety (push) Waiting to run
Tests / flutter test (shard ${{ matrix.shard }}) (0) (push) Waiting to run
Tests / flutter test (shard ${{ matrix.shard }}) (1) (push) Waiting to run
Tests / flutter test (shard ${{ matrix.shard }}) (2) (push) Waiting to run
Tests / flutter test (shard ${{ matrix.shard }}) (3) (push) Waiting to run
Tests / flutter test (shard ${{ matrix.shard }}) (4) (push) Waiting to run
Tests / flutter test (shard ${{ matrix.shard }}) (5) (push) Waiting to run
Tests / flutter test (shard ${{ matrix.shard }}) (6) (push) Waiting to run
Tests / flutter test (shard ${{ matrix.shard }}) (7) (push) Waiting to run
Tests / flutter-coverage (push) Blocked by required conditions
Tests / web-coverage (push) Waiting to run
release-apk / release (APK) (push) Waiting to run
Tests (~214 s, gated by flutter-coverage): - Flutter suite runs as 8 parallel buckets of whole test files (check_flutter_coverage.sh --shard I/N); flutter-coverage merges their lcov files (--merged N) and applies the unchanged 100% bar and every-lib-file-present guard. `flutter test --total-shards` splits test cases inside each file, so every shard would still compile all 77 files. Proved locally: the merged lcov matches an unsharded run line for line (3312/3312), and a missing shard fails. flutter-action caches the SDK. - pytest: uv install, -n auto -q -p no:sugar (local: 25.9 s -> 10.6 s, 100% coverage both ways). - lock-popup-safety: uv, and no apt step -- xvfb-run and setup-python's tkinter are already on the runner (screens-fit relies on both already). pre-commit (~122 s): matrix of mypy / pylint / flutter-analyze / rest, each installing only its own toolchain, with a per-group hook cache. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0188kZdx3bb56QM8JFUnbHuM
213 lines
7.7 KiB
Bash
Executable File
213 lines
7.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Enforces 100% line coverage for the Flutter workout app.
|
|
#
|
|
# Run from the repo root. Fails if:
|
|
# 1. Any lib/**/*.dart file is missing from coverage/lcov.info (unreachable
|
|
# file — the 100% would be fake without this check).
|
|
# 2. Line coverage across all lib/ files is below 100%.
|
|
#
|
|
# Usage:
|
|
# scripts/check_flutter_coverage.sh whole suite, then both checks
|
|
# scripts/check_flutter_coverage.sh --shard I/N test bucket I of N (0-based)
|
|
# only; leaves its lcov.info,
|
|
# checks nothing
|
|
# scripts/check_flutter_coverage.sh --merged N LCOV...
|
|
# union N shards' lcov files
|
|
# into coverage/lcov.info,
|
|
# then both checks
|
|
#
|
|
# Why shards: the suite took ~150 s on one 4-core runner, almost all of it
|
|
# compiling 77 test files. `flutter test --total-shards` cannot help -- it
|
|
# splits the test CASES inside every file, so each shard still compiles all
|
|
# 77 -- hence buckets of whole files, one per CI runner, and a fan-in job that
|
|
# runs the same two checks on their union.
|
|
set -euo pipefail
|
|
|
|
APP_DIR="stronglift_replacement/workout_app"
|
|
LCOV_INFO="$APP_DIR/coverage/lcov.info"
|
|
|
|
die() {
|
|
echo "ERROR: $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
# Runs `flutter test --coverage` in the app, on the given test files (none =
|
|
# the whole suite).
|
|
run_flutter_tests() {
|
|
echo "Running flutter test --coverage ..."
|
|
# env -u GIT_DIR: git exports it to hooks, and the flutter tool shells out to
|
|
# git to identify its own SDK. With it set, flutter reads THIS repository as
|
|
# the SDK -- reporting our HEAD as the framework revision -- and pub then
|
|
# resolves every version constraint against "0.0.0-unknown" and fails.
|
|
# FLUTTER_TEST_CONCURRENCY: one test isolate per core is the default and
|
|
# peaks well over 4 GiB on this suite, which the 4 GiB resource cap
|
|
# (capped.sh) OOM-kills. Set it to 1-2 under the cap; unset keeps the default.
|
|
local concurrency=()
|
|
if [[ -n "${FLUTTER_TEST_CONCURRENCY:-}" ]]; then
|
|
concurrency=(--concurrency "$FLUTTER_TEST_CONCURRENCY")
|
|
fi
|
|
(cd "$APP_DIR" && env -u GIT_DIR -u GIT_WORK_TREE -u GIT_INDEX_FILE \
|
|
flutter test --coverage "${concurrency[@]}" "$@")
|
|
}
|
|
|
|
# Prints bucket INDEX of TOTAL: every TOTAL-th test file, in a fixed sort
|
|
# order, so the N buckets partition the suite exactly.
|
|
shard_files() {
|
|
local index=$1 total=$2 i=0 file
|
|
while IFS= read -r file; do
|
|
if (( i % total == index )); then
|
|
printf '%s\n' "$file"
|
|
fi
|
|
i=$(( i + 1 ))
|
|
done < <(cd "$APP_DIR" && find test -name '*_test.dart' | LC_ALL=C sort)
|
|
}
|
|
|
|
# Writes to OUT the union of the given lcov files: per source file, every
|
|
# line any shard instrumented, hit if any shard hit it -- which is what one
|
|
# unsharded run reports, since flutter merges its test isolates the same way.
|
|
# LF/LH are recomputed from that union rather than summed, because a lib file
|
|
# loaded by two shards would otherwise count its lines twice.
|
|
merge_lcov() {
|
|
local out=$1 file line sf="" rest ln hits key lf lh
|
|
shift
|
|
local -A hit=() lines_of=() seen=()
|
|
local -a order=()
|
|
for file in "$@"; do
|
|
while IFS= read -r line; do
|
|
case $line in
|
|
SF:*)
|
|
sf=${line#SF:}
|
|
if [[ -z ${seen[$sf]:-} ]]; then
|
|
seen[$sf]=1
|
|
order+=("$sf")
|
|
fi
|
|
;;
|
|
DA:*)
|
|
rest=${line#DA:}
|
|
ln=${rest%%,*}
|
|
rest=${rest#*,}
|
|
hits=${rest%%,*}
|
|
key="$sf|$ln"
|
|
if [[ -z ${hit[$key]:-} ]]; then
|
|
hit[$key]=$hits
|
|
lines_of[$sf]+="$ln "
|
|
else
|
|
hit[$key]=$(( hit[$key] + hits ))
|
|
fi
|
|
;;
|
|
esac
|
|
done < "$file"
|
|
done
|
|
mkdir -p "$(dirname "$out")"
|
|
for sf in "${order[@]}"; do
|
|
echo "SF:$sf"
|
|
lf=0
|
|
lh=0
|
|
for ln in ${lines_of[$sf]:-}; do
|
|
echo "DA:$ln,${hit[$sf|$ln]}"
|
|
lf=$(( lf + 1 ))
|
|
if (( hit[$sf|$ln] > 0 )); then
|
|
lh=$(( lh + 1 ))
|
|
fi
|
|
done
|
|
echo "LF:$lf"
|
|
echo "LH:$lh"
|
|
echo "end_of_record"
|
|
done > "$out"
|
|
}
|
|
|
|
case "${1:-}" in
|
|
"")
|
|
run_flutter_tests
|
|
;;
|
|
--shard)
|
|
[[ ${2:-} =~ ^([0-9]+)/([1-9][0-9]*)$ ]] || die "--shard wants I/N, got '${2:-}'"
|
|
index=${BASH_REMATCH[1]}
|
|
total=${BASH_REMATCH[2]}
|
|
(( index < total )) || die "shard index $index is not below $total"
|
|
mapfile -t files < <(shard_files "$index" "$total")
|
|
(( ${#files[@]} > 0 )) || die "shard $index/$total has no test files"
|
|
echo "Shard $index/$total: ${#files[@]} test files"
|
|
run_flutter_tests "${files[@]}"
|
|
exit 0
|
|
;;
|
|
--merged)
|
|
[[ ${2:-} =~ ^[1-9][0-9]*$ ]] || die "--merged wants a shard count first"
|
|
expected=$2
|
|
shift 2
|
|
# A shard whose artifact went missing would quietly shrink the union.
|
|
(( $# == expected )) || die "expected $expected shard lcov files, got $#"
|
|
merge_lcov "$LCOV_INFO" "$@"
|
|
;;
|
|
*)
|
|
die "unknown argument '$1' (see the usage at the top of $0)"
|
|
;;
|
|
esac
|
|
|
|
if [[ ! -f "$LCOV_INFO" ]]; then
|
|
echo "ERROR: $LCOV_INFO not found — did flutter test run?" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# ── Guard: every lib/**/*.dart must appear in the coverage report ──────────────
|
|
# Flutter only reports files that are transitively imported by a test.
|
|
# Unreferenced files silently score 100% by absence — catch that here.
|
|
#
|
|
# Exception: a file whose only content is a conditional `export` (a
|
|
# platform-gate barrel like google_platform.dart, re-exporting google_platform_io.dart
|
|
# or google_platform_web.dart per dart.library.js_interop) has zero executable
|
|
# statements. Dart's coverage instrumentation never emits an SF: entry for such
|
|
# a file regardless of whether it was imported -- there is no "silently 100% by
|
|
# absence" for it to hide, since there is nothing to cover. Importing it (even
|
|
# transitively) is what makes its *resolved* sibling appear in lcov instead.
|
|
barrel_pattern="^(library;)?[[:space:]]*export[[:space:]]+'[^']+'[[:space:]]+if[[:space:]]*\([^)]+\)[[:space:]]+'[^']+';[[:space:]]*\$"
|
|
|
|
missing=0
|
|
while IFS= read -r dart_file; do
|
|
rel="${dart_file#"$APP_DIR"/}"
|
|
# Strip //-comments, ///-doc-comments and blank lines, then collapse
|
|
# whitespace, so a wrapped `export 'x' if (...) 'y';` statement (the
|
|
# platform-gate barrel shape) becomes matchable on one logical line
|
|
# regardless of how it's line-wrapped in source.
|
|
code_only=$(grep -vE '^[[:space:]]*(///|//|$)' "$dart_file" | tr '\n' ' ' | tr -s ' ')
|
|
if [[ $code_only =~ $barrel_pattern ]]; then
|
|
continue
|
|
fi
|
|
if ! grep -qF "SF:$rel" "$LCOV_INFO" && \
|
|
! grep -qF "SF:lib/${rel#lib/}" "$LCOV_INFO"; then
|
|
echo "MISSING FROM COVERAGE: $dart_file" >&2
|
|
missing=1
|
|
fi
|
|
done < <(find "$APP_DIR/lib" -name "*.dart" ! -path "*/generated/*")
|
|
|
|
if [[ $missing -eq 1 ]]; then
|
|
echo ""
|
|
echo "ERROR: Some lib/ files are not covered. Import them in a test." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# ── Compute line coverage percentage from lcov.info ───────────────────────────
|
|
total_found=0
|
|
total_hit=0
|
|
while IFS= read -r line; do
|
|
if [[ $line == LF:* ]]; then
|
|
total_found=$(( total_found + ${line#LF:} ))
|
|
elif [[ $line == LH:* ]]; then
|
|
total_hit=$(( total_hit + ${line#LH:} ))
|
|
fi
|
|
done < "$LCOV_INFO"
|
|
|
|
if [[ $total_found -eq 0 ]]; then
|
|
echo "ERROR: No line coverage data found in $LCOV_INFO" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ $total_hit -lt $total_found ]]; then
|
|
missed=$(( total_found - total_hit ))
|
|
echo "ERROR: Line coverage is not 100% — $missed/$total_found lines not covered." >&2
|
|
echo "Run: flutter test --coverage && genhtml coverage/lcov.info -o coverage/html" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "Coverage OK: $total_hit/$total_found lines covered (100%)."
|