OXYGENHUB

flow: say when a pipeline may be newer than this flow 3b9dddc92057

A pipeline naming a node, output or event this flow does not know was
refused as 'not valid', reading as an error in the pipeline when a
newer one was simply ahead of an older flow. flow check and flow run now
say it uses something this flow (with its version) does not know, and
that a pipeline written for a newer OxygenFlow needs a newer flow.

closes #43
Author
Andy McCall @andymccall <[email protected]>
When
· 2026-10-12 00:20 UTC
Signature
✔ signed by Andy McCall
Hash
3b9dddc92057914023d77830272fd4f996331cfa20899c2977845b926275ada4
Depends on
a72abeeedd78 e0918b887850
Depended on by
nothing yet
In bookmarks
main newer-pipeline push-uses-login
In tags
v0.2.0 v0.3.0 v0.3.1 v0.4.0 v0.5.0 v0.5.1 v0.5.2 v0.5.3
Edits
4 atoms, 0 tree operations, 1 file

Browse the tree at this change

modified crates/flow/src/main.rs +26 −1
…
119 unchanged lines
120 120
121 121
fn load(file: &Path) -> Result<Pipeline> {
122 122
    let src = std::fs::read_to_string(file).with_context(|| format!("read {}", file.display()))?;
123 -
    Pipeline::parse(&src).map_err(|p| anyhow::anyhow!("{} is not valid:\n{p}", file.display()))
123 +
    Pipeline::parse(&src).map_err(|p| anyhow::anyhow!("{}", not_valid(file, &p.to_string())))
124 124
}
125 125
126 +
/// Why a pipeline did not parse. When it names something this flow does
127 +
/// not know (a node, an output, an event), the pipeline may simply be
128 +
/// newer than this flow (oxygenflow#43): say so, with this flow's version.
129 +
fn not_valid(file: &Path, problems: &str) -> String {
130 +
    if problems.contains("unknown ") {
131 +
        format!(
132 +
            "{} uses something this flow ({}) does not know:\n{problems}\n\
133 +
             If the pipeline was written for a newer OxygenFlow, update flow (build it from oxygenflow main); \
134 +
             otherwise fix the lines named.",
135 +
            file.display(),
136 +
            env!("OXY_VERSION_LONG")
137 +
        )
138 +
    } else {
139 +
        format!("{} is not valid:\n{problems}", file.display())
140 +
    }
141 +
}
142 +
126 143
fn check(file: &Path) -> Result<()> {
127 144
    let p = load(file)?;
128 145
    let depths = p.depths();
…
154 unchanged lines
283 300
284 301
#[cfg(test)]
285 302
mod tests {
303 +
    #[test]
304 +
    fn a_pipeline_newer_than_flow_is_named_as_such() {
305 +
        let m = super::not_valid(std::path::Path::new(".flow/pipeline.kdl"), "line 92: unknown output `sbom`; outputs are …");
306 +
        assert!(m.contains("does not know") && m.contains(env!("OXY_VERSION_LONG")) && m.contains("newer OxygenFlow"), "{m}");
307 +
        let m = super::not_valid(std::path::Path::new(".flow/pipeline.kdl"), "line 3: a job needs a sandbox");
308 +
        assert!(m.contains("is not valid") && !m.contains("newer"), "{m}");
309 +
    }
310 +
286 311
    use super::image_env_file;
287 312
288 313
    #[test]
…
9 unchanged lines