mirror of
https://github.com/mudler/LocalAI.git
synced 2026-10-29 01:28:43 -04:00
The previous commit added per-root log files but forgot to create the output directory before the first ginkgo invocation. On CI the coverage/ dir did not exist yet, so the shell redirect to cover-pkg.out.log failed with "No such file or directory" before ginkgo even ran. Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
151 lines
4.5 KiB
Bash
Executable File
151 lines
4.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# shellcheck disable=SC2312
|
|
#
|
|
# run-coverage.sh — run ginkgo per test root, merge coverprofiles, and
|
|
# enforce a coverage floor. Designed for POSIX sh (dash) and bash.
|
|
#
|
|
# Usage:
|
|
# run-coverage.sh OUTPUT_DIR MERGED_PROFILE FLAKE_ATTEMPTS UNIT_ROOT...
|
|
#
|
|
# Environment:
|
|
# GINKGO_TAGS Space-separated build tags (e.g. "debug auth").
|
|
# COVERAGE_COVERPKG Comma-separated --coverpkg pattern.
|
|
# COVERAGE_E2E_ROOTS Space-separated non-recursive e2e roots.
|
|
# COVERAGE_E2E_LABELS Ginkgo --label-filter for e2e roots.
|
|
# COVERAGE_EXCLUDE_RE Regex for coverprofile lines to drop on merge.
|
|
#
|
|
# Each ginkgo invocation's combined stdout+stderr is captured to a per-root
|
|
# log file (OUTPUT_DIR/<root>.log). On failure the last 80 lines are
|
|
# printed to stderr so the error is visible under `make --output-sync=target`
|
|
# (which buffers all output and flushes at the end, hiding the actual error
|
|
# in interleaved output). On success the log is replayed to stdout.
|
|
|
|
set -u
|
|
|
|
out_dir="${1:?usage: run-coverage.sh OUTPUT_DIR MERGED_PROFILE FLAKES UNIT_ROOT...}"
|
|
merged="${2:?missing MERGED_PROFILE}"
|
|
flakes="${3:?missing FLAKE_ATTEMPTS}"
|
|
shift 3
|
|
unit_roots="$*"
|
|
|
|
fail=0
|
|
mkdir -p "$out_dir"
|
|
|
|
# Build flags shared by every ginkgo invocation. We store them as a
|
|
# newline-delimited list in $build_flags_list so we can iterate without
|
|
# word-splitting issues (e.g. --tags="debug auth" contains a space).
|
|
build_flags_list=""
|
|
if [ -n "${GINKGO_TAGS:-}" ]; then
|
|
build_flags_list="${build_flags_list}${build_flags_list:+
|
|
}--tags=$GINKGO_TAGS"
|
|
fi
|
|
if [ -n "${COVERAGE_COVERPKG:-}" ]; then
|
|
build_flags_list="${build_flags_list}${build_flags_list:+
|
|
}--coverpkg=$COVERAGE_COVERPKG"
|
|
fi
|
|
|
|
# cover-<root>.out, with path separators flattened (POSIX BRE, no \+).
|
|
profile_name() {
|
|
printf 'cover-%s.out' "$(printf '%s' "$1" | sed 's#[./][./]*#_#g; s#^_##; s#_$##')"
|
|
}
|
|
|
|
# run_ginkgo ROOT RECURSIVE [LABEL_FILTER]
|
|
# Runs ginkgo for ROOT, captures combined output to a log file, and on
|
|
# failure prints the tail to stderr.
|
|
run_ginkgo() {
|
|
_root="$1"
|
|
_recursive="$2"
|
|
_label_filter="${3:-}"
|
|
_base="$(profile_name "$_root")"
|
|
_log="$out_dir/$_base.log"
|
|
|
|
if [ "$_recursive" = "1" ]; then
|
|
_rflag="-r"
|
|
else
|
|
_rflag=""
|
|
fi
|
|
|
|
# Build the ginkgo command. We use eval to properly handle --tags
|
|
# values that contain spaces. The build_flags_list is newline-delimited;
|
|
# we convert newlines to spaces for the eval string. Each flag is
|
|
# already in the form --key=value, and the value never contains shell
|
|
# metacharacters (tags are alphanum, coverpkg is a Go pattern).
|
|
_cmd="go run github.com/onsi/ginkgo/v2/ginkgo --flake-attempts $flakes -v $_rflag"
|
|
# Append build flags (one per line -> one per arg)
|
|
if [ -n "$build_flags_list" ]; then
|
|
_bf=$(printf '%s' "$build_flags_list" | while IFS= read -r _line; do
|
|
# Quote the value part after = so spaces are preserved
|
|
printf '%s ' "${_line%%=*}=\"${_line#*=}\""
|
|
done)
|
|
_cmd="$_cmd $_bf"
|
|
fi
|
|
if [ -n "$_label_filter" ]; then
|
|
_cmd="$_cmd --label-filter=$_label_filter"
|
|
fi
|
|
_cmd="$_cmd --cover --covermode=atomic --coverprofile=$_base --output-dir=$out_dir $_root"
|
|
|
|
# Run ginkgo, capture all output to the log file.
|
|
eval "$_cmd" >"$_log" 2>&1
|
|
_rc=$?
|
|
if [ "$_rc" -ne 0 ]; then
|
|
echo "run-coverage: ginkgo failed for $_root (exit $_rc), last 80 lines:" >&2
|
|
tail -80 "$_log" >&2
|
|
fail=1
|
|
else
|
|
# Replay the log so test output is visible in CI.
|
|
cat "$_log"
|
|
fi
|
|
return "$_rc"
|
|
}
|
|
|
|
# Unit/suite roots: recursive.
|
|
for root in $unit_roots; do
|
|
run_ginkgo "$root" 1 || true
|
|
done
|
|
|
|
# In-process integration roots: NON-recursive + optional label filter.
|
|
for root in ${COVERAGE_E2E_ROOTS:-}; do
|
|
run_ginkgo "$root" 0 "${COVERAGE_E2E_LABELS:-}" || true
|
|
done
|
|
|
|
#########################################################
|
|
## Merge coverprofiles
|
|
#########################################################
|
|
|
|
# Collect all coverprofiles except the merged one.
|
|
profiles=""
|
|
for f in "$out_dir"/cover-*.out; do
|
|
[ -f "$f" ] || continue
|
|
[ "$f" = "$merged" ] && continue
|
|
if [ -z "$profiles" ]; then
|
|
profiles="$f"
|
|
else
|
|
profiles="$profiles $f"
|
|
fi
|
|
done
|
|
|
|
if [ -z "$profiles" ]; then
|
|
echo "run-coverage: no coverprofiles found in $out_dir" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Merge: drop the mode line from all but the first profile, optionally
|
|
# exclude generated proto files, then concatenate.
|
|
first=1
|
|
for f in $profiles; do
|
|
if [ "$first" = "1" ]; then
|
|
cat "$f"
|
|
first=0
|
|
else
|
|
tail -n +2 "$f"
|
|
fi
|
|
done | { if [ -n "${COVERAGE_EXCLUDE_RE:-}" ]; then
|
|
grep -vE "$COVERAGE_EXCLUDE_RE"
|
|
else
|
|
cat
|
|
fi; } >"$merged"
|
|
|
|
echo "run-coverage: merged $(echo "$profiles" | wc -w) coverprofiles into $merged"
|
|
|
|
exit "$fail"
|