1use anyhow::Result;
2use apm_core::config::{CompletionStrategy, Config};
3use std::collections::HashSet;
4use std::path::Path;
5use crate::ctx::CmdContext;
6
7pub fn run(root: &Path, fix: bool, no_aggressive: bool) -> Result<()> {
8 let ctx = CmdContext::load(root, no_aggressive)?;
9
10 let merged = apm_core::git::merged_into_main(root, &ctx.config.project.default_branch).unwrap_or_default();
11 let merged_set: HashSet<String> = merged.into_iter().collect();
12
13 let issues = apm_core::verify::verify_tickets(root, &ctx.config, &ctx.tickets, &merged_set);
14
15 for state in &ctx.config.workflow.states {
17 for tr in &state.transitions {
18 let label = match &tr.completion {
19 CompletionStrategy::Pr => "pr",
20 CompletionStrategy::Merge => "merge",
21 CompletionStrategy::Pull => "pull",
22 CompletionStrategy::PrOrEpicMerge => "pr_or_epic_merge",
23 CompletionStrategy::None => continue,
24 };
25 println!("completion: {} → {} = {label}", state.id, tr.to);
26 }
27 }
28
29 if ctx.config.logging.enabled {
30 let log_path = apm_core::logger::resolve_log_path(
31 &ctx.config.project.name,
32 ctx.config.logging.file.as_deref(),
33 );
34 println!("logging: {}", log_path.display());
35 }
36
37 if issues.is_empty() {
38 println!("verify: no issues found");
39 return Ok(());
40 }
41
42 for issue in &issues {
43 println!("{issue}");
44 }
45
46 if fix {
47 let merged_refs: HashSet<&str> = merged_set.iter().map(|s| s.as_str()).collect();
48 apply_fixes(root, &ctx.config, &ctx.tickets, &merged_refs)?;
49 }
50
51 std::process::exit(1);
52}
53
54fn apply_fixes(
55 root: &Path,
56 config: &Config,
57 tickets: &[apm_core::ticket::Ticket],
58 merged_set: &HashSet<&str>,
59) -> Result<()> {
60 for t in tickets {
61 let fm = &t.frontmatter;
62 let Some(branch) = &fm.branch else { continue };
63 if (fm.state == "in_progress" || fm.state == "implemented")
64 && merged_set.contains(branch.as_str())
65 {
66 let id = fm.id.clone();
67 let old_state = fm.state.clone();
68 match apm_core::ticket::close(root, config, &id, None, "verify --fix", false) {
69 Ok(msgs) => {
70 for msg in &msgs {
71 println!("{msg}");
72 }
73 println!(" fixed {id}: {old_state} → closed");
74 }
75 Err(e) => eprintln!(" warning: could not fix {id}: {e:#}"),
76 }
77 }
78 }
79 Ok(())
80}