Skip to main content

opensession_git_native/
refs.rs

1use base64::engine::general_purpose::URL_SAFE_NO_PAD;
2use base64::Engine;
3
4use crate::BRANCH_LEDGER_REF_PREFIX;
5
6/// Encode a branch name as base64url (without padding) for ref-safe storage.
7pub fn encode_branch_component(branch: &str) -> String {
8    URL_SAFE_NO_PAD.encode(branch.as_bytes())
9}
10
11/// Return hidden ref name for branch ledger storage.
12pub fn branch_ledger_ref(branch: &str) -> String {
13    let encoded = encode_branch_component(branch);
14    format!("{BRANCH_LEDGER_REF_PREFIX}/{encoded}")
15}
16
17/// Normalize branch identity for ledger storage.
18///
19/// Rules:
20/// - Normal branch names are used as-is.
21/// - Detached HEAD (`HEAD`/empty branch) maps to `detached@<head8>` when HEAD exists.
22/// - Falls back to `detached` if no usable HEAD hash is available.
23pub fn resolve_ledger_branch(branch: Option<&str>, head: Option<&str>) -> String {
24    let branch = branch.unwrap_or("").trim();
25    if !branch.is_empty() && !branch.eq_ignore_ascii_case("HEAD") {
26        return branch.to_string();
27    }
28
29    let head = head.unwrap_or("").trim();
30    let hex: String = head.chars().filter(|c| c.is_ascii_hexdigit()).collect();
31    if hex.len() >= 8 {
32        return format!("detached@{}", &hex[..8]);
33    }
34
35    "detached".to_string()
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41
42    #[test]
43    fn encode_branch_component_is_deterministic() {
44        let encoded = encode_branch_component("feature/hello-world");
45        assert_eq!(encoded, "ZmVhdHVyZS9oZWxsby13b3JsZA");
46    }
47
48    #[test]
49    fn branch_ledger_ref_builds_hidden_ref() {
50        let ref_name = branch_ledger_ref("main");
51        assert_eq!(ref_name, "refs/opensession/branches/bWFpbg");
52    }
53
54    #[test]
55    fn resolve_ledger_branch_keeps_named_branch() {
56        let branch = resolve_ledger_branch(Some("feature/x"), Some("abcd1234"));
57        assert_eq!(branch, "feature/x");
58    }
59
60    #[test]
61    fn resolve_ledger_branch_uses_detached_with_head_prefix() {
62        let branch = resolve_ledger_branch(Some("HEAD"), Some("aabbccddeeff0011"));
63        assert_eq!(branch, "detached@aabbccdd");
64    }
65
66    #[test]
67    fn resolve_ledger_branch_falls_back_when_head_missing() {
68        let branch = resolve_ledger_branch(Some("HEAD"), None);
69        assert_eq!(branch, "detached");
70    }
71}