use serde::de::{Deserializer, MapAccess, Visitor};
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Trigger {
PullRequest,
PullRequestTarget,
Push,
Schedule,
WorkflowDispatch,
WorkflowCall,
WorkflowRun,
Release,
Tags,
Other(String),
}
impl Trigger {
fn from_name(name: &str) -> Self {
match name {
"pull_request" => Self::PullRequest,
"pull_request_target" => Self::PullRequestTarget,
"push" => Self::Push,
"schedule" => Self::Schedule,
"workflow_dispatch" => Self::WorkflowDispatch,
"workflow_call" => Self::WorkflowCall,
"workflow_run" => Self::WorkflowRun,
"release" => Self::Release,
"tags" => Self::Tags,
other => Self::Other(other.to_owned()),
}
}
#[must_use]
pub fn as_str(&self) -> &str {
match self {
Self::PullRequest => "pull_request",
Self::PullRequestTarget => "pull_request_target",
Self::Push => "push",
Self::Schedule => "schedule",
Self::WorkflowDispatch => "workflow_dispatch",
Self::WorkflowCall => "workflow_call",
Self::WorkflowRun => "workflow_run",
Self::Release => "release",
Self::Tags => "tags",
Self::Other(s) => s.as_str(),
}
}
}
impl fmt::Display for Trigger {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
fn parse_triggers<'de, D: Deserializer<'de>>(de: D) -> Result<Vec<Trigger>, D::Error> {
struct V;
impl<'de> Visitor<'de> for V {
type Value = Vec<Trigger>;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a YAML string, list, or map describing workflow triggers")
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Vec<Trigger>, E> {
Ok(vec![Trigger::from_name(v)])
}
fn visit_string<E: serde::de::Error>(self, v: String) -> Result<Vec<Trigger>, E> {
Ok(vec![Trigger::from_name(&v)])
}
fn visit_seq<A: serde::de::SeqAccess<'de>>(
self,
mut seq: A,
) -> Result<Vec<Trigger>, A::Error> {
let mut out = Vec::new();
while let Some(name) = seq.next_element::<String>()? {
out.push(Trigger::from_name(&name));
}
Ok(out)
}
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Vec<Trigger>, A::Error> {
let mut out = Vec::new();
while let Some(name) = map.next_key::<String>()? {
let _: serde::de::IgnoredAny = map.next_value()?;
out.push(Trigger::from_name(&name));
}
Ok(out)
}
}
de.deserialize_any(V)
}
pub(super) fn parse_triggers_opt<'de, D: Deserializer<'de>>(
de: D,
) -> Result<Option<Vec<Trigger>>, D::Error> {
parse_triggers(de).map(Some)
}