use std::path::Path;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ChangeKind {
Source {
is_proc_macro: bool,
},
Test {
kind: TestKind,
},
Example,
BuildScript,
Config {
kind: ConfigKind,
},
Documentation,
Other,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TestKind {
Integration,
Bench,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConfigKind {
CargoToml,
CargoLock,
CargoConfig,
RustToolchain,
}
pub fn classify_file(path: &Path) -> ChangeKind {
let path_str = path.to_string_lossy();
if path_str.ends_with("build.rs") {
return ChangeKind::BuildScript;
}
if let Some(config_kind) = classify_config(&path_str) {
return ChangeKind::Config { kind: config_kind };
}
if is_documentation(&path_str) {
return ChangeKind::Documentation;
}
if path_str.ends_with(".rs") {
return classify_rust_file(&path_str);
}
ChangeKind::Other
}
fn classify_config(path_str: &str) -> Option<ConfigKind> {
if path_str.ends_with("Cargo.toml") {
Some(ConfigKind::CargoToml)
} else if path_str.ends_with("Cargo.lock") {
Some(ConfigKind::CargoLock)
} else if path_str.ends_with(".cargo/config.toml") || path_str.ends_with(".cargo/config") {
Some(ConfigKind::CargoConfig)
} else if path_str.ends_with("rust-toolchain.toml") || path_str.ends_with("rust-toolchain") {
Some(ConfigKind::RustToolchain)
} else {
None
}
}
fn is_documentation(path_str: &str) -> bool {
path_str.ends_with(".md")
|| path_str.ends_with(".txt")
|| path_str.ends_with(".adoc")
|| path_str.ends_with(".rst")
|| path_str.ends_with("LICENSE")
|| path_str.ends_with("README")
}
fn classify_rust_file(path_str: &str) -> ChangeKind {
if is_example_file(path_str) {
return ChangeKind::Example;
}
if is_test_file(path_str) {
let kind = if path_str.contains("/benches/") || path_str.starts_with("benches/") {
TestKind::Bench
} else {
TestKind::Integration
};
return ChangeKind::Test { kind };
}
ChangeKind::Source { is_proc_macro: false }
}
fn is_example_file(path_str: &str) -> bool {
path_str.contains("/examples/") || path_str.starts_with("examples/")
}
fn is_test_file(path_str: &str) -> bool {
(path_str.contains("/tests/") || path_str.starts_with("tests/"))
|| (path_str.contains("/benches/") || path_str.starts_with("benches/"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_classify_build_script() {
assert_eq!(classify_file(Path::new("build.rs")), ChangeKind::BuildScript);
assert_eq!(classify_file(Path::new("crates/foo/build.rs")), ChangeKind::BuildScript);
}
#[test]
fn test_classify_config_files() {
assert_eq!(
classify_file(Path::new("Cargo.toml")),
ChangeKind::Config {
kind: ConfigKind::CargoToml
}
);
assert_eq!(
classify_file(Path::new("Cargo.lock")),
ChangeKind::Config {
kind: ConfigKind::CargoLock
}
);
assert_eq!(
classify_file(Path::new(".cargo/config.toml")),
ChangeKind::Config {
kind: ConfigKind::CargoConfig
}
);
assert_eq!(
classify_file(Path::new("rust-toolchain.toml")),
ChangeKind::Config {
kind: ConfigKind::RustToolchain
}
);
}
#[test]
fn test_classify_documentation() {
assert_eq!(classify_file(Path::new("README.md")), ChangeKind::Documentation);
assert_eq!(classify_file(Path::new("docs/guide.md")), ChangeKind::Documentation);
assert_eq!(classify_file(Path::new("LICENSE")), ChangeKind::Documentation);
}
#[test]
fn test_classify_examples() {
assert_eq!(classify_file(Path::new("examples/demo.rs")), ChangeKind::Example);
assert_eq!(
classify_file(Path::new("crates/foo/examples/demo.rs")),
ChangeKind::Example
);
assert_eq!(
classify_file(Path::new("foo/bar/examples/demo.rs")),
ChangeKind::Example
);
}
#[test]
fn test_classify_integration_tests() {
let result = classify_file(Path::new("tests/integration.rs"));
assert!(matches!(
result,
ChangeKind::Test {
kind: TestKind::Integration
}
));
let result = classify_file(Path::new("crates/foo/tests/integration.rs"));
assert!(matches!(
result,
ChangeKind::Test {
kind: TestKind::Integration
}
));
}
#[test]
fn test_classify_benchmarks() {
let result = classify_file(Path::new("benches/benchmark.rs"));
assert!(matches!(result, ChangeKind::Test { kind: TestKind::Bench }));
let result = classify_file(Path::new("crates/foo/benches/benchmark.rs"));
assert!(matches!(result, ChangeKind::Test { kind: TestKind::Bench }));
}
#[test]
fn test_classify_source_files() {
let result = classify_file(Path::new("src/lib.rs"));
assert!(matches!(result, ChangeKind::Source { .. }));
let result = classify_file(Path::new("crates/foo/src/main.rs"));
assert!(matches!(result, ChangeKind::Source { .. }));
}
}