semver-common 1.2.2

Common library to use for semantic release core and plugins.
Documentation
use std::str::FromStr;

use crate::{Alert, CommitMap};
use derive_getters::Getters;
use serde::{Deserialize, Serialize};

/// Data structure that contains a version with a major, minor, and patch number as well as a map
/// of commits that represent changes since the previous version.
#[derive(Serialize, Deserialize, Getters, Clone)]
pub struct Version {
    major: u32,
    minor: u32,
    patch: u32,
    changes: CommitMap,
}

impl Default for Version {
    fn default() -> Self {
        Self::new(0, 0, 0, CommitMap::new())
    }
}

impl FromStr for Version {
    type Err = Alert;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let config: Version = serde_json::from_str(s)?;
        Ok(config)
    }
}

impl<T> From<T> for Version
where
    T: ToString,
{
    fn from(value: T) -> Self {
        Self::from_str(&value.to_string()).unwrap()
    }
}

impl Version {
    /// Gets the version in string form. Formatted, "v(major).(minor).(patch)"
    pub fn get(&self) -> String {
        format!("v{}.{}.{}", self.major, self.minor, self.patch)
    }

    /// Gets the version in short string form. Formatted, "(major).(minor).(patch)"
    pub fn short(&self) -> String {
        format!("{}.{}.{}", self.major, self.minor, self.patch)
    }

    /// Parse a string into the appropriate version numbers. Returns a tuple containing
    /// the major, minor, and patch version numbers extracted from the string, if available.
    pub fn parse(version: &str) -> Option<(u32, u32, u32)> {
        if version.len() <= 1 {
            return None;
        }
        let separated: Vec<&str> = version[1..].split(".").collect();
        if separated.len() == 3 {
            let major_version = separated.first()?;
            let minor_version = separated.get(1)?;
            let patch_version = separated.get(2)?;
            return Some((
                major_version.parse().ok()?,
                minor_version.parse().ok()?,
                patch_version.parse().ok()?,
            ));
        }
        None
    }

    pub fn new(major: u32, minor: u32, patch: u32, changes: CommitMap) -> Self {
        Version {
            major,
            minor,
            patch,
            changes,
        }
    }
}

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

    #[test]
    fn test_version_parse_valid() {
        let parse_value = Version::parse("v1.9.2");
        assert_eq!(parse_value, Some((1, 9, 2)));
    }

    #[test]
    fn test_version_parse_invalid_full_len() {
        let parse_value = Version::parse("oopasdf91.9.2ff");
        assert_eq!(parse_value, None);
    }

    #[test]
    fn test_version_parse_invalid_one_len() {
        let parse_value = Version::parse("v");
        assert_eq!(parse_value, None);
    }

    #[test]
    fn test_version_parse_invalid_no_input() {
        let parse_value = Version::parse("");
        assert_eq!(parse_value, None);
    }

    #[test]
    fn test_version_parse_invalid_no_int() {
        let parse_value = Version::parse("vIU.AB.PE");
        assert_eq!(parse_value, None);
    }

    #[test]
    fn test_version_get() {
        let (major, minor, patch) = Version::parse("v1.9.2").unwrap();
        let changes = CommitMap::new();
        let version = Version::new(major, minor, patch, changes);
        assert_eq!(version.get(), "v1.9.2");
    }
}