use std::collections::HashMap;
use rite_model::{ArtifactId, MaterialId, ParamId, RoleId, StepOutcome};
use crate::actions::ArtifactValue;
#[derive(Debug)]
pub struct ExecutionState {
pub params: HashMap<ParamId, serde_json::Value>,
pub roles: HashMap<RoleId, String>,
pub materials: HashMap<MaterialId, String>,
pub dry_run: bool,
pub artifacts: HashMap<ArtifactId, ArtifactValue>,
}
fn resolve_role_in(roles: &HashMap<RoleId, String>, role_id: &RoleId) -> String {
roles
.get(role_id)
.cloned()
.unwrap_or_else(|| role_id.as_str().to_string())
}
impl ExecutionState {
#[must_use]
pub fn new(
params: HashMap<ParamId, serde_json::Value>,
roles: HashMap<RoleId, String>,
materials: HashMap<MaterialId, String>,
dry_run: bool,
) -> Self {
Self {
params,
roles,
materials,
dry_run,
artifacts: HashMap::new(),
}
}
#[must_use]
pub fn handler_context(&self) -> HandlerContext<'_> {
HandlerContext {
params: &self.params,
artifacts: &self.artifacts,
roles: &self.roles,
materials: &self.materials,
}
}
#[must_use]
pub fn with_material(mut self, id: ArtifactId, artifact: ArtifactValue) -> Self {
self.artifacts.insert(id, artifact);
self
}
#[must_use]
pub fn resolve_role(&self, role_id: &RoleId) -> String {
resolve_role_in(&self.roles, role_id)
}
}
#[derive(Debug, Clone, Copy)]
pub struct HandlerContext<'a> {
pub params: &'a HashMap<ParamId, serde_json::Value>,
pub artifacts: &'a HashMap<ArtifactId, ArtifactValue>,
pub roles: &'a HashMap<RoleId, String>,
pub materials: &'a HashMap<MaterialId, String>,
}
impl HandlerContext<'_> {
#[must_use]
pub fn resolve_role(&self, role_id: &RoleId) -> String {
resolve_role_in(self.roles, role_id)
}
#[must_use]
pub fn resolve_role_name(&self, role_name: &str) -> String {
self.resolve_role(&RoleId::new(role_name))
}
#[must_use]
pub fn get_artifact(&self, id: &ArtifactId) -> Option<&ArtifactValue> {
self.artifacts.get(id)
}
#[must_use]
pub fn resolve_material(&self, material_id: &MaterialId) -> Option<&str> {
self.materials.get(material_id).map(String::as_str)
}
}
#[derive(Debug)]
pub struct StepResult {
pub outcome: StepOutcome,
pub artifacts: Vec<(ArtifactId, ArtifactValue)>,
}
impl StepResult {
pub fn completed(message: impl Into<String>) -> Self {
Self {
outcome: StepOutcome::Completed {
message: message.into(),
},
artifacts: Vec::new(),
}
}
pub fn completed_with_artifact(
message: impl Into<String>,
id: ArtifactId,
value: ArtifactValue,
) -> Self {
Self {
outcome: StepOutcome::Completed {
message: message.into(),
},
artifacts: vec![(id, value)],
}
}
#[must_use]
pub fn with_artifact(mut self, id: ArtifactId, value: ArtifactValue) -> Self {
self.artifacts.push((id, value));
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn handler_context_is_read_only_view() {
let mut artifacts = HashMap::new();
artifacts.insert(
ArtifactId::new("test"),
ArtifactValue::Bytes(b"value".to_vec()),
);
let state = ExecutionState {
params: HashMap::new(),
roles: HashMap::new(),
materials: HashMap::new(),
dry_run: true,
artifacts,
};
let ctx = state.handler_context();
assert!(ctx.get_artifact(&ArtifactId::new("test")).is_some());
assert!(ctx.get_artifact(&ArtifactId::new("missing")).is_none());
}
#[test]
fn step_result_builder_pattern() {
let result = StepResult::completed("Done")
.with_artifact(ArtifactId::new("a"), ArtifactValue::Bytes(b"1".to_vec()))
.with_artifact(ArtifactId::new("b"), ArtifactValue::Bytes(b"2".to_vec()));
assert_eq!(result.artifacts.len(), 2);
}
}