fundaia 0.55.0

Command line for the Fundaia deployment platform: projects, services, variables, deployments, logs and metrics
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Version {
    major: u64,
    minor: u64,
    patch: u64,
    release: bool,
}

impl Version {
    pub fn parse(text: &str) -> Option<Self> {
        let text = text.trim();
        let (core, tail) = match text.find(['-', '+']) {
            Some(at) => text.split_at(at),
            None => (text, ""),
        };

        let mut parts = core.split('.');
        let major = parts.next()?.parse().ok()?;
        let minor = parts.next().unwrap_or("0").parse().ok()?;
        let patch = parts.next().unwrap_or("0").parse().ok()?;

        if parts.next().is_some() {
            return None;
        }

        Some(Self {
            major,
            minor,
            patch,
            release: !tail.starts_with('-'),
        })
    }
}

pub fn newer<'a>(current: &str, published: &'a str) -> Option<&'a str> {
    let installed = Version::parse(current)?;
    let candidate = Version::parse(published)?;

    (candidate > installed).then_some(published)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_should_read_a_plain_version() {
        assert_eq!(Version::parse("0.3.0").unwrap().minor, 3);
    }

    #[test]
    fn it_should_rank_a_newer_minor_above_an_older_one() {
        assert!(Version::parse("0.4.0") > Version::parse("0.3.9"));
    }

    #[test]
    fn it_should_rank_a_newer_major_above_a_much_higher_minor() {
        assert!(Version::parse("1.0.0") > Version::parse("0.99.0"));
    }

    #[test]
    fn it_should_rank_a_release_above_its_own_pre_release() {
        assert!(Version::parse("0.4.0") > Version::parse("0.4.0-rc1"));
    }

    #[test]
    fn it_should_read_a_version_carrying_build_metadata_as_a_release() {
        assert!(Version::parse("0.4.0+deadbeef").unwrap().release);
    }

    #[test]
    fn it_should_refuse_a_version_with_a_fourth_part() {
        assert!(Version::parse("1.2.3.4").is_none());
    }

    #[test]
    fn it_should_refuse_something_that_is_not_a_version_at_all() {
        assert!(Version::parse("latest").is_none());
    }

    #[test]
    fn it_should_report_a_newer_release() {
        assert_eq!(newer("0.3.0", "0.4.0"), Some("0.4.0"));
    }

    #[test]
    fn it_should_report_nothing_when_the_installed_version_is_the_newest() {
        assert!(newer("0.3.0", "0.3.0").is_none());
    }

    #[test]
    fn it_should_report_nothing_when_the_installed_version_is_ahead() {
        assert!(newer("0.4.0", "0.3.0").is_none());
    }

    #[test]
    fn it_should_report_nothing_when_nothing_has_been_cached_yet() {
        assert!(newer("0.3.0", "").is_none());
    }

    #[test]
    fn it_should_report_nothing_when_the_registry_answer_is_unreadable() {
        assert!(newer("0.3.0", "not-a-version").is_none());
    }
}