Skip to content

Commit 74e9faf

Browse files
committed
feat(utils): implement filter_logs to filter submission records of specified rules
1 parent 36c1d8f commit 74e9faf

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

src/utils/filter_logs.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
use anyhow::Result;
2+
use regex::Regex;
3+
4+
const AUTHOR_IDX: usize = 1;
5+
const MSG_IDX: usize = 3;
6+
7+
/// Build a case-insensitive regex, return None if patterns is empty
8+
fn build_regex(patterns: &[String]) -> Option<Regex> {
9+
let patterns: Vec<&str> = patterns
10+
.iter()
11+
.filter(|s| !s.is_empty())
12+
.map(|s| s.as_str())
13+
.collect();
14+
if patterns.is_empty() {
15+
None
16+
} else {
17+
Some(Regex::new(&format!("(?i){}", patterns.join("|"))).unwrap())
18+
}
19+
}
20+
21+
pub fn filter_logs(
22+
logs: &[String],
23+
authors: &[String],
24+
includes: &[String],
25+
excludes: &[String],
26+
) -> Result<Vec<String>> {
27+
// Build regex by configuration
28+
let author_re = build_regex(authors);
29+
let include_re = build_regex(includes);
30+
let exclude_re = build_regex(excludes);
31+
32+
let filtered: Vec<String> = logs
33+
.iter()
34+
.filter(|log| {
35+
let fields: Vec<&str> = log.split("|||").collect();
36+
let author = fields.get(AUTHOR_IDX).unwrap_or(&"");
37+
author_re.as_ref().map_or(true, |re| re.is_match(author))
38+
})
39+
.filter(|log| {
40+
let fields: Vec<&str> = log.split("|||").collect();
41+
let msg = fields.get(MSG_IDX).unwrap_or(&"");
42+
include_re.as_ref().map_or(true, |re| re.is_match(msg))
43+
})
44+
.filter(|log| {
45+
let fields: Vec<&str> = log.split("|||").collect();
46+
let msg = fields.get(MSG_IDX).unwrap_or(&"");
47+
!exclude_re.as_ref().map_or(false, |re| re.is_match(msg))
48+
})
49+
.cloned()
50+
.collect();
51+
52+
Ok(filtered)
53+
}
54+
55+
#[cfg(test)]
56+
mod tests {
57+
use super::*;
58+
59+
fn logs() -> Vec<String> {
60+
vec![
61+
"repo1|||Alice|||alice@example.com|||feat: add feature|||'abc123|||2024-06-01 12:00:00"
62+
.to_string(),
63+
"repo1|||Bob|||bob@example.com|||fix: bug|||'def456|||2024-06-01 13:00:00".to_string(),
64+
"repo2|||Alice|||alice@example.com|||docs: update|||'ghi789|||2024-06-01 14:00:00"
65+
.to_string(),
66+
"repo2|||Eve|||eve@example.com|||chore: deps|||'jkl012|||2024-06-01 15:00:00"
67+
.to_string(),
68+
]
69+
}
70+
71+
#[test]
72+
fn test_filter_by_author() {
73+
let logs = logs();
74+
let authors = vec!["Alice".to_string()];
75+
let includes = vec!["".to_string()]; // 匹配所有
76+
let excludes = vec!["".to_string()]; // 不排除
77+
let filtered = filter_logs(&logs, &authors, &includes, &excludes).unwrap();
78+
assert_eq!(filtered.len(), 2);
79+
assert!(filtered.iter().all(|log| log.contains("Alice")));
80+
}
81+
82+
#[test]
83+
fn test_filter_by_include() {
84+
let logs = logs();
85+
let authors = vec!["".to_string()]; // 匹配所有
86+
let includes = vec!["feat".to_string()];
87+
let excludes = vec!["".to_string()];
88+
let filtered = filter_logs(&logs, &authors, &includes, &excludes).unwrap();
89+
assert_eq!(filtered.len(), 1);
90+
assert!(filtered[0].contains("feat: add feature"));
91+
}
92+
93+
#[test]
94+
fn test_filter_by_exclude() {
95+
let logs = logs();
96+
let authors = vec!["".to_string()];
97+
let includes = vec!["".to_string()];
98+
let excludes = vec!["chore".to_string()];
99+
let filtered = filter_logs(&logs, &authors, &includes, &excludes).unwrap();
100+
assert_eq!(filtered.len(), 3);
101+
assert!(filtered.iter().all(|log| !log.contains("chore")));
102+
}
103+
104+
#[test]
105+
fn test_filter_combined() {
106+
let logs = logs();
107+
let authors = vec!["Alice".to_string()];
108+
let includes = vec!["docs".to_string()];
109+
let excludes = vec!["".to_string()];
110+
let filtered = filter_logs(&logs, &authors, &includes, &excludes).unwrap();
111+
assert_eq!(filtered.len(), 1);
112+
assert!(filtered[0].contains("docs: update"));
113+
}
114+
115+
#[test]
116+
fn test_filter_none() {
117+
let logs = logs();
118+
let authors = vec!["NonExist".to_string()];
119+
let includes = vec!["feat".to_string()];
120+
let excludes = vec!["".to_string()];
121+
let filtered = filter_logs(&logs, &authors, &includes, &excludes).unwrap();
122+
assert_eq!(filtered.len(), 0);
123+
}
124+
}

src/utils/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
pub mod filter_logs;
12
pub mod format_commit;
23
pub mod format_log;
34
pub mod get_repo_logs;

0 commit comments

Comments
 (0)