243 lines
7.4 KiB
Bash
Executable File
243 lines
7.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT="$(git rev-parse --show-toplevel)"
|
|
CONFIG_PATH="${ROOT}/files/config/runtime-edge-coverage-domains.json"
|
|
DEFAULT_REPORT="${ROOT}/target/llvm-cov/report.json"
|
|
GREEN=$'\033[32m'
|
|
RED=$'\033[31m'
|
|
CYAN=$'\033[36m'
|
|
RESET=$'\033[0m'
|
|
|
|
line_percent() {
|
|
jq -r --arg domain "${1}" --arg root "${ROOT}" '
|
|
.domains[$domain].paths as $paths
|
|
| def matches_domain:
|
|
. as $file
|
|
| any($paths[]; . as $p | ($file.filename | startswith($root + "/" + $p) or startswith("./" + $p) or startswith($p)));
|
|
def pct($covered; $count):
|
|
if $count > 0 then (($covered * 10000 / $count | floor) / 100) else 0 end;
|
|
reduce (
|
|
input.data[]?.files[]?
|
|
| select(matches_domain)
|
|
) as $file (
|
|
{lines: {count: 0, covered: 0}};
|
|
.lines.count += ($file.summary.lines.count // 0)
|
|
| .lines.covered += ($file.summary.lines.covered // 0)
|
|
)
|
|
| pct(.lines.covered; .lines.count)
|
|
' "${CONFIG_PATH}" "${2}"
|
|
}
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage:
|
|
coverage-domain-evidence.sh --list
|
|
coverage-domain-evidence.sh [--check] [--show-summary-details] [--show-paths] [--show-tracked-files] [--show-matched-files] [--verbose] <domain> [report.json]
|
|
coverage-domain-evidence.sh [--show-summary-details] [--show-paths] [--show-tracked-files] [--show-matched-files] [--verbose] --check-all [report.json]
|
|
|
|
The report path defaults to target/llvm-cov/report.json and is expected to be
|
|
generated by `make ci` or `make coverage-report-json`.
|
|
EOF
|
|
}
|
|
|
|
if [[ ! -f "${CONFIG_PATH}" ]]; then
|
|
echo "missing coverage domain config: ${CONFIG_PATH}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ $# -eq 0 ]]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$1" == "--list" ]]; then
|
|
jq -r '.domains | keys[]' "${CONFIG_PATH}"
|
|
exit 0
|
|
fi
|
|
|
|
CHECK_MODE=0
|
|
CHECK_ALL=0
|
|
SHOW_PATHS=0
|
|
SHOW_TRACKED_FILES=0
|
|
SHOW_MATCHED_FILES=0
|
|
SHOW_SUMMARY_DETAILS=0
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--check)
|
|
CHECK_MODE=1
|
|
shift
|
|
;;
|
|
--check-all)
|
|
CHECK_MODE=1
|
|
CHECK_ALL=1
|
|
shift
|
|
;;
|
|
--show-paths)
|
|
SHOW_PATHS=1
|
|
shift
|
|
;;
|
|
--show-summary-details)
|
|
SHOW_SUMMARY_DETAILS=1
|
|
shift
|
|
;;
|
|
--show-tracked-files)
|
|
SHOW_TRACKED_FILES=1
|
|
shift
|
|
;;
|
|
--show-matched-files)
|
|
SHOW_MATCHED_FILES=1
|
|
shift
|
|
;;
|
|
--verbose)
|
|
SHOW_SUMMARY_DETAILS=1
|
|
SHOW_PATHS=1
|
|
SHOW_TRACKED_FILES=1
|
|
SHOW_MATCHED_FILES=1
|
|
shift
|
|
;;
|
|
--)
|
|
shift
|
|
break
|
|
;;
|
|
-*)
|
|
echo "unknown option: $1" >&2
|
|
usage
|
|
exit 1
|
|
;;
|
|
*)
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ ${CHECK_ALL} -eq 1 ]]; then
|
|
REPORT_PATH="${1:-${DEFAULT_REPORT}}"
|
|
FAIL=0
|
|
|
|
while IFS= read -r domain; do
|
|
ARGS=(--check)
|
|
[[ ${SHOW_SUMMARY_DETAILS} -eq 1 ]] && ARGS+=(--show-summary-details)
|
|
[[ ${SHOW_PATHS} -eq 1 ]] && ARGS+=(--show-paths)
|
|
[[ ${SHOW_TRACKED_FILES} -eq 1 ]] && ARGS+=(--show-tracked-files)
|
|
[[ ${SHOW_MATCHED_FILES} -eq 1 ]] && ARGS+=(--show-matched-files)
|
|
"${BASH_SOURCE[0]}" "${ARGS[@]}" "${domain}" "${REPORT_PATH}" || FAIL=1
|
|
echo
|
|
done < <(jq -r '.domains | keys[]' "${CONFIG_PATH}")
|
|
|
|
exit "${FAIL}"
|
|
fi
|
|
|
|
DOMAIN="${1:-}"
|
|
REPORT_PATH="${2:-${DEFAULT_REPORT}}"
|
|
|
|
if [[ -z "${DOMAIN}" ]]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
if ! jq -e --arg domain "${DOMAIN}" '.domains[$domain]' "${CONFIG_PATH}" >/dev/null; then
|
|
echo "unknown domain: ${DOMAIN}" >&2
|
|
echo "available domains:" >&2
|
|
jq -r '.domains | keys[]' "${CONFIG_PATH}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
BASELINE="$(jq -r --arg domain "${DOMAIN}" '.domains[$domain].baseline_percent' "${CONFIG_PATH}")"
|
|
|
|
if [[ ${SHOW_PATHS} -eq 1 ]]; then
|
|
echo "Mapped repository paths:"
|
|
jq -r --arg domain "${DOMAIN}" '.domains[$domain].paths[]' "${CONFIG_PATH}" | while IFS= read -r prefix; do
|
|
echo " - ${prefix}"
|
|
done
|
|
echo
|
|
fi
|
|
|
|
if [[ ${SHOW_TRACKED_FILES} -eq 1 ]]; then
|
|
echo "Tracked files present in repository:"
|
|
while IFS= read -r path; do
|
|
(
|
|
cd "${ROOT}"
|
|
rg --files . | sed 's#^\./##'
|
|
) | rg "^${path//\//\\/}" || true
|
|
done < <(jq -r --arg domain "${DOMAIN}" '.domains[$domain].paths[]' "${CONFIG_PATH}")
|
|
echo
|
|
fi
|
|
|
|
if [[ ! -f "${REPORT_PATH}" ]]; then
|
|
echo "Coverage report not found: ${REPORT_PATH}"
|
|
echo "Generate it with: make coverage-report-json"
|
|
if [[ ${CHECK_MODE} -eq 1 ]]; then
|
|
exit 1
|
|
fi
|
|
exit 0
|
|
fi
|
|
|
|
jq -r --arg domain "${DOMAIN}" --arg root "${ROOT}" --argjson baseline "${BASELINE}" --argjson show_matched_files "${SHOW_MATCHED_FILES}" --argjson show_summary_details "${SHOW_SUMMARY_DETAILS}" '
|
|
.domains[$domain].paths as $paths
|
|
| def matches_domain:
|
|
. as $file
|
|
| any($paths[]; . as $p | ($file.filename | startswith($root + "/" + $p) or startswith("./" + $p) or startswith($p)));
|
|
def pct($covered; $count):
|
|
if $count > 0 then (($covered * 10000 / $count | floor) / 100) else 0 end;
|
|
reduce (
|
|
input.data[]?.files[]?
|
|
| select(matches_domain)
|
|
) as $file (
|
|
{
|
|
files: [],
|
|
lines: {count: 0, covered: 0},
|
|
functions: {count: 0, covered: 0},
|
|
regions: {count: 0, covered: 0}
|
|
};
|
|
.files += [$file.filename]
|
|
| .lines.count += ($file.summary.lines.count // 0)
|
|
| .lines.covered += ($file.summary.lines.covered // 0)
|
|
| .functions.count += ($file.summary.functions.count // 0)
|
|
| .functions.covered += ($file.summary.functions.covered // 0)
|
|
| .regions.count += ($file.summary.regions.count // 0)
|
|
| .regions.covered += ($file.summary.regions.covered // 0)
|
|
)
|
|
| . + {line_percent: pct(.lines.covered; .lines.count)}
|
|
| (if $show_summary_details == 1 then "lines: " + (.line_percent | tostring) + "% (" + (.lines.covered|tostring) + "/" + (.lines.count|tostring) + ")" else empty end),
|
|
(if $show_summary_details == 1 then " files_in_report: " + (.files | length | tostring) else empty end),
|
|
(if $show_summary_details == 1 then
|
|
" functions: " + (pct(.functions.covered; .functions.count) | tostring) + "% (" + (.functions.covered|tostring) + "/" + (.functions.count|tostring) + ")"
|
|
else empty end),
|
|
(if $show_summary_details == 1 then
|
|
" regions: " + (pct(.regions.covered; .regions.count) | tostring) + "% (" + (.regions.covered|tostring) + "/" + (.regions.count|tostring) + ")"
|
|
else empty end),
|
|
(if $show_matched_files == 1 then "" else empty end),
|
|
(if $show_matched_files == 1 then "Matched report files:" else empty end),
|
|
(if $show_matched_files == 1 then (.files[]? | " - " + .) else empty end)
|
|
' "${CONFIG_PATH}" "${REPORT_PATH}"
|
|
|
|
LINE_PERCENT="$(line_percent "${DOMAIN}" "${REPORT_PATH}")"
|
|
|
|
if awk "BEGIN { exit !(${LINE_PERCENT} >= ${BASELINE}) }"; then
|
|
GATE_STATUS="${GREEN}PASS${RESET}"
|
|
else
|
|
GATE_STATUS="${RED}FAIL${RESET}"
|
|
fi
|
|
|
|
LINE="Domain: ${DOMAIN} :: GATE(lines>=baseline) [${CYAN}${LINE_PERCENT}%${RESET} >= ${RED}${BASELINE}%${RESET}]: ${GATE_STATUS}"
|
|
VISIBLE_LINE="Domain: ${DOMAIN} :: GATE(lines>=baseline) [${LINE_PERCENT}% >= ${BASELINE}%]: PASS"
|
|
if awk "BEGIN { exit !(${LINE_PERCENT} >= ${BASELINE}) }"; then
|
|
VISIBLE_LINE="Domain: ${DOMAIN} :: GATE(lines>=baseline) [${LINE_PERCENT}% >= ${BASELINE}%]: PASS"
|
|
else
|
|
VISIBLE_LINE="Domain: ${DOMAIN} :: GATE(lines>=baseline) [${LINE_PERCENT}% >= ${BASELINE}%]: FAIL"
|
|
fi
|
|
LINE_WIDTH="${#VISIBLE_LINE}"
|
|
BORDER="$(printf '═%.0s' $(seq 1 "${LINE_WIDTH}"))"
|
|
echo "╔${BORDER}╗"
|
|
echo "║${LINE}║"
|
|
echo "╚${BORDER}╝"
|
|
|
|
if [[ ${CHECK_MODE} -eq 1 ]]; then
|
|
awk "BEGIN { exit !(${LINE_PERCENT} < ${BASELINE}) }" && {
|
|
echo "Domain coverage gate failed for ${DOMAIN}: ${LINE_PERCENT}% is below baseline ${BASELINE}%"
|
|
exit 1
|
|
} || true
|
|
fi
|