mirror of
https://codeberg.org/Toasterson/solstice-ci.git
synced 2026-04-10 13:20:41 +00:00
94 lines
2.4 KiB
Rust
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 })
|
|
}
|