#!/bin/sh # # Requirement traceability gate. Run locally exactly as CI runs it, from the # component repo root: # # scripts/traceability/traceability-gate.sh # # Writes the JSON report and the markdown matrix, prints the coverage report, # and exits non-zero when the gate fails. # # This script is shared by every JRay component, so it knows nothing about any # one repo. All repo-specific settings - requirement ID prefixes, source # suffixes, scan roots, register path, thresholds - live in `traceability.toml` # at the component repo root. Run # # scripts/traceability/extract_traces.py --print-example-config # # for the annotated schema. A repo whose config is wrong parses zero # requirements or scans zero files, and the gate refuses to report rather than # printing a misleading 0%. # # Environment (all optional; each overrides the config file): # TRACES_CONFIG path to traceability.toml # TRACES_ROOT repo root (default: nearest dir containing traceability.toml) # MIN_COVERAGE minimum overall coverage percent # ALLOW_ORPHANS 1 to report orphan tags without failing # TRACES_JSON JSON report path # TRACES_MD markdown matrix path # SYSTEM_SPEC SPEC.md defining PR/SR; enables PR/SR orphan checking # PYTHON interpreter (default: python3) # # Threshold policy belongs in traceability.toml, not here and not in the # workflow YAML: a threshold written in two places is a threshold that will # disagree with itself. # # POSIX sh, no bashisms, no jq - the extractor does its own arithmetic and # printing, so CI needs nothing beyond python3. set -eu SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) PYTHON="${PYTHON:-python3}" command -v "$PYTHON" >/dev/null 2>&1 || { echo "FAILED: $PYTHON not found. The traceability gate needs Python 3.9+," >&2 echo " or 3.11+ to read traceability.toml." >&2 exit 2 } set -- --format coverage # Explicit `if` rather than `[ ... ] && ...`, because a trailing false test in # an && list exits under `set -e` in some POSIX shells. if [ -n "${TRACES_CONFIG:-}" ]; then set -- "$@" --config "$TRACES_CONFIG"; fi if [ -n "${TRACES_ROOT:-}" ]; then set -- "$@" --root "$TRACES_ROOT"; fi if [ -n "${MIN_COVERAGE:-}" ]; then set -- "$@" --min-coverage "$MIN_COVERAGE"; fi if [ -n "${TRACES_JSON:-}" ]; then set -- "$@" --json-out "$TRACES_JSON"; fi if [ -n "${TRACES_MD:-}" ]; then set -- "$@" --markdown-out "$TRACES_MD"; fi if [ -n "${SYSTEM_SPEC:-}" ]; then set -- "$@" --system-spec "$SYSTEM_SPEC"; fi if [ "${ALLOW_ORPHANS:-0}" = "1" ]; then set -- "$@" --allow-orphans; fi exec "$PYTHON" "$SCRIPT_DIR/extract_traces.py" "$@"