use std::str::FromStr;
use strum::{Display, EnumString};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, Display, EnumString)]
#[strum(ascii_case_insensitive)]
pub enum LinkStyle {
#[default]
Github,
Gitlab,
Stash,
Cgit,
}
impl<'de> serde::de::Deserialize<'de> for LinkStyle {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
FromStr::from_str(&s).map_err(serde::de::Error::custom)
}
}
impl LinkStyle {
pub fn issue_link<S: AsRef<str>>(&self, issue: S, repo: Option<S>) -> String {
let issue = issue.as_ref();
if let Some(link) = repo {
let link = link.as_ref();
match *self {
LinkStyle::Github | LinkStyle::Gitlab => format!("{link}/issues/{issue}"),
LinkStyle::Stash | LinkStyle::Cgit => issue.to_string(),
}
} else {
issue.to_string()
}
}
pub fn commit_link<S: AsRef<str>>(&self, hash: S, repo: Option<S>) -> String {
let hash = hash.as_ref();
if let Some(link) = repo {
let link = link.as_ref();
match *self {
LinkStyle::Github | LinkStyle::Gitlab => format!("{link}/commit/{hash}"),
LinkStyle::Stash => format!("{link}/commits/{hash}"),
LinkStyle::Cgit => format!("{link}/commit/?id={hash}"),
}
} else {
hash.get(0..8).unwrap_or(hash).to_string()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
const REPO: &str = "https://github.com/test/repo";
const HASH: &str = "abc1234567890abcdef";
#[test]
fn github_issue_link() {
let link = LinkStyle::Github.issue_link("42", Some(REPO));
assert_eq!(link, "https://github.com/test/repo/issues/42");
}
#[test]
fn gitlab_issue_link() {
let link = LinkStyle::Gitlab.issue_link("42", Some(REPO));
assert_eq!(link, "https://github.com/test/repo/issues/42");
}
#[test]
fn stash_issue_link_returns_number() {
let link = LinkStyle::Stash.issue_link("42", Some(REPO));
assert_eq!(link, "42");
}
#[test]
fn cgit_issue_link_returns_number() {
let link = LinkStyle::Cgit.issue_link("42", Some(REPO));
assert_eq!(link, "42");
}
#[test]
fn issue_link_without_repo() {
let link = LinkStyle::Github.issue_link("42", None::<&str>);
assert_eq!(link, "42");
}
#[test]
fn github_commit_link() {
let link = LinkStyle::Github.commit_link(HASH, Some(REPO));
assert_eq!(link, format!("{REPO}/commit/{HASH}"));
}
#[test]
fn stash_commit_link() {
let link = LinkStyle::Stash.commit_link(HASH, Some(REPO));
assert_eq!(link, format!("{REPO}/commits/{HASH}"));
}
#[test]
fn cgit_commit_link() {
let link = LinkStyle::Cgit.commit_link(HASH, Some(REPO));
assert_eq!(link, format!("{REPO}/commit/?id={HASH}"));
}
#[test]
fn commit_link_without_repo_truncates_hash() {
let link = LinkStyle::Github.commit_link(HASH, None::<&str>);
assert_eq!(link, "abc12345");
}
#[test]
fn commit_link_without_repo_short_hash() {
let link = LinkStyle::Github.commit_link("abc", None::<&str>);
assert_eq!(link, "abc");
}
#[test]
fn link_style_from_str() {
assert_eq!("Github".parse::<LinkStyle>().unwrap(), LinkStyle::Github);
assert_eq!("github".parse::<LinkStyle>().unwrap(), LinkStyle::Github);
assert_eq!("GITLAB".parse::<LinkStyle>().unwrap(), LinkStyle::Gitlab);
assert_eq!("stash".parse::<LinkStyle>().unwrap(), LinkStyle::Stash);
assert_eq!("Cgit".parse::<LinkStyle>().unwrap(), LinkStyle::Cgit);
}
}