Skip to content

Commit 826d5b9

Browse files
committed
WIP: use Cargo.toml to get crate name
1 parent 5f2c19b commit 826d5b9

File tree

3 files changed

+144
-23
lines changed

3 files changed

+144
-23
lines changed

.github/actions/clippy-annotation-reporter/Cargo.lock

Lines changed: 82 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/actions/clippy-annotation-reporter/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ env_logger = "0.10"
1616
# Octocrab has a defined MSRV < 1.78 and depends on url 2.5.4 which also has a defined MSRV < 1.78 but url has a dependency on `idna` has a MSRV of 1.81. Not sure what is going on here.
1717
url = "=2.5.2"
1818
tempfile = "3.20.0"
19+
toml = "0.8.22"
1920

2021
[dev-dependencies]
2122
mockall = "0.11"

.github/actions/clippy-annotation-reporter/src/analyzer.rs

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ use log::{debug, info, warn};
1111
use octocrab::Octocrab;
1212
use regex::Regex;
1313
use std::collections::{HashMap, HashSet};
14+
use std::fs;
15+
use std::path::{Path, PathBuf};
1416
use std::process::Command;
1517
use std::rc::Rc;
18+
use toml::Value;
1619

1720
/// Represents a clippy annotation in code
1821
#[derive(Debug, Clone)]
@@ -247,39 +250,74 @@ fn count_annotations_by_rule(annotations: &[ClippyAnnotation]) -> HashMap<Rc<Str
247250
counts
248251
}
249252

250-
/// Get crate information for a given file path
251-
// TODO: EK - is this the right way to determine crate names?
253+
/// Get crate information for a given file path by finding the closest Cargo.toml
252254
fn get_crate_for_file(file_path: &str) -> String {
253-
// Simple heuristic: use the first directory as the crate name
254-
// For files in src/ directory, use the parent directory
255-
// For files in the root, use "root"
255+
// Convert to Path for easier manipulation
256+
let path = Path::new(file_path);
256257

257-
let path_parts: Vec<&str> = file_path.split('/').collect();
258+
// Try to find the closest Cargo.toml file
259+
if let Some(cargo_toml_path) = find_closest_cargo_toml(path) {
260+
if let Some(crate_name) = extract_package_name(&cargo_toml_path) {
261+
return crate_name;
262+
}
263+
}
264+
265+
// Fallback to the old heuristic if Cargo.toml can't be found or parsed
266+
"unknown-crate".to_owned()
267+
}
258268

259-
if path_parts.is_empty() {
260-
return "unknown".to_owned();
269+
/// Find the closest Cargo.toml file by traversing up the directory tree
270+
fn find_closest_cargo_toml(mut path: &Path) -> Option<PathBuf> {
271+
// Start with the directory containing the file
272+
if !path.is_dir() {
273+
path = path.parent()?;
261274
}
262275

263-
// Handle common project structures
264-
if path_parts.len() > 1 {
265-
// If it's in "src" or "tests" folder, use the parent directory
266-
if path_parts[0] == "src" || path_parts[0] == "tests" {
267-
return "root".to_owned();
276+
// Traverse up the directory tree
277+
loop {
278+
let cargo_path = path.join("Cargo.toml");
279+
if cargo_path.exists() {
280+
return Some(cargo_path);
268281
}
269282

270-
// If it's in a nested crate structure like crates/foo/src
271-
if path_parts[0] == "crates" && path_parts.len() > 2 {
272-
return path_parts[1].to_owned();
283+
// Check if we've reached the root
284+
let parent = path.parent()?;
285+
if parent == path {
286+
// We've reached the root without finding Cargo.toml
287+
return None;
273288
}
274289

275-
// If it's in a workspace pattern like foo/src
276-
if path_parts.len() > 1 && (path_parts[1] == "src" || path_parts[1] == "tests") {
277-
return path_parts[0].to_owned();
278-
}
290+
// Move up one directory
291+
path = parent;
279292
}
293+
}
280294

281-
// Default: use first directory name
282-
path_parts[0].to_owned()
295+
/// Extract package name from Cargo.toml
296+
fn extract_package_name(cargo_toml_path: &Path) -> Option<String> {
297+
// Read the Cargo.toml file
298+
let content = match fs::read_to_string(cargo_toml_path) {
299+
Ok(content) => content,
300+
Err(e) => {
301+
log::warn!("Failed to read {}: {}", cargo_toml_path.display(), e);
302+
return None;
303+
}
304+
};
305+
306+
// Parse the TOML
307+
let toml_value: Value = match content.parse() {
308+
Ok(value) => value,
309+
Err(e) => {
310+
log::warn!("Failed to parse {}: {}", cargo_toml_path.display(), e);
311+
return None;
312+
}
313+
};
314+
315+
// Extract the package name
316+
toml_value
317+
.get("package")?
318+
.get("name")?
319+
.as_str()
320+
.map(|s| s.to_string())
283321
}
284322

285323
/// Count annotations by crate
@@ -421,7 +459,7 @@ fn get_branch_content(file: &str, branch: &str) -> String {
421459
// "#;
422460
//
423461
// let regex =
424-
//
462+
//
425463
// Regex::new(r"#\s*\[\s*allow\s*\(\s*clippy\s*::\s*(unwrap_used|expect_used)\s*\)\s*\]")
426464
// .unwrap();
427465
// let mut rule_cache = HashMap::new();

0 commit comments

Comments
 (0)