1919
2020from pombast .config ._settings import PombastConfig , parse_repo_spec
2121from pombast .core ._filter import ComponentFilter
22+ from pombast .core ._smelt_json import load_smelt_components
2223from pombast .maven ._bom import load_bom
2324from pombast .maven ._rules import RulesXML
2425from pombast .status ._drift import drift_text
8283 default = None ,
8384 help = "Path to vetting timestamps file (G:A <space> YYYYMMDDHHmmss per line)." ,
8485)
86+ @click .option (
87+ "--smelt" ,
88+ "smelt_path" ,
89+ type = click .Path (exists = True , path_type = Path ),
90+ default = None ,
91+ help = "Path to smelt.json to overlay binary/source compatibility columns." ,
92+ )
8593@click .option (
8694 "--no-timestamps" ,
8795 is_flag = True ,
@@ -142,6 +150,7 @@ def status_cmd(
142150 projects : str | None ,
143151 badges : str | None ,
144152 timestamps : str | None ,
153+ smelt_path : Path | None ,
145154 no_timestamps : bool ,
146155 nexus_base : str | None ,
147156 html_path : Path | None ,
@@ -167,6 +176,7 @@ def status_cmd(
167176 effective_projects = projects or (str (sc .projects ) if sc .projects else None )
168177 effective_badges = badges or (str (sc .badges ) if sc .badges else None )
169178 effective_timestamps = timestamps or (str (sc .timestamps ) if sc .timestamps else None )
179+ effective_smelt = smelt_path or sc .smelt
170180 effective_html = html_path or sc .html
171181 effective_header = header or sc .header
172182 effective_footer = footer or sc .footer
@@ -200,6 +210,14 @@ def status_cmd(
200210 load_timestamps_file (effective_timestamps ) if effective_timestamps else {}
201211 )
202212
213+ smelt_components : dict [str , dict ] | None = None
214+ if effective_smelt :
215+ smelt_components = load_smelt_components (effective_smelt )
216+ console .print (
217+ f"Loaded smelt data: [bold]{ len (smelt_components )} [/bold] components "
218+ f"([cyan]{ effective_smelt } [/cyan])"
219+ )
220+
203221 cf = ComponentFilter (includes = list (include ), excludes = list (exclude ))
204222 total = len (cf .filter (bom_data .components ))
205223
@@ -231,7 +249,7 @@ def status_cmd(
231249 description = f"{ entry .component .group } :{ entry .component .name } " ,
232250 )
233251
234- _print_status_table (entries )
252+ _print_status_table (entries , smelt = smelt_components )
235253
236254 cuts = sum (1 for e in entries if e .action == "Cut" )
237255 bumps = sum (1 for e in entries if e .action == "Bump" )
@@ -251,17 +269,49 @@ def status_cmd(
251269 nexus_base = nexus_base or "" ,
252270 header_html = header_html ,
253271 footer_html = footer_html ,
272+ smelt = smelt_components ,
254273 )
255274 )
256275 console .print (f"HTML report written to: [cyan]{ effective_html } [/cyan]" )
257276
258277
259- def _print_status_table (entries : list [StatusEntry ]) -> None :
278+ def _smelt_cells (comp_data : dict | None , bom_version : str ) -> tuple [str , str ]:
279+ """Return (binary_cell, source_cell) Rich markup for a smelt component entry."""
280+ if comp_data is None :
281+ return "[dim]—[/dim]" , "[dim]—[/dim]"
282+
283+ mismatch = comp_data .get ("version" ) not in (None , bom_version )
284+ suffix = "[yellow]*[/yellow]" if mismatch else ""
285+ skipped = comp_data .get ("skipped_reason" )
286+
287+ def _render (status : str | None ) -> str :
288+ if status == "pass" :
289+ return f"[green]pass[/green]{ suffix } "
290+ if status in ("fail" , "error" ):
291+ return f"[red]{ status } [/red]{ suffix } "
292+ if status == "skipped" :
293+ return f"[dim]skip[/dim]{ suffix } "
294+ if status is None and skipped == "prior success" :
295+ return f"[green]prior[/green]{ suffix } "
296+ if status is None and skipped :
297+ return f"[dim]skip[/dim]{ suffix } "
298+ return f"[dim]—[/dim]{ suffix } "
299+
300+ return _render (comp_data .get ("binary_test" )), _render (comp_data .get ("source_build" ))
301+
302+
303+ def _print_status_table (
304+ entries : list [StatusEntry ],
305+ smelt : dict [str , dict ] | None = None ,
306+ ) -> None :
260307 table = Table (title = "BOM Status" , show_lines = False )
261308 table .add_column ("Component" , style = "cyan" , no_wrap = True )
262309 table .add_column ("Release" , justify = "right" )
263310 table .add_column ("Drift" , justify = "right" )
264311 table .add_column ("Action" , justify = "left" )
312+ if smelt is not None :
313+ table .add_column ("Binary" , justify = "center" )
314+ table .add_column ("Source" , justify = "center" )
265315
266316 for e in entries :
267317 latest = e .latest_version or e .bom_version
@@ -281,11 +331,23 @@ def _print_status_table(entries: list[StatusEntry]) -> None:
281331 "Bump" : "[yellow]Bump[/yellow]" ,
282332 "None" : "[dim]—[/dim]" ,
283333 }[e .action ]
284- table . add_row (
334+ row : list [ str ] = [
285335 f"{ e .component .group } :{ e .component .name } " ,
286336 release_str ,
287337 drift_cell ,
288338 action_str ,
289- )
339+ ]
340+ if smelt is not None :
341+ ga = f"{ e .component .group } :{ e .component .name } "
342+ binary_cell , source_cell = _smelt_cells (smelt .get (ga ), e .bom_version )
343+ row .extend ([binary_cell , source_cell ])
344+ table .add_row (* row )
290345
291346 console .print (table )
347+
348+ if smelt is not None and any (
349+ smelt .get (f"{ e .component .group } :{ e .component .name } " , {}).get ("version" ) not in
350+ (None , e .bom_version )
351+ for e in entries
352+ ):
353+ console .print ("[dim][yellow]*[/yellow] smelt result is from a different version[/dim]" )
0 commit comments