git_stack/legacy/git/
protect.rs1#[derive(Clone, Debug)]
2pub struct ProtectedBranches {
3 ignores: ignore::gitignore::Gitignore,
4}
5
6impl ProtectedBranches {
7 pub fn new<'p>(patterns: impl IntoIterator<Item = &'p str>) -> eyre::Result<Self> {
8 let mut ignores = ignore::gitignore::GitignoreBuilder::new("");
9 for pattern in patterns {
10 ignores.add_line(None, pattern)?;
11 }
12 let ignores = ignores.build()?;
13 Ok(Self { ignores })
14 }
15
16 pub fn is_protected(&self, name: &str) -> bool {
17 let name_match = self.ignores.matched_path_or_any_parents(name, false);
18 match name_match {
19 ignore::Match::None => false,
20 ignore::Match::Ignore(glob) => {
21 log::trace!("{}: ignored {:?}", name, glob.original());
22 true
23 }
24 ignore::Match::Whitelist(glob) => {
25 log::trace!("{}: allowed {:?}", name, glob.original());
26 false
27 }
28 }
29 }
30}
31
32#[cfg(test)]
33mod test {
34 use super::*;
35
36 #[test]
37 fn empty_allows_all() {
38 let protect = ProtectedBranches::new(None).unwrap();
39 assert!(!protect.is_protected("main"));
40 }
41
42 #[test]
43 fn protect_branch() {
44 let protect = ProtectedBranches::new(Some("main")).unwrap();
45 assert!(protect.is_protected("main"));
46 assert!(!protect.is_protected("feature"));
47 }
48
49 #[test]
50 fn negation_patterns() {
51 let protect = ProtectedBranches::new(vec!["v*", "!very"]).unwrap();
52 assert!(protect.is_protected("v1.0.0"));
53 assert!(!protect.is_protected("very"));
54 assert!(!protect.is_protected("feature"));
55 }
56
57 #[test]
58 fn folders() {
59 let protect = ProtectedBranches::new(vec!["release/"]).unwrap();
60 assert!(!protect.is_protected("release"));
61 assert!(protect.is_protected("release/v1.0.0"));
62 assert!(!protect.is_protected("feature"));
63 }
64}