use std::fmt::Debug;
use std::io::sink;
use itertools::Itertools;
use miette::Diagnostic;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::state::RunType;
use crate::step::{Step, StepError};
use crate::State;
#[derive(Deserialize, Debug, Serialize)]
pub(crate) struct Workflow {
pub(crate) name: 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(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: [StepError; 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: [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)
}
}