solstice-ci/crates/common/src/job.rs
Till Wegmueller a71f9cc7d1
Initial Commit
Signed-off-by: Till Wegmueller <toasterson@gmail.com>
2025-10-25 20:01:08 +02:00

94 lines
2.4 KiB
Rust

use std::{collections::BTreeMap, fs, path::Path};
use kdl::{KdlDocument, KdlNode};
use miette::{IntoDiagnostic, Report, Result};
#[derive(Debug, Clone)]
pub struct Workflow {
pub name: Option<String>,
pub jobs: BTreeMap<String, Job>,
}
#[derive(Debug, Clone)]
pub struct Job {
pub id: String,
pub runs_on: Option<String>,
pub steps: Vec<Step>,
}
#[derive(Debug, Clone)]
pub struct Step {
pub name: Option<String>,
pub run: String,
}
pub fn parse_workflow_file<P: AsRef<Path>>(path: P) -> Result<Workflow> {
let s = fs::read_to_string(path).into_diagnostic()?;
parse_workflow_str(&s)
}
pub fn parse_workflow_str(s: &str) -> Result<Workflow> {
let doc: KdlDocument = s.parse().into_diagnostic()?;
// Expect a top-level `workflow` node
let wf_node = doc
.nodes()
.iter()
.find(|n| n.name().value() == "workflow")
.ok_or_else(|| Report::msg("missing `workflow {}` root node"))?;
let name = wf_node
.get("name")
.and_then(|e| e.value().as_string())
.map(|s| s.to_string());
// Child nodes are within the workflow node body
let mut jobs = BTreeMap::new();
if let Some(children) = wf_node.children() {
for node in children.nodes().iter() {
if node.name().value() == "job" {
let job = parse_job(node)?;
jobs.insert(job.id.clone(), job);
}
}
}
Ok(Workflow { name, jobs })
}
fn parse_job(node: &KdlNode) -> Result<Job> {
let id = node
.get("id")
.and_then(|e| e.value().as_string())
.map(|s| s.to_string())
.ok_or_else(|| Report::msg("job missing string `id` property"))?;
let runs_on = node
.get("runs_on")
.and_then(|e| e.value().as_string())
.map(|s| s.to_string());
let mut steps = Vec::new();
if let Some(children) = node.children() {
for child in children.nodes() {
if child.name().value() == "step" {
steps.push(parse_step(child)?);
}
}
}
Ok(Job { id, runs_on, steps })
}
fn parse_step(node: &KdlNode) -> Result<Step> {
let run = node
.get("run")
.and_then(|e| e.value().as_string())
.map(|s| s.to_string())
.ok_or_else(|| Report::msg("step missing string `run` property"))?;
let name = node
.get("name")
.and_then(|e| e.value().as_string())
.map(|s| s.to_string());
Ok(Step { name, run })
}