cargo_ferris_wheel/reports/
github.rs1use std::fmt::Write;
4
5use super::ReportGenerator;
6use crate::detector::CycleDetector;
7use crate::error::FerrisWheelError;
8
9pub struct GitHubReportGenerator;
10
11impl Default for GitHubReportGenerator {
12 fn default() -> Self {
13 Self::new()
14 }
15}
16
17impl GitHubReportGenerator {
18 pub fn new() -> Self {
19 Self
20 }
21}
22
23impl ReportGenerator for GitHubReportGenerator {
24 fn generate_report(&self, detector: &CycleDetector) -> Result<String, FerrisWheelError> {
25 let mut output = String::new();
26
27 if !detector.has_cycles() {
28 writeln!(
29 output,
30 "::notice title=Dependency Check::No workspace dependency cycles detected! ✅"
31 )?;
32 return Ok(output);
33 }
34
35 writeln!(
36 output,
37 "::error title=Dependency Cycles::Found {} workspace dependency cycle{}",
38 detector.cycle_count(),
39 if detector.cycle_count() == 1 { "" } else { "s" }
40 )?;
41
42 let mut sorted_cycles: Vec<_> = detector.cycles().iter().collect();
43 sorted_cycles.sort_by(|a, b| {
44 let a_names = a.workspace_names();
45 let b_names = b.workspace_names();
46 let a_first = a_names.first().map(|s| s.as_str()).unwrap_or("");
47 let b_first = b_names.first().map(|s| s.as_str()).unwrap_or("");
48 a_first.cmp(b_first)
49 });
50
51 for (i, cycle) in sorted_cycles.iter().enumerate() {
52 let mut workspace_names = cycle.workspace_names().to_vec();
53 workspace_names.sort();
54 writeln!(
55 output,
56 "::warning title=Cycle {}::Workspaces: {}",
57 i + 1,
58 workspace_names.join(" → ")
59 )?;
60
61 let mut sorted_edges = cycle.edges().to_vec();
62 sorted_edges.sort_by(|a, b| match a.from_crate().cmp(b.from_crate()) {
63 std::cmp::Ordering::Equal => a.to_crate().cmp(b.to_crate()),
64 other => other,
65 });
66
67 for edge in sorted_edges {
68 writeln!(
69 output,
70 "::notice:: {} → {} ({})",
71 edge.from_crate(),
72 edge.to_crate(),
73 edge.dependency_type()
74 )?;
75 }
76 }
77
78 writeln!(
79 output,
80 "::notice title=Recommendation::To break these cycles, consider extracting shared \
81 code into a separate workspace that both can depend on."
82 )?;
83
84 Ok(output)
85 }
86}