use super::identity::{ActionId, CommitSha, Version};
use crate::domain::workflow_actions::WorkflowAction;
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub enum RefType {
#[serde(rename = "release")]
Release,
#[serde(rename = "tag")]
Tag,
#[serde(rename = "branch")]
Branch,
#[serde(rename = "commit")]
Commit,
}
impl fmt::Display for RefType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Release => write!(f, "release"),
Self::Tag => write!(f, "tag"),
Self::Branch => write!(f, "branch"),
Self::Commit => write!(f, "commit"),
}
}
}
impl RefType {
#[must_use]
pub fn parse(s: &str) -> Option<Self> {
match s {
"release" => Some(Self::Release),
"tag" => Some(Self::Tag),
"branch" => Some(Self::Branch),
"commit" => Some(Self::Commit),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UsesRef {
pub action_name: String,
pub uses_ref: String,
pub comment: Option<String>,
}
impl UsesRef {
#[must_use]
pub const fn new(action_name: String, uses_ref: String, comment: Option<String>) -> Self {
Self {
action_name,
uses_ref,
comment,
}
}
#[must_use]
pub fn interpret(&self) -> WorkflowAction {
let (version, sha) = self.comment.as_ref().map_or_else(
|| {
(Version::from(self.uses_ref.as_str()), None)
},
|comment| {
let version = Version::normalized(comment);
let sha = CommitSha::is_valid(&self.uses_ref)
.then(|| CommitSha::from(self.uses_ref.as_str()));
(version, sha)
},
);
WorkflowAction {
id: ActionId::from(self.action_name.as_str()),
version,
sha,
}
}
}
#[cfg(test)]
mod tests {
use super::{CommitSha, RefType, UsesRef};
#[test]
fn ref_type_display() {
assert_eq!(RefType::Release.to_string(), "release");
assert_eq!(RefType::Tag.to_string(), "tag");
assert_eq!(RefType::Branch.to_string(), "branch");
assert_eq!(RefType::Commit.to_string(), "commit");
}
#[test]
fn ref_type_parse() {
assert_eq!(RefType::parse("release"), Some(RefType::Release));
assert_eq!(RefType::parse("tag"), Some(RefType::Tag));
assert_eq!(RefType::parse("branch"), Some(RefType::Branch));
assert_eq!(RefType::parse("commit"), Some(RefType::Commit));
assert_eq!(RefType::parse("unknown"), None);
}
#[test]
fn ref_type_equality() {
assert_eq!(RefType::Release, RefType::Release);
assert_ne!(RefType::Release, RefType::Tag);
}
#[test]
fn uses_ref_interpret_tag_only() {
let uses_ref = UsesRef::new("actions/checkout".to_owned(), "v4".to_owned(), None);
let interpreted = uses_ref.interpret();
assert_eq!(interpreted.id.as_str(), "actions/checkout");
assert_eq!(interpreted.version.as_str(), "v4");
assert!(interpreted.sha.is_none());
}
#[test]
fn uses_ref_interpret_sha_with_comment() {
let uses_ref = UsesRef::new(
"actions/checkout".to_owned(),
"abc123def456789012345678901234567890abcd".to_owned(),
Some("v4".to_owned()),
);
let interpreted = uses_ref.interpret();
assert_eq!(interpreted.id.as_str(), "actions/checkout");
assert_eq!(interpreted.version.as_str(), "v4");
assert_eq!(
interpreted.sha.as_ref().map(CommitSha::as_str),
Some("abc123def456789012345678901234567890abcd")
);
}
#[test]
fn uses_ref_interpret_normalizes_version() {
let uses_ref = UsesRef::new(
"actions/checkout".to_owned(),
"abc123def456789012345678901234567890abcd".to_owned(),
Some("4".to_owned()), );
let interpreted = uses_ref.interpret();
assert_eq!(interpreted.version.as_str(), "v4"); }
#[test]
fn uses_ref_interpret_sha_without_comment() {
let uses_ref = UsesRef::new(
"actions/checkout".to_owned(),
"abc123def456789012345678901234567890abcd".to_owned(),
None,
);
let interpreted = uses_ref.interpret();
assert_eq!(
interpreted.version.as_str(),
"abc123def456789012345678901234567890abcd"
);
assert!(interpreted.sha.is_none());
}
#[test]
fn uses_ref_interpret_short_ref_with_comment() {
let uses_ref = UsesRef::new(
"actions/checkout".to_owned(),
"abc123".to_owned(),
Some("v4".to_owned()),
);
let interpreted = uses_ref.interpret();
assert_eq!(interpreted.version.as_str(), "v4");
assert!(interpreted.sha.is_none()); }
}