forge_core_utils/
git.rs

1pub fn is_valid_branch_prefix(prefix: &str) -> bool {
2    if prefix.is_empty() {
3        return true;
4    }
5
6    if prefix.contains('/') {
7        return false;
8    }
9
10    git2::Branch::name_is_valid(&format!("{prefix}/x")).unwrap_or_default()
11}
12
13#[cfg(test)]
14mod tests {
15    use super::*;
16
17    #[test]
18    fn test_valid_prefixes() {
19        assert!(is_valid_branch_prefix(""));
20        assert!(is_valid_branch_prefix("af"));
21        assert!(is_valid_branch_prefix("feature"));
22        assert!(is_valid_branch_prefix("hotfix-123"));
23        assert!(is_valid_branch_prefix("foo.bar"));
24        assert!(is_valid_branch_prefix("foo_bar"));
25        assert!(is_valid_branch_prefix("FOO-Bar"));
26    }
27
28    #[test]
29    fn test_invalid_prefixes() {
30        assert!(!is_valid_branch_prefix("foo/bar"));
31        assert!(!is_valid_branch_prefix("foo..bar"));
32        assert!(!is_valid_branch_prefix("foo@{"));
33        assert!(!is_valid_branch_prefix("foo.lock"));
34        // Note: git2 allows trailing dots in some contexts, but we enforce stricter rules
35        // for prefixes by checking the full branch name format
36        assert!(!is_valid_branch_prefix("foo bar"));
37        assert!(!is_valid_branch_prefix("foo?"));
38        assert!(!is_valid_branch_prefix("foo*"));
39        assert!(!is_valid_branch_prefix("foo~"));
40        assert!(!is_valid_branch_prefix("foo^"));
41        assert!(!is_valid_branch_prefix("foo:"));
42        assert!(!is_valid_branch_prefix("foo["));
43        assert!(!is_valid_branch_prefix("/foo"));
44        assert!(!is_valid_branch_prefix("foo/"));
45        assert!(!is_valid_branch_prefix(".foo"));
46    }
47}