|
1 | 1 | use anyhow::{Context as _, Result};
|
2 | 2 | use octocrab::Octocrab;
|
3 |
| -use std::collections::HashMap; |
4 | 3 |
|
5 | 4 | mod analyzer;
|
6 | 5 | mod config;
|
| 6 | +mod report_generator; |
7 | 7 |
|
8 |
| -use crate::analyzer::{AnalysisResult, Analyzer}; |
| 8 | +use crate::analyzer::Analyzer; |
9 | 9 | use crate::config::ConfigBuilder;
|
| 10 | +use crate::report_generator::generate_report; |
10 | 11 |
|
11 | 12 | #[tokio::main]
|
12 | 13 | async fn main() -> Result<()> {
|
@@ -142,169 +143,3 @@ async fn find_existing_comment(
|
142 | 143 | // No matching comment found
|
143 | 144 | Ok(None)
|
144 | 145 | }
|
145 |
| - |
146 |
| -/// Generate a detailed report for PR comment |
147 |
| -fn generate_report( |
148 |
| - analysis: &AnalysisResult, |
149 |
| - rules: &[String], |
150 |
| - repository: &str, |
151 |
| - base_branch: &str, |
152 |
| - head_branch: &str, |
153 |
| -) -> String { |
154 |
| - let mut report = String::from("## Clippy Allow Annotation Report\n\n"); |
155 |
| - |
156 |
| - // Add branch information with link to base branch |
157 |
| - report.push_str("Comparing clippy allow annotations between branches:\n"); |
158 |
| - report.push_str(&format!( |
159 |
| - "- **Base Branch**: [{}](https://github.com/{}/tree/{})\n", |
160 |
| - base_branch, repository, base_branch |
161 |
| - )); |
162 |
| - report.push_str(&format!("- **PR Branch**: {}\n\n", head_branch)); |
163 |
| - |
164 |
| - // Summary table by rule |
165 |
| - report.push_str("### Summary by Rule\n\n"); |
166 |
| - report.push_str("| Rule | Base Branch | PR Branch | Change |\n"); |
167 |
| - report.push_str("|------|------------|-----------|--------|\n"); |
168 |
| - |
169 |
| - let mut total_base = 0; |
170 |
| - let mut total_head = 0; |
171 |
| - |
172 |
| - for rule in rules { |
173 |
| - let base_count = *analysis.base_counts.get(rule).unwrap_or(&0); |
174 |
| - let head_count = *analysis.head_counts.get(rule).unwrap_or(&0); |
175 |
| - let change = head_count as isize - base_count as isize; |
176 |
| - |
177 |
| - total_base += base_count; |
178 |
| - total_head += head_count; |
179 |
| - |
180 |
| - // Calculate percentage change |
181 |
| - let percent_change = if base_count > 0 { |
182 |
| - (change as f64 / base_count as f64) * 100.0 |
183 |
| - } else if change > 0 { |
184 |
| - // If base count is 0 and there's an increase, it's an infinite increase |
185 |
| - // but we'll display it as N/A or a large number |
186 |
| - f64::INFINITY |
187 |
| - } else { |
188 |
| - // No change if both are 0 |
189 |
| - 0.0 |
190 |
| - }; |
191 |
| - |
192 |
| - // Format the change string with percentage |
193 |
| - let change_str = if change > 0 { |
194 |
| - if percent_change.is_infinite() { |
195 |
| - format!("⚠️ +{} (N/A)", change) |
196 |
| - } else { |
197 |
| - format!("⚠️ +{} (+{:.1}%)", change, percent_change) |
198 |
| - } |
199 |
| - } else if change < 0 { |
200 |
| - format!("✅ {} ({:.1}%)", change, percent_change) |
201 |
| - } else { |
202 |
| - "No change (0%)".to_string() |
203 |
| - }; |
204 |
| - |
205 |
| - report.push_str(&format!( |
206 |
| - "| `{}` | {} | {} | {} |\n", |
207 |
| - rule, base_count, head_count, change_str |
208 |
| - )); |
209 |
| - } |
210 |
| - |
211 |
| - // Add total row with percentage |
212 |
| - let total_change = total_head as isize - total_base as isize; |
213 |
| - let total_percent_change = if total_base > 0 { |
214 |
| - (total_change as f64 / total_base as f64) * 100.0 |
215 |
| - } else if total_change > 0 { |
216 |
| - f64::INFINITY |
217 |
| - } else { |
218 |
| - 0.0 |
219 |
| - }; |
220 |
| - |
221 |
| - let total_change_str = if total_change > 0 { |
222 |
| - if total_percent_change.is_infinite() { |
223 |
| - format!("⚠️ +{} (N/A)", total_change) |
224 |
| - } else { |
225 |
| - format!("⚠️ +{} (+{:.1}%)", total_change, total_percent_change) |
226 |
| - } |
227 |
| - } else if total_change < 0 { |
228 |
| - format!("✅ {} ({:.1}%)", total_change, total_percent_change) |
229 |
| - } else { |
230 |
| - "No change (0%)".to_string() |
231 |
| - }; |
232 |
| - |
233 |
| - report.push_str(&format!( |
234 |
| - "| **Total** | **{}** | **{}** | **{}** |\n\n", |
235 |
| - total_base, total_head, total_change_str |
236 |
| - )); |
237 |
| - |
238 |
| - // File-level annotation counts with percentage change |
239 |
| - if !analysis.changed_files.is_empty() { |
240 |
| - report.push_str("### Annotation Counts by File\n\n"); |
241 |
| - report.push_str("| File | Base Branch | PR Branch | Change |\n"); |
242 |
| - report.push_str("|------|------------|-----------|--------|\n"); |
243 |
| - |
244 |
| - // Count annotations by file in base branch |
245 |
| - let mut base_file_counts = HashMap::new(); |
246 |
| - for anno in &analysis.base_annotations { |
247 |
| - *base_file_counts.entry(anno.file.clone()).or_insert(0) += 1; |
248 |
| - } |
249 |
| - |
250 |
| - // Count annotations by file in head branch |
251 |
| - let mut head_file_counts = HashMap::new(); |
252 |
| - for anno in &analysis.head_annotations { |
253 |
| - *head_file_counts.entry(anno.file.clone()).or_insert(0) += 1; |
254 |
| - } |
255 |
| - |
256 |
| - // Get a sorted list of all files |
257 |
| - let mut all_files: Vec<String> = analysis.changed_files.iter().cloned().collect(); |
258 |
| - all_files.sort(); |
259 |
| - |
260 |
| - // Generate table rows |
261 |
| - for file in all_files { |
262 |
| - let base_count = *base_file_counts.get(&file).unwrap_or(&0); |
263 |
| - let head_count = *head_file_counts.get(&file).unwrap_or(&0); |
264 |
| - let change = head_count as isize - base_count as isize; |
265 |
| - |
266 |
| - // Skip files with no changes in annotation count |
267 |
| - if change == 0 && base_count == 0 && head_count == 0 { |
268 |
| - continue; |
269 |
| - } |
270 |
| - |
271 |
| - // Calculate percentage change for file |
272 |
| - let percent_change = if base_count > 0 { |
273 |
| - (change as f64 / base_count as f64) * 100.0 |
274 |
| - } else if change > 0 { |
275 |
| - f64::INFINITY |
276 |
| - } else { |
277 |
| - 0.0 |
278 |
| - }; |
279 |
| - |
280 |
| - // Format the change string with percentage for file |
281 |
| - let change_str = if change > 0 { |
282 |
| - if percent_change.is_infinite() { |
283 |
| - format!("⚠️ +{} (N/A)", change) |
284 |
| - } else { |
285 |
| - format!("⚠️ +{} (+{:.1}%)", change, percent_change) |
286 |
| - } |
287 |
| - } else if change < 0 { |
288 |
| - format!("✅ {} ({:.1}%)", change, percent_change) |
289 |
| - } else { |
290 |
| - "No change (0%)".to_string() |
291 |
| - }; |
292 |
| - |
293 |
| - report.push_str(&format!( |
294 |
| - "| `{}` | {} | {} | {} |\n", |
295 |
| - file, base_count, head_count, change_str |
296 |
| - )); |
297 |
| - } |
298 |
| - |
299 |
| - report.push_str("\n"); |
300 |
| - } |
301 |
| - |
302 |
| - // Add explanation |
303 |
| - report.push_str("### About This Report\n\n"); |
304 |
| - report.push_str("This report tracks Clippy allow annotations for specific rules, "); |
305 |
| - report.push_str("showing how they've changed in this PR. "); |
306 |
| - report |
307 |
| - .push_str("Decreasing the number of these annotations generally improves code quality.\n"); |
308 |
| - |
309 |
| - report |
310 |
| -} |
0 commit comments