use std::collections::HashMap;
use std::time::Duration;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct FluxConfig {
pub project: Option<String>,
pub language: Option<String>,
pub environment: Option<Environment>,
pub secrets: Vec<String>,
pub deployment: Option<Deployment>,
pub uses: Vec<String>,
pub runner_pools: Vec<RunnerPool>,
pub policies: Vec<Policy>,
pub execution: Execution,
pub steps: Vec<Step>,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Execution {
pub timeout: Option<Timeout>,
pub parallel: Option<u32>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Timeout {
Off,
After(Duration),
}
impl Timeout {
pub fn limit(self) -> Option<Duration> {
match self {
Timeout::Off => None,
Timeout::After(d) => Some(d),
}
}
pub fn describe(self) -> String {
match self {
Timeout::Off => "off".to_string(),
Timeout::After(d) => format!("\"{}\"", format_duration(d)),
}
}
}
pub fn format_duration(d: Duration) -> String {
let secs = d.as_secs();
if secs > 0 && secs % 3600 == 0 {
format!("{}h", secs / 3600)
} else if secs > 0 && secs % 60 == 0 {
format!("{}m", secs / 60)
} else {
format!("{secs}s")
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Policy {
pub name: String,
pub require_tests: bool,
pub require_security: bool,
pub require_approvals: u32,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct RunnerPool {
pub name: String,
pub gpu: Option<bool>,
pub memory: Option<String>,
pub os: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Environment {
pub image: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Deployment {
pub target: Option<String>,
pub replicas: Option<u32>,
pub image: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Step {
pub name: String,
pub command: Option<String>,
pub tool: Option<String>,
pub description: Option<String>,
pub cache: bool,
pub needs: Vec<String>,
pub only_if: Option<Condition>,
pub retries: u32,
pub timeout: Option<Timeout>,
pub secrets: Vec<String>,
pub inputs: Vec<String>,
}
impl Step {
pub fn new(name: impl Into<String>) -> Self {
Step {
name: name.into(),
command: None,
tool: None,
description: None,
cache: true,
needs: Vec::new(),
only_if: None,
retries: 0,
timeout: None,
secrets: Vec::new(),
inputs: Vec::new(),
}
}
pub fn command(name: impl Into<String>, command: impl Into<String>) -> Self {
let mut s = Step::new(name);
s.command = Some(command.into());
s
}
pub fn is_hook(&self) -> bool {
self.tool.is_some()
}
}
pub const CONDITION_VARS: &[&str] = &["branch", "tag", "flux_env"];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CondOp {
Eq,
Ne,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Condition {
pub var: String,
pub op: CondOp,
pub value: String,
}
impl Condition {
pub fn evaluate(&self, vars: &HashMap<String, String>) -> bool {
let lhs = vars.get(&self.var).map(String::as_str).unwrap_or("");
match self.op {
CondOp::Eq => lhs == self.value,
CondOp::Ne => lhs != self.value,
}
}
pub fn describe(&self) -> String {
let op = match self.op {
CondOp::Eq => "==",
CondOp::Ne => "!=",
};
format!("{} {} \"{}\"", self.var, op, self.value)
}
}