1use crate::git::git_interop::{
2 create_consolidated_pending_read_branch, get_commit_details, get_commits_with_notes,
3 get_notes_for_commit,
4};
5use crate::serialization::deserialize;
6use anyhow::Result;
7use std::collections::HashSet;
8
9#[derive(Debug)]
11pub struct PendingStatus {
12 pub commit_count: usize,
14
15 pub measurement_count: usize,
17
18 pub measurement_names: HashSet<String>,
20
21 pub per_commit: Option<Vec<CommitMeasurements>>,
23}
24
25#[derive(Debug)]
27pub struct CommitMeasurements {
28 pub commit: String,
30
31 pub title: String,
33
34 pub measurement_names: Vec<String>,
36
37 pub count: usize,
39}
40
41pub fn show_status(detailed: bool) -> Result<()> {
43 let status = gather_pending_status(detailed)?;
45
46 display_status(&status, detailed)?;
48
49 Ok(())
50}
51
52pub fn gather_pending_status(detailed: bool) -> Result<PendingStatus> {
54 let pending_guard = create_consolidated_pending_read_branch()?;
58
59 let pending_ref = pending_guard.ref_name();
61
62 let pending_commits = get_commits_with_notes(pending_ref)?;
65
66 let mut commit_count = 0;
67 let mut measurement_count = 0;
68 let mut all_measurement_names = HashSet::new();
69 let mut per_commit = if detailed { Some(Vec::new()) } else { None };
70
71 for commit_sha in &pending_commits {
72 let note_lines = get_notes_for_commit(pending_ref, commit_sha)?;
73 if note_lines.is_empty() {
74 continue;
75 }
76
77 let note_text = note_lines.join("\n");
79 let measurements = deserialize(¬e_text);
80
81 if measurements.is_empty() {
82 continue;
83 }
84
85 commit_count += 1;
86 measurement_count += measurements.len();
87
88 let measurement_names: Vec<String> = measurements.iter().map(|m| m.name.clone()).collect();
90
91 for name in &measurement_names {
92 all_measurement_names.insert(name.clone());
93 }
94
95 if let Some(ref mut per_commit_vec) = per_commit {
97 let commit_details = get_commit_details(std::slice::from_ref(commit_sha))?;
99 if let Some(commit_info) = commit_details.first() {
100 per_commit_vec.push(CommitMeasurements {
101 commit: commit_sha.clone(),
102 title: commit_info.title.clone(),
103 measurement_names: measurement_names.clone(),
104 count: measurements.len(),
105 });
106 }
107 }
108 }
109
110 Ok(PendingStatus {
111 commit_count,
112 measurement_count,
113 measurement_names: all_measurement_names,
114 per_commit,
115 })
116}
117
118fn display_status(status: &PendingStatus, detailed: bool) -> Result<()> {
120 if status.commit_count == 0 {
121 println!("No pending measurements.");
122 println!("(use \"git perf add\" or \"git perf measure\" to add measurements)");
123 return Ok(());
124 }
125
126 println!("Pending measurements:");
127 let commit_word = if status.commit_count == 1 {
128 "commit"
129 } else {
130 "commits"
131 };
132 println!(
133 " {} {} with measurements",
134 status.commit_count, commit_word
135 );
136 let measurement_word = if status.measurement_names.len() == 1 {
137 "measurement"
138 } else {
139 "measurements"
140 };
141 println!(
142 " {} unique {}",
143 status.measurement_names.len(),
144 measurement_word
145 );
146 println!();
147
148 if !status.measurement_names.is_empty() {
149 println!("Measurement names:");
150 let mut sorted_names: Vec<_> = status.measurement_names.iter().collect();
151 sorted_names.sort();
152 for name in sorted_names {
153 println!(" - {}", name);
154 }
155 println!();
156 }
157
158 if detailed {
159 if let Some(ref per_commit) = status.per_commit {
160 println!("Per-commit breakdown:");
161 for commit_info in per_commit {
162 let short_sha = if commit_info.commit.len() >= 12 {
163 &commit_info.commit[..12]
164 } else {
165 &commit_info.commit
166 };
167 let meas_word = if commit_info.count == 1 {
168 "measurement"
169 } else {
170 "measurements"
171 };
172 println!(
173 " {} ({} {}) - {}",
174 short_sha, commit_info.count, meas_word, commit_info.title
175 );
176 for name in &commit_info.measurement_names {
177 println!(" - {}", name);
178 }
179 }
180 println!();
181 }
182 }
183
184 println!("(use \"git perf reset\" to discard pending measurements)");
185 println!("(use \"git perf push\" to publish measurements)");
186
187 Ok(())
188}