Radish alpha
r
rad:zwTxygwuz5LDGBq255RA2CbNGrz8
Radicle CI broker
Radicle
Git
feat(src/ci_event.rs): add parser for Git refs for patch, branch, tag
Lars Wirzenius committed 1 year ago
commit 504f13262c0ade4ee57a0c55ccb4b8195f99df0c
parent 6dc057e
2 files changed +127 -1
modified src/ci_event.rs
@@ -652,3 +652,102 @@ mod test_patch_id {
        ));
    }
}
+

+
#[derive(Debug, Eq, PartialEq)]
+
#[allow(dead_code)]
+
enum ParsedRef {
+
    Branch(BranchName),
+
    Patch(PatchId),
+
    Tag(String),
+
}
+

+
impl ParsedRef {
+
    #[cfg(test)]
+
    #[allow(clippy::unwrap_used)]
+
    fn parse_ref(refname: &RefString) -> Option<Self> {
+
        use crate::refs::branch_from_str;
+

+
        fn parse_patch_id(refname: &RefString) -> Option<ParsedRef> {
+
            const PATTERN: &str = r"^refs/namespaces/[^/]+/refs/heads/patches/([^/]+)$";
+
            let re = Regex::new(PATTERN).unwrap();
+
            if let Some(captures) = re.captures(refname) {
+
                if let Some(patch_id) = captures.get(1) {
+
                    if let Ok(oid) = Oid::try_from(patch_id.as_str()) {
+
                        let patch_id = PatchId::from(oid);
+
                        return Some(ParsedRef::Patch(patch_id));
+
                    }
+
                }
+
            }
+
            None
+
        }
+

+
        fn parse_branch_name(refname: &RefString) -> Option<ParsedRef> {
+
            const PATTERN: &str = r"^refs/namespaces/[^/]+/refs/heads/(.+)$";
+
            let re = Regex::new(PATTERN).unwrap();
+
            if let Some(captures) = re.captures(refname) {
+
                if let Some(branch_name) = captures.get(1) {
+
                    if let Ok(branch_name) = branch_from_str(branch_name.as_str()) {
+
                        return Some(ParsedRef::Branch(branch_name));
+
                    }
+
                }
+
            }
+
            None
+
        }
+

+
        fn parse_tag_name(refname: &RefString) -> Option<ParsedRef> {
+
            const PATTERN: &str = r"^refs/namespaces/[^/]+/refs/tags/(.+)$";
+
            let re = Regex::new(PATTERN).unwrap();
+
            if let Some(captures) = re.captures(refname) {
+
                if let Some(tag_name) = captures.get(1) {
+
                    return Some(ParsedRef::Tag(tag_name.as_str().to_string()));
+
                }
+
            }
+
            None
+
        }
+

+
        parse_patch_id(refname)
+
            .or_else(|| parse_branch_name(refname))
+
            .or_else(|| parse_tag_name(refname))
+
            .or(None)
+
    }
+
}
+

+
#[cfg(test)]
+
#[allow(clippy::unwrap_used)]
+
mod test_parsed_ref {
+
    use std::str::FromStr;
+

+
    use crate::refs::{branch_ref, ref_string};
+

+
    use super::*;
+

+
    #[test]
+
    fn branch() {
+
        let actual = ref_string("refs/namespaces/NID/refs/heads/main").unwrap();
+
        let wanted = branch_ref(&ref_string("main").unwrap()).unwrap();
+
        assert_eq!(
+
            ParsedRef::parse_ref(&actual),
+
            Some(ParsedRef::Branch(wanted))
+
        );
+
    }
+

+
    #[test]
+
    fn patch() {
+
        let actual = ref_string(
+
            "refs/namespaces/NID/refs/heads/patches/9d1a97571e86caafa86df7bc1692d305710a596e",
+
        )
+
        .unwrap();
+
        let wanted = PatchId::from_str("9d1a97571e86caafa86df7bc1692d305710a596e").unwrap();
+
        assert_eq!(
+
            ParsedRef::parse_ref(&actual),
+
            Some(ParsedRef::Patch(wanted))
+
        );
+
    }
+

+
    #[test]
+
    fn tag() {
+
        let actual = ref_string("refs/namespaces/NID/refs/tags/v0.0.0").unwrap();
+
        let wanted = "v0.0.0".to_string();
+
        assert_eq!(ParsedRef::parse_ref(&actual), Some(ParsedRef::Tag(wanted)));
+
    }
+
}
modified src/refs.rs
@@ -1,6 +1,11 @@
//! Git reference names, namespaced and not.

-
use radicle::git::{BranchName, Component, Namespaced, Qualified, RefStr, RefString};
+
use std::str::FromStr;
+

+
use radicle::{
+
    cob::patch::PatchId,
+
    git::{BranchName, Component, Namespaced, Qualified, RefStr, RefString},
+
};

/// Convert a plain branch name (`main`) from a Git ref
pub fn branch_ref(name: &RefStr) -> Result<BranchName, RefError> {
@@ -65,6 +70,13 @@ pub fn branch_from_namespaced(ns: &Namespaced) -> Result<BranchName, RefError> {
    ))
}

+
/// Create a [`PatchId`] from a string slice.
+
pub fn patch_from_str(s: &str) -> Result<PatchId, RefError> {
+
    let res = PatchId::from_str(s).map_err(|_| RefError::PatchIdFromStr(s.into()));
+
    eprintln!("{res:#?}");
+
    res
+
}
+

/// All errors from Git reference manipulation.
#[derive(Debug, thiserror::Error, Eq, PartialEq)]
pub enum RefError {
@@ -91,11 +103,17 @@ pub enum RefError {
    /// Can't create a [`Component`] from a name space name.
    #[error("failed to create a name space component from its name {0:?}")]
    NamespaceName(RefString),
+

+
    /// Can't create a patch id from string.
+
    #[error("failed to create a patch id from string: {0:?}")]
+
    PatchIdFromStr(String),
}

#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod test {
+
    use std::str::FromStr;
+

    use super::*;

    #[test]
@@ -139,4 +157,13 @@ mod test {
        let extracted = branch_from_namespaced(&name);
        assert_eq!(extracted.map(|x| x.to_string()), Ok("main".into()));
    }
+

+
    #[test]
+
    fn creates_patch_from_str() {
+
        let oid = PatchId::from_str("e76d814f6934f24d45f628f8ff9533dcdefc1bd8").unwrap();
+
        assert_eq!(
+
            patch_from_str("e76d814f6934f24d45f628f8ff9533dcdefc1bd8"),
+
            Ok(oid)
+
        );
+
    }
}