use std::path::Path;
use clap::Parser;
use crate::contribute::pipeline::run_contribute;
use crate::contribute::{ContributeFilter, StageStatus};
#[derive(Debug, Parser)]
pub struct Args {
#[arg(long, conflicts_with = "all")]
pub op: Option<String>,
#[arg(long)]
pub all: bool,
}
pub fn run(args: Args) -> Result<(), Box<dyn std::error::Error>> {
let filter = if args.all {
ContributeFilter::All
} else if let Some(op) = args.op {
ContributeFilter::Op(Box::leak(op.into_boxed_str()))
} else {
return Err("Fix: specify --op <id> or --all.".into());
};
let vyre_src_root = Path::new(".");
let reports = run_contribute(filter, vyre_src_root);
let json = serde_json::to_string_pretty(&reports)
.map_err(|err| format!("Fix: failed to serialize report: {err}"))?;
println!("{json}");
let total_wall_ms: u64 = reports.iter().map(|r| r.total_duration_ms).sum();
let any_fail = reports
.iter()
.any(|r| r.overall_status == StageStatus::Fail);
let any_skip = reports
.iter()
.any(|r| r.overall_status == StageStatus::Skip);
for report in &reports {
eprintln!("op: {} | status: {:?}", report.op_id, report.overall_status);
for stage in &report.stages {
eprintln!(
" [{:12}] {:4}ms | {:?} | {} finding(s)",
stage.stage_name,
stage.duration_ms,
stage.status,
stage.findings.len()
);
}
}
eprintln!("Total wall time: {total_wall_ms}ms");
if any_fail {
return Err("Fix: contribution feedback loop reported one or more failed stages.".into());
}
let _ = any_skip;
Ok(())
}