CLI API Reference
Command line interface for reqtrace.
main(args=None)
CLI Entrypoint for reqtrace.
Source code in reqtrace/cli.py
def main(args: Optional[List[str]] = None):
"""CLI Entrypoint for reqtrace."""
# @trace-start: REQ-CLI
parser = argparse.ArgumentParser(description="Reqtrace: A GitOps-friendly requirements tracer.")
parser.add_argument(
"--reqs", default=["reqs/"], nargs="+", help="Path(s) to .rqtr requirement files or folder containing them. (Default: reqs/)"
)
parser.add_argument(
"--src",
default=["src/"],
nargs="+",
help="Path(s) to source code directories or files to scan. (Default: src/)",
)
parser.add_argument(
"-v",
"--verbose",
action="store_true",
help="Enable verbose (DEBUG) logging output.",
)
parser.add_argument(
"--html",
metavar="DIR",
help="Generate a structured multi-page HTML report in the specified directory.",
)
parsed_args = parser.parse_args(args)
logging.basicConfig(
level=logging.DEBUG if parsed_args.verbose else logging.INFO,
format="%(message)s",
)
try:
# 1. Load the requirements
log.info("Loading requirements from %s...", parsed_args.reqs)
all_req_data = _load_requirements(parsed_args.reqs)
req_index = parse_requirements(all_req_data)
# 2. Scan the source code
log.info("Scanning source code at %s...", parsed_args.src)
all_traces, file_lines = _load_source_code(parsed_args.src)
# 3. Calculate Coverage
log.info("Calculating traceability matrix...")
report = calculate_coverage(req_index, all_traces, file_lines)
# 4. Generate HTML Report (if requested)
if parsed_args.html:
enrich_metadata(req_index, report)
output_dir = Path(parsed_args.html)
generate_html(req_index, report, output_dir)
log.info("Multi-page HTML report generated at: %s", output_dir.absolute())
# 5. Print Summary to Console (plain output)
print("\n=== REQTRACE COVERAGE REPORT ===")
print(f"Total Requirements: {report.total_requirements}")
print(f"Implemented (>=100%): {report.implemented_requirements}")
print(f"Partial (<100%): {report.partial_requirements}")
print(f"Missing (0%): {report.missing_requirements}\n")
if report.source_stats:
print("--- SOURCE CODE COVERAGE ---")
print(f"Total Source Files: {report.source_stats.total_files}")
if report.source_stats.disabled_files > 0:
print(f"Disabled Files: {report.source_stats.disabled_files}")
print(f"Total Source Lines: {report.source_stats.total_lines}")
print(f"Mapped Lines: {report.source_stats.mapped_lines}")
print(f"Unmapped Lines: {report.source_stats.unmapped_lines}\n")
print("--- DETAILS ---")
for req_id, cov in report.coverage_details.items():
status = "✅ IMPLEMENTED" if cov.is_implemented else ("⚠️ PARTIAL" if cov.total_percentage > 0 else "❌ MISSING")
print(f"[{status}] {req_id} - Coverage: {cov.total_percentage}%")
if report.unmatched_traces:
print("\n--- WARNING: UNMATCHED TRACE TAGS ---")
print("The following trace tags refer to unknown requirement IDs.")
for trace in report.unmatched_traces:
pct_str = f"({trace.percentage}%)" if trace.percentage else ""
print(f"Unknown ID: '{trace.req_id}' {pct_str} at {trace.file_path}:{trace.line_start}-{trace.line_end}")
# Exit with error code if coverage is not 100%
# (This fails the CI pipeline intentionally if requirements aren't met!)
if report.missing_requirements > 0 or report.partial_requirements > 0:
sys.exit(1)
sys.exit(0)
# @trace-end: REQ-CLI
except Exception as e: # pylint: disable=broad-exception-caught
log.error("Error running reqtrace: %s", e)
sys.exit(2)