11from __future__ import annotations
22
33import argparse
4+ import json
45from pathlib import Path
56import sys
67
2021from .trends import build_trend_report
2122
2223
24+ def _print_json (data : dict [str , object ]) -> None :
25+ print (json .dumps (data , indent = 2 , sort_keys = True , ensure_ascii = False ))
26+
27+
28+ def _add_json_flag (parser : argparse .ArgumentParser ) -> None :
29+ parser .add_argument ("--json" , action = "store_true" , help = "print machine-readable JSON output" )
30+
31+
2332def _cmd_cluster (args : argparse .Namespace ) -> int :
2433 payload = build_clusters (args .pack )
2534 write_json (args .output , payload )
35+ if args .json :
36+ response = dict (payload )
37+ response ["output" ] = str (args .output )
38+ _print_json (response )
39+ return 0
2640 print (f"Wrote clusters to { args .output } " )
2741 return 0
2842
2943
3044def _cmd_summarize (args : argparse .Namespace ) -> int :
3145 payload = load_clusters (args .path )
46+ if args .json :
47+ _print_json (payload )
48+ return 0
3249 print (summarize_clusters (payload ))
3350 return 0
3451
3552
3653def _cmd_markdown (args : argparse .Namespace ) -> int :
3754 payload = load_clusters (args .path )
3855 Path (args .output ).write_text (markdown_report (payload ), encoding = "utf-8" )
56+ if args .json :
57+ _print_json (
58+ {
59+ "output" : str (args .output ),
60+ "cluster_count" : int (payload .get ("cluster_count" , 0 )),
61+ "case_count" : int (payload .get ("case_count" , 0 )),
62+ "format" : "markdown" ,
63+ }
64+ )
65+ return 0
3966 print (f"Wrote report to { args .output } " )
4067 return 0
4168
4269
4370def _cmd_compare (args : argparse .Namespace ) -> int :
4471 payload = compare_cluster_files (args .baseline , args .candidate )
4572 write_json (args .output , payload )
73+ if args .json :
74+ response = dict (payload )
75+ response ["output" ] = str (args .output )
76+ _print_json (response )
77+ return 0
4678 print (f"Wrote compare report to { args .output } " )
4779 return 0
4880
4981
5082def _cmd_compare_summary (args : argparse .Namespace ) -> int :
5183 payload = load_clusters (args .path )
84+ if args .json :
85+ _print_json (payload )
86+ return 0
5287 print (summarize_compare (payload ))
5388 return 0
5489
5590
5691def _cmd_compare_markdown (args : argparse .Namespace ) -> int :
5792 payload = load_clusters (args .path )
5893 Path (args .output ).write_text (markdown_compare_report (payload ), encoding = "utf-8" )
94+ if args .json :
95+ _print_json (
96+ {
97+ "output" : str (args .output ),
98+ "cluster_count" : int (payload .get ("cluster_count" , 0 )),
99+ "summary" : dict (payload .get ("summary" , {})),
100+ "format" : "markdown" ,
101+ }
102+ )
103+ return 0
59104 print (f"Wrote compare markdown to { args .output } " )
60105 return 0
61106
62107
63108def _cmd_issue_drafts (args : argparse .Namespace ) -> int :
64109 statuses = set (args .status ) if args .status else None
65110 manifest = generate_issue_drafts (args .path , args .output_dir , include_statuses = statuses , rules_path = args .rules )
111+ if args .json :
112+ response = dict (manifest )
113+ response ["output_dir" ] = str (args .output_dir )
114+ _print_json (response )
115+ return 0
66116 print (f"Wrote { manifest ['draft_count' ]} issue drafts to { args .output_dir } " )
67117 return 0
68118
69119
70120def _cmd_issue_bundle (args : argparse .Namespace ) -> int :
71121 bundle = build_issue_bundle (args .issues_path , args .output_dir )
122+ if args .json :
123+ response = dict (bundle )
124+ response ["output_dir" ] = str (args .output_dir )
125+ _print_json (response )
126+ return 0
72127 print (f"Wrote issue bundle with { bundle ['draft_count' ]} drafts to { args .output_dir } " )
73128 return 0
74129
75130
76131def _cmd_issue_bundle_summary (args : argparse .Namespace ) -> int :
77132 bundle = load_issue_manifest (args .path )
133+ if args .json :
134+ _print_json (bundle )
135+ return 0
78136 draft_count = int (bundle .get ("draft_count" , 0 ))
79137 print (f"Drafts: { draft_count } " )
80138 print ("By priority:" )
@@ -89,19 +147,37 @@ def _cmd_issue_bundle_summary(args: argparse.Namespace) -> int:
89147def _cmd_trend (args : argparse .Namespace ) -> int :
90148 payload = build_trend_report (args .paths )
91149 write_json (args .output , payload )
150+ if args .json :
151+ response = dict (payload )
152+ response ["output" ] = str (args .output )
153+ _print_json (response )
154+ return 0
92155 print (f"Wrote trend report to { args .output } " )
93156 return 0
94157
95158
96159def _cmd_trend_summary (args : argparse .Namespace ) -> int :
97160 payload = load_clusters (args .path )
161+ if args .json :
162+ _print_json (payload )
163+ return 0
98164 print (summarize_trends (payload ))
99165 return 0
100166
101167
102168def _cmd_trend_markdown (args : argparse .Namespace ) -> int :
103169 payload = load_clusters (args .path )
104170 Path (args .output ).write_text (markdown_trend_report (payload ), encoding = "utf-8" )
171+ if args .json :
172+ _print_json (
173+ {
174+ "output" : str (args .output ),
175+ "snapshot_count" : int (payload .get ("snapshot_count" , 0 )),
176+ "signature_count" : int (payload .get ("signature_count" , 0 )),
177+ "format" : "markdown" ,
178+ }
179+ )
180+ return 0
105181 print (f"Wrote trend markdown to { args .output } " )
106182 return 0
107183
@@ -113,30 +189,36 @@ def build_parser() -> argparse.ArgumentParser:
113189 cluster = subparsers .add_parser ("cluster" , help = "cluster failures from a TracePack pack" )
114190 cluster .add_argument ("pack" )
115191 cluster .add_argument ("output" )
192+ _add_json_flag (cluster )
116193 cluster .set_defaults (func = _cmd_cluster )
117194
118195 summarize = subparsers .add_parser ("summarize" , help = "summarize a clusters json file" )
119196 summarize .add_argument ("path" )
197+ _add_json_flag (summarize )
120198 summarize .set_defaults (func = _cmd_summarize )
121199
122200 markdown = subparsers .add_parser ("markdown" , help = "render a markdown report from clusters json" )
123201 markdown .add_argument ("path" )
124202 markdown .add_argument ("output" )
203+ _add_json_flag (markdown )
125204 markdown .set_defaults (func = _cmd_markdown )
126205
127206 compare = subparsers .add_parser ("compare" , help = "compare two cluster json files" )
128207 compare .add_argument ("baseline" )
129208 compare .add_argument ("candidate" )
130209 compare .add_argument ("output" )
210+ _add_json_flag (compare )
131211 compare .set_defaults (func = _cmd_compare )
132212
133213 compare_summary = subparsers .add_parser ("compare-summary" , help = "summarize a compare json file" )
134214 compare_summary .add_argument ("path" )
215+ _add_json_flag (compare_summary )
135216 compare_summary .set_defaults (func = _cmd_compare_summary )
136217
137218 compare_markdown = subparsers .add_parser ("compare-markdown" , help = "render markdown from a compare json file" )
138219 compare_markdown .add_argument ("path" )
139220 compare_markdown .add_argument ("output" )
221+ _add_json_flag (compare_markdown )
140222 compare_markdown .set_defaults (func = _cmd_compare_markdown )
141223
142224 issue_drafts = subparsers .add_parser ("issue-drafts" , help = "generate issue-ready markdown drafts from a compare json file" )
@@ -149,29 +231,35 @@ def build_parser() -> argparse.ArgumentParser:
149231 choices = ["new" , "resolved" , "growing" , "shrinking" , "unchanged" ],
150232 help = "limit generated drafts to selected statuses; can be passed multiple times" ,
151233 )
234+ _add_json_flag (issue_drafts )
152235 issue_drafts .set_defaults (func = _cmd_issue_drafts )
153236
154237 issue_bundle = subparsers .add_parser ("issue-bundle" , help = "group issue drafts into a batch triage bundle" )
155238 issue_bundle .add_argument ("issues_path" )
156239 issue_bundle .add_argument ("output_dir" )
240+ _add_json_flag (issue_bundle )
157241 issue_bundle .set_defaults (func = _cmd_issue_bundle )
158242
159243 issue_bundle_summary = subparsers .add_parser ("issue-bundle-summary" , help = "summarize an issue bundle json file" )
160244 issue_bundle_summary .add_argument ("path" )
245+ _add_json_flag (issue_bundle_summary )
161246 issue_bundle_summary .set_defaults (func = _cmd_issue_bundle_summary )
162247
163248 trend = subparsers .add_parser ("trend" , help = "build a trend report from multiple cluster snapshots" )
164249 trend .add_argument ("output" )
165250 trend .add_argument ("paths" , nargs = "+" )
251+ _add_json_flag (trend )
166252 trend .set_defaults (func = _cmd_trend )
167253
168254 trend_summary = subparsers .add_parser ("trend-summary" , help = "summarize a trend json file" )
169255 trend_summary .add_argument ("path" )
256+ _add_json_flag (trend_summary )
170257 trend_summary .set_defaults (func = _cmd_trend_summary )
171258
172259 trend_markdown = subparsers .add_parser ("trend-markdown" , help = "render markdown from a trend json file" )
173260 trend_markdown .add_argument ("path" )
174261 trend_markdown .add_argument ("output" )
262+ _add_json_flag (trend_markdown )
175263 trend_markdown .set_defaults (func = _cmd_trend_markdown )
176264
177265 return parser
0 commit comments