refactor(traceability): parameterise the extractor for all three components
The tool is moving into the jray-project submodule to be shared by
scene-actor-extraction (C++/Python), jRay (C#) and JRay-public-server
(Rust). Two constants blocked that: LOCAL_TYPES and SOURCE_SUFFIXES were
hardcoded to this repo, so either sibling parsed zero requirements and
scanned zero files. Both, plus the register path, scan roots, system-spec
path, exclude list and CI-executable tier set, are now configuration.
One implementation, parameterised. A second copy for "the other language"
is how two implementations start drifting apart, so there is exactly one -
the same code path now produces:
scene-actor-extraction AR/DP/IR/GR/VR 59 defined 0 tagged 0.0%
jRay JR 46 defined 24 covered 52.2%
JRay-public-server UR/DR 32 defined 23 covered 71.9%
Configuration is traceability.toml at the component repo root, CLI flags,
or both (flags win). Its directory defines the repo root, so the gate works
from any subdirectory. `--print-example-config` emits the annotated schema.
The JSON report echoes the settings it ran with, since a shared tool's
output is otherwise ambiguous about which repo it describes.
The refusal behaviour is kept and sharpened, because parameterising is
exactly what makes it easy to point a repo at the wrong prefixes or the
wrong suffixes. Zero requirements parsed or zero files scanned is still a
hard failure, and the message now names the setting that is wrong rather
than printing a plausible 0%. Config errors exit 2, not 1: a broken config
is not a coverage failure, and conflating them makes CI logs lie about why
the job went red.
Also fixed while adapting to the sibling registers, which are read but not
modified here:
* escaped `\|` inside a markdown cell no longer shifts every later column
(the server's register contains `small-\|M\|`);
* a tag above an attribute-decorated declaration attributes to the
declaration, not to `[HttpGet(...)]` or `#[derive(...)]` - the gap
jRay's register calls out;
* Rust and C# declaration patterns for context extraction;
* the missing-tier warning is suppressed for a register that assigns no
tiers at all, rather than listing every requirement in it.
The workflow is now component-agnostic too: the changed-file check reads
its extension list out of the report the gate just wrote, so the definition
of "source file" lives in one place.
79 tests, still fixture-based, now including the cross-repo cases: the same
parser over JR and UR/DR registers, the same scanner over Rust and C#, and
both misconfigurations failing loudly.
This commit is contained in:
@@ -1,64 +1,62 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Requirement traceability gate. Run locally exactly as CI runs it:
|
||||
# Requirement traceability gate. Run locally exactly as CI runs it, from the
|
||||
# component repo root:
|
||||
#
|
||||
# scripts/traceability/traceability-gate.sh
|
||||
#
|
||||
# Writes traces-report.json and docs/traceability.md, prints the coverage
|
||||
# report, and exits non-zero when the gate fails.
|
||||
# Writes the JSON report and the markdown matrix, prints the coverage report,
|
||||
# and exits non-zero when the gate fails.
|
||||
#
|
||||
# Environment:
|
||||
# MIN_COVERAGE minimum overall coverage percent (default 0 - see below)
|
||||
# ALLOW_ORPHANS set to 1 to report orphan tags without failing
|
||||
# TRACES_JSON JSON report path (default traces-report.json)
|
||||
# TRACES_MD markdown matrix path (default docs/traceability.md)
|
||||
# SYSTEM_SPEC optional path to the umbrella SPEC.md, which defines the
|
||||
# PR/SR IDs; when given, PR/SR orphans are reported too. That
|
||||
# file lives in the parent project, not in this repo, so CI
|
||||
# normally leaves it unset.
|
||||
# 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
|
||||
#
|
||||
# Threshold policy lives here and nowhere else. It is deliberately NOT
|
||||
# duplicated into the workflow YAML: a threshold written in two places is a
|
||||
# threshold that will disagree with itself.
|
||||
# scripts/traceability/extract_traces.py --print-example-config
|
||||
#
|
||||
# MIN_COVERAGE defaults to 0 because almost nothing is tagged yet - tags are
|
||||
# added as the pipeline is built, so a low number today is accurate rather than
|
||||
# alarming. A zero threshold does NOT mean the gate cannot fail: orphan tags,
|
||||
# a >100% ratio, a register that parses to nothing, and an empty source scan
|
||||
# are all hard failures from day one. Raise MIN_COVERAGE as tags land; treat
|
||||
# every raise as a ratchet, never a reset.
|
||||
# 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.
|
||||
# printing, so CI needs nothing beyond python3.
|
||||
|
||||
set -eu
|
||||
|
||||
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
REPO_ROOT=$(CDPATH= cd -- "$SCRIPT_DIR/../.." && pwd)
|
||||
|
||||
MIN_COVERAGE="${MIN_COVERAGE:-0}"
|
||||
TRACES_JSON="${TRACES_JSON:-$REPO_ROOT/traces-report.json}"
|
||||
TRACES_MD="${TRACES_MD:-$REPO_ROOT/docs/traceability.md}"
|
||||
|
||||
PYTHON="${PYTHON:-python3}"
|
||||
command -v "$PYTHON" >/dev/null 2>&1 || {
|
||||
echo "FAILED: $PYTHON not found. The traceability gate needs Python 3.9+" >&2
|
||||
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 -- \
|
||||
--root "$REPO_ROOT" \
|
||||
--format coverage \
|
||||
--json-out "$TRACES_JSON" \
|
||||
--markdown-out "$TRACES_MD" \
|
||||
--min-coverage "$MIN_COVERAGE"
|
||||
set -- --format coverage
|
||||
|
||||
if [ "${ALLOW_ORPHANS:-0}" = "1" ]; then
|
||||
set -- "$@" --allow-orphans
|
||||
fi
|
||||
|
||||
if [ -n "${SYSTEM_SPEC:-}" ]; then
|
||||
set -- "$@" --system-spec "$SYSTEM_SPEC"
|
||||
fi
|
||||
# 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" "$@"
|
||||
|
||||
Reference in New Issue
Block a user