use std::{fmt::Debug, io::sink};
use itertools::Itertools;
use miette::Diagnostic;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::{state::RunType, step, step::Step, State};
#[derive(Debug, Deserialize, Serialize)]
pub(crate) struct Workflow {
pub(crate) name: String,
pub(crate) help_text: Option<String>,
pub(crate) steps: Vec<Step>,
}
impl Workflow {
pub(crate) fn set_prerelease_label(&mut self, prerelease_label: &str) {
for step in &mut self.steps {
step.set_prerelease_label(prerelease_label);
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum Verbose {
Yes,
No,
}
impl From<bool> for Verbose {
fn from(verbose: bool) -> Self {
if verbose {
Verbose::Yes
} else {
Verbose::No
}
}
}
#[derive(Debug, Error, Diagnostic)]
#[error("There are problems with the defined workflows")]
pub struct ValidationErrorCollection {
#[related]
errors: Vec<Error>,
}
#[derive(Debug, thiserror::Error, Diagnostic)]
#[error("Problem with workflow {name}")]
pub struct Error {
name: String,
#[related]
inner: Box<[step::Error; 1]>,
}
pub(crate) fn run(workflow: Workflow, mut state: RunType) -> Result<(), Error> {
for step in workflow.steps {
state = match step.run(state) {
Ok(state) => state,
Err(err) => {
return Err(Error {
name: workflow.name,
inner: Box::new([err]),
});
}
};
}
Ok(())
}
#[allow(clippy::needless_pass_by_value)] pub(crate) fn validate(
workflows: Vec<Workflow>,
state: State,
) -> Result<(), ValidationErrorCollection> {
let errors = workflows
.into_iter()
.filter_map(|workflow| {
run(
workflow,
RunType::DryRun {
state: state.clone(),
stdout: Box::new(sink()),
},
)
.err()
})
.collect_vec();
if errors.is_empty() {
Ok(())
} else {
Err(ValidationErrorCollection { errors })
}
}
impl std::fmt::Display for Workflow {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", &self.name)
}
}