use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::PathBuf;
use worktrunk::HookType;
use super::hook_filter::HookSource;
#[derive(Serialize, Deserialize)]
pub struct PipelineSpec {
pub worktree_path: PathBuf,
pub branch: String,
pub hook_type: HookType,
pub source: HookSource,
pub context: HashMap<String, String>,
pub steps: Vec<PipelineStepSpec>,
pub log_dir: PathBuf,
}
#[derive(Serialize, Deserialize)]
pub enum PipelineStepSpec {
Single {
name: Option<String>,
template: String,
},
Concurrent {
commands: Vec<PipelineCommandSpec>,
},
}
#[derive(Serialize, Deserialize)]
pub struct PipelineCommandSpec {
pub name: Option<String>,
pub template: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pipeline_spec_roundtrip() {
let spec = PipelineSpec {
worktree_path: "/tmp/test-worktree".into(),
branch: "feature/auth".into(),
hook_type: HookType::PostStart,
source: HookSource::User,
context: [("branch".into(), "feature/auth".into())]
.into_iter()
.collect(),
log_dir: "/tmp/test-worktree/.git/wt/logs".into(),
steps: vec![
PipelineStepSpec::Single {
name: Some("install".into()),
template: "npm install".into(),
},
PipelineStepSpec::Concurrent {
commands: vec![
PipelineCommandSpec {
name: Some("build".into()),
template: "npm run build".into(),
},
PipelineCommandSpec {
name: None,
template: "echo {{ vars.tag }}".into(),
},
],
},
],
};
let json = serde_json::to_string(&spec).unwrap();
let roundtripped: PipelineSpec = serde_json::from_str(&json).unwrap();
assert_eq!(roundtripped.worktree_path, spec.worktree_path);
assert_eq!(roundtripped.branch, spec.branch);
assert_eq!(roundtripped.hook_type, spec.hook_type);
assert_eq!(roundtripped.source, spec.source);
assert_eq!(roundtripped.context, spec.context);
assert_eq!(roundtripped.steps.len(), 2);
match &roundtripped.steps[0] {
PipelineStepSpec::Single { name, template } => {
assert_eq!(name.as_deref(), Some("install"));
assert_eq!(template, "npm install");
}
_ => panic!("expected Single step"),
}
match &roundtripped.steps[1] {
PipelineStepSpec::Concurrent { commands } => {
assert_eq!(commands.len(), 2);
assert_eq!(commands[0].name.as_deref(), Some("build"));
assert!(commands[1].template.contains("vars.tag"));
}
_ => panic!("expected Concurrent step"),
}
}
}