use std::path::PathBuf;
use kind::TriggerKind;
pub(crate) use dispatcher::dispatch_triggers;
pub use error::{TriggerError, TriggerKindLabel};
pub use http_method::HttpMethod;
pub use template::TemplateErrorKind;
#[cfg(unix)]
pub use yaml::CommandTriggerConfig;
pub use yaml::{EchoConfig, LogConfig, TriggerConfig, WebhookTriggerConfig};
#[cfg(unix)]
mod command;
mod dispatcher;
mod echo;
mod error;
mod http_method;
mod kind;
mod log;
mod post;
mod teams;
mod template;
mod webhook;
mod yaml;
#[cfg(test)]
mod tests;
pub use webhook::DEFAULT_WEBHOOK_TIMEOUT;
#[non_exhaustive]
#[derive(Clone)]
pub struct Trigger {
kind: TriggerKind,
pub(crate) retries: u32,
pub(crate) required: bool,
pub(crate) timeout: Option<std::time::Duration>,
pub(crate) fail_fast: bool,
}
impl std::fmt::Debug for Trigger {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Trigger {
kind,
retries,
required,
timeout,
fail_fast,
} = self;
f.debug_struct("Trigger")
.field("kind", kind)
.field("retries", retries)
.field("required", required)
.field("timeout", timeout)
.field("fail_fast", fail_fast)
.finish()
}
}
impl Trigger {
#[must_use]
pub fn echo() -> Self {
Self {
kind: TriggerKind::Echo { label: None },
retries: 0,
required: true,
timeout: None,
fail_fast: true,
}
}
#[must_use]
pub fn label(mut self, name: impl Into<String>) -> Self {
if let TriggerKind::Echo { label } = &mut self.kind {
*label = Some(name.into());
}
self
}
#[must_use]
pub fn log(path: impl Into<PathBuf>) -> Self {
Self {
kind: TriggerKind::Log { path: path.into() },
retries: 0,
required: true,
timeout: None,
fail_fast: true,
}
}
#[cfg(unix)]
#[must_use]
pub fn command(cmd: impl Into<String>) -> Self {
Self {
kind: TriggerKind::Command(Box::new(command::build_command_config(cmd))),
retries: 0,
required: true,
timeout: None,
fail_fast: true,
}
}
#[cfg(unix)]
#[must_use]
pub fn env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
if let TriggerKind::Command(cfg) = &mut self.kind {
cfg.env.insert(key.into(), value.into());
}
self
}
#[cfg(unix)]
#[must_use]
pub fn working_dir(mut self, dir: impl Into<PathBuf>) -> Self {
if let TriggerKind::Command(cfg) = &mut self.kind {
cfg.working_dir = Some(dir.into());
}
self
}
#[must_use]
pub fn retries(mut self, retries: u32) -> Self {
self.retries = retries;
self
}
#[must_use]
pub fn required(mut self, required: bool) -> Self {
self.required = required;
self
}
#[must_use]
pub fn timeout(mut self, t: std::time::Duration) -> Self {
self.timeout = Some(t);
self
}
#[must_use]
pub fn fail_fast(mut self, on: bool) -> Self {
self.fail_fast = on;
self
}
}
#[cfg(test)]
impl Trigger {
fn test_failing(
failures_remaining: u32,
eventual: kind::TestEventual,
retries: u32,
required: bool,
) -> (Self, std::sync::Arc<std::sync::atomic::AtomicU32>) {
let counter = std::sync::Arc::new(std::sync::atomic::AtomicU32::new(failures_remaining));
let trigger = Self {
kind: TriggerKind::TestFailing {
failures_remaining: counter.clone(),
eventual,
},
retries,
required,
timeout: None,
fail_fast: true,
};
(trigger, counter)
}
pub(crate) fn test_fail_on_call(
fail_on_call: u32,
retries: u32,
required: bool,
) -> (Self, std::sync::Arc<std::sync::atomic::AtomicU32>) {
let counter = std::sync::Arc::new(std::sync::atomic::AtomicU32::new(0));
let trigger = Self {
kind: TriggerKind::TestFailOnCall {
calls: counter.clone(),
fail_on_call,
},
retries,
required,
timeout: None,
fail_fast: true,
};
(trigger, counter)
}
}
pub(super) struct TriggerState {
pub(super) log_handle: Option<tokio::fs::File>,
}
impl TriggerState {
pub(super) fn new() -> Self {
Self { log_handle: None }
}
}
#[derive(Debug)]
pub(super) enum DispatchOutcome {
RequiredFailed {
kind: TriggerKindLabel,
source: TriggerError,
},
Cancelled,
}