#!/usr/bin/env python3 """ issue_check.py — validate issues against the canonical format. Offline. The same check the sync layer runs before it pushes anything, available on its own so a local-only issue can be held to the format without a tracker being involved. Errors mean malformed; warnings mean it deviates from its type's template or its graph looks suspect. issue_check.py every issue in the store issue_check.py wire-sqlc one issue issue_check.py --quiet exit code only (0 clean, 1 errors) Format reference: ../references/format.md """ import argparse import os import sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import issue # noqa: E402 def main(): ap = argparse.ArgumentParser(description="Validate local issues (offline)") ap.add_argument("ids", nargs="*", help="ids to check (default: all)") ap.add_argument("--quiet", action="store_true", help="exit code only") ap.add_argument("--strict", action="store_true", help="treat warnings as errors") ap.add_argument("--out", default=issue.ISSUE_ROOT, help="store root (default: /tmp/issues)") args = ap.parse_args() problem = issue.store_error(args.out) if problem: sys.exit("issue_check.py: %s" % problem) issues = issue.load_all(args.out) ids = args.ids or sorted(issues) for i in ids: if i not in issues: sys.exit("issue_check.py: no issue %r in %s" % (i, args.out)) known = set(issues) bad = 0 for i in ids: err, warn = issue.validate(issues[i], known_ids=known) if args.strict: err, warn = err + warn, [] if err: bad += 1 if args.quiet: continue if not err and not warn: print("ok %s" % i) continue for e in err: print("ERROR %s: %s" % (i, e)) for w in warn: print("warn %s: %s" % (i, w)) for c in issue.find_cycles(issue.graph(issues)): bad += 1 if not args.quiet: print("ERROR cycle: %s" % " -> ".join(c)) if not args.quiet: print("%d issue(s) checked, %d with errors" % (len(ids), bad)) return 1 if bad else 0 if __name__ == "__main__": sys.exit(main())