Move pipeline load into Pipeline::load associated function
Load is the only way to construct a Pipeline, so it reads more
naturally as an associated function on the type it produces.

Also collapses a nested if-let to satisfy clippy::collapsible_if.

Assisted-by: GLM-5.1 via pi
change urnwsxuznztwxnlzqrrwvrswqtyqtkkp
commit ad2726e04f0a00f068c43fe074b9d0805703425e
author Alpha Chen <alpha@kejadlen.dev>
date
parent pkqswvnv
diff --git a/src/ci/lua.rs b/src/ci/lua.rs
index 3440e1d..9081a7f 100644
--- a/src/ci/lua.rs
+++ b/src/ci/lua.rs
@@ -273,14 +273,14 @@ fn run_sh(lua: &Lua, (cmd, opts): (Cmd, Option<ShOpts>)) -> mlua::Result<mlua::V
         .run(opts.unwrap_or_default())
         .map_err(mlua::Error::external)?;
 
-    if let Some(rt) = lua.app_data_ref::<Rc<RuntimeState>>() {
-        if let Some(job) = rt.current_job.borrow().as_ref() {
-            rt.outputs
-                .borrow_mut()
-                .entry(job.clone())
-                .or_default()
-                .push(output.clone());
-        }
+    if let Some(rt) = lua.app_data_ref::<Rc<RuntimeState>>()
+        && let Some(job) = rt.current_job.borrow().as_ref()
+    {
+        rt.outputs
+            .borrow_mut()
+            .entry(job.clone())
+            .or_default()
+            .push(output.clone());
     }
 
     lua.to_value(&output)
@@ -288,7 +288,7 @@ fn run_sh(lua: &Lua, (cmd, opts): (Cmd, Option<ShOpts>)) -> mlua::Result<mlua::V
 
 #[cfg(test)]
 mod tests {
-    use super::super::pipeline::load;
+    use super::super::pipeline::Pipeline;
     use super::*;
 
     #[test]
@@ -300,7 +300,8 @@ mod tests {
         );
         let source = r#"(local ci (require :quire.ci))
 (ci.job :grab [:quire/push] (fn [_] (ci.secret :github_token)))"#;
-        let pipeline = load(source, "ci.fnl", "ci.fnl", secrets).expect("load should succeed");
+        let pipeline =
+            Pipeline::load(source, "ci.fnl", "ci.fnl", secrets).expect("load should succeed");
         let token: String = pipeline.jobs()[0]
             .run_fn
             .call(())
@@ -312,8 +313,8 @@ mod tests {
     fn ci_secret_errors_for_unknown_name() {
         let source = r#"(local ci (require :quire.ci))
 (ci.job :grab [:quire/push] (fn [_] (ci.secret :missing)))"#;
-        let pipeline =
-            load(source, "ci.fnl", "ci.fnl", HashMap::new()).expect("load should succeed");
+        let pipeline = Pipeline::load(source, "ci.fnl", "ci.fnl", HashMap::new())
+            .expect("load should succeed");
         let err = pipeline.jobs()[0]
             .run_fn
             .call::<mlua::Value>(())
@@ -329,8 +330,8 @@ mod tests {
     /// invoke it, and decode the resulting Lua table as ShOutput through
     /// the pipeline's VM via `lua.from_value`.
     fn run_sh_via_job(source: &str) -> ShOutput {
-        let pipeline =
-            load(source, "ci.fnl", "ci.fnl", HashMap::new()).expect("load should succeed");
+        let pipeline = Pipeline::load(source, "ci.fnl", "ci.fnl", HashMap::new())
+            .expect("load should succeed");
         let value: mlua::Value = pipeline.jobs()[0]
             .run_fn
             .call(())
@@ -406,7 +407,7 @@ mod tests {
 
     #[test]
     fn ci_sh_rejects_unknown_opt_key() {
-        let pipeline = load(
+        let pipeline = Pipeline::load(
             r#"(local ci (require :quire.ci))
 (ci.job :go [:quire/push] (fn [_] (ci.sh "echo hi" {:cwdir "/tmp"})))"#,
             "ci.fnl",
@@ -427,7 +428,7 @@ mod tests {
 
     #[test]
     fn ci_sh_rejects_non_sequence_table_as_cmd() {
-        let pipeline = load(
+        let pipeline = Pipeline::load(
             r#"(local ci (require :quire.ci))
 (ci.job :go [:quire/push] (fn [_] (ci.sh {:env {:FOO "bar"}})))"#,
             "ci.fnl",
@@ -448,7 +449,7 @@ mod tests {
 
     #[test]
     fn ci_sh_rejects_empty_argv() {
-        let pipeline = load(
+        let pipeline = Pipeline::load(
             r#"(local ci (require :quire.ci))
 (ci.job :go [:quire/push] (fn [_] (ci.sh [])))"#,
             "ci.fnl",
diff --git a/src/ci/mod.rs b/src/ci/mod.rs
index f735b69..6c8658b 100644
--- a/src/ci/mod.rs
+++ b/src/ci/mod.rs
@@ -67,7 +67,7 @@ impl Ci {
         };
         let name = CI_FNL.to_string();
         let lua_name = format!("{}:{CI_FNL}", commit.sha);
-        let pipeline = pipeline::load(&source, &lua_name, &name, secrets)?;
+        let pipeline = Pipeline::load(&source, &lua_name, &name, secrets)?;
         Ok(Some(pipeline))
     }
 
@@ -175,7 +175,7 @@ fn trigger_ref(
     let name = CI_FNL.to_string();
     let lua_name = format!("{}:{CI_FNL}", push_ref.new_sha);
 
-    match pipeline::load(&source, &lua_name, &name, secrets) {
+    match Pipeline::load(&source, &lua_name, &name, secrets) {
         Ok(_pipeline) => run.transition(RunState::Complete)?,
         Err(e) => {
             run.transition(RunState::Failed)?;
diff --git a/src/ci/pipeline.rs b/src/ci/pipeline.rs
index b4373d6..aa8ddeb 100644
--- a/src/ci/pipeline.rs
+++ b/src/ci/pipeline.rs
@@ -75,7 +75,7 @@ impl Job {
 /// A validated CI pipeline — a job graph that has passed all
 /// structural rules.
 ///
-/// Obtain via `pipeline::load`, which parses the Fennel source and
+/// Obtain via [`Pipeline::load`], which parses the Fennel source and
 /// validates the result. Holding a `Pipeline` is proof that the graph
 /// is sound.
 ///
@@ -117,6 +117,52 @@ impl Pipeline {
             .map(|idx| self.jobs[self.graph[idx]].id.as_str())
             .collect()
     }
+
+    /// Parse and validate a ci.fnl source string into a `Pipeline`.
+    ///
+    /// Delegates evaluation to [`lua::parse`] for the Fennel-side work,
+    /// then runs the post-graph rules over the surviving jobs. Any errors
+    /// found are gathered into a single `LoadError` carrying the source
+    /// for miette to render with inline labels.
+    pub(crate) fn load(
+        source: &str,
+        filename: &str,
+        display: &str,
+        secrets: HashMap<String, SecretString>,
+    ) -> Result<Pipeline> {
+        let fennel = Fennel::new()?;
+        let results = lua::parse(&fennel, source, filename, display, secrets)?;
+
+        let mut errors = Vec::new();
+        let mut jobs = Vec::new();
+        for r in results {
+            match r {
+                Ok(j) => jobs.push(j),
+                Err(e) => errors.push(e),
+            }
+        }
+
+        let (graph, node_index) = build_graph(&jobs);
+
+        if let Err(post) = validate_post_graph(&jobs, &graph) {
+            errors.extend(post);
+        }
+
+        if errors.is_empty() {
+            Ok(Self {
+                jobs,
+                graph,
+                node_index,
+                fennel,
+            })
+        } else {
+            Err(LoadError {
+                src: NamedSource::new(display, source.to_string()),
+                errors,
+            }
+            .into())
+        }
+    }
 }
 
 /// Build the dependency graph for `jobs`. Inputs that don't match a
@@ -140,52 +186,6 @@ fn build_graph(jobs: &[Job]) -> (JobGraph, HashMap<String, NodeIndex>) {
     (graph, node_index)
 }
 
-/// Parse and validate a ci.fnl source string into a `Pipeline`.
-///
-/// Delegates evaluation to [`lua::parse`] for the Fennel-side work,
-/// then runs the post-graph rules over the surviving jobs. Any errors
-/// found are gathered into a single `LoadError` carrying the source
-/// for miette to render with inline labels.
-pub(crate) fn load(
-    source: &str,
-    filename: &str,
-    display: &str,
-    secrets: HashMap<String, SecretString>,
-) -> Result<Pipeline> {
-    let fennel = Fennel::new()?;
-    let results = lua::parse(&fennel, source, filename, display, secrets)?;
-
-    let mut errors = Vec::new();
-    let mut jobs = Vec::new();
-    for r in results {
-        match r {
-            Ok(j) => jobs.push(j),
-            Err(e) => errors.push(e),
-        }
-    }
-
-    let (graph, node_index) = build_graph(&jobs);
-
-    if let Err(post) = validate_post_graph(&jobs, &graph) {
-        errors.extend(post);
-    }
-
-    if errors.is_empty() {
-        Ok(Pipeline {
-            jobs,
-            graph,
-            node_index,
-            fennel,
-        })
-    } else {
-        Err(LoadError {
-            src: NamedSource::new(display, source.to_string()),
-            errors,
-        }
-        .into())
-    }
-}
-
 /// Compute a span covering the given 1-indexed line in `source`.
 /// Returns an empty span at offset 0 when the line is unknown.
 fn span_for_line(source: &str, line: u32) -> SourceSpan {
@@ -344,8 +344,8 @@ mod tests {
     fn load_registers_a_job() {
         let source = r#"(local ci (require :quire.ci))
 (ci.job :test [:quire/push] (fn [_] nil))"#;
-        let pipeline =
-            load(source, "ci.fnl", "ci.fnl", HashMap::new()).expect("load should succeed");
+        let pipeline = Pipeline::load(source, "ci.fnl", "ci.fnl", HashMap::new())
+            .expect("load should succeed");
         let jobs = pipeline.jobs();
         assert_eq!(jobs.len(), 1);
         assert_eq!(jobs[0].id, "test");
@@ -359,8 +359,8 @@ mod tests {
 (ci.job :build [:quire/push] (fn [_] nil))
 (ci.job :test [:build] (fn [_] nil))
 "#;
-        let pipeline =
-            load(source, "ci.fnl", "ci.fnl", HashMap::new()).expect("load should succeed");
+        let pipeline = Pipeline::load(source, "ci.fnl", "ci.fnl", HashMap::new())
+            .expect("load should succeed");
         let jobs = pipeline.jobs();
         assert_eq!(jobs.len(), 2);
         assert_eq!(jobs[0].id, "build");
@@ -377,8 +377,8 @@ mod tests {
 
 
 (ci.job :sixth [:quire/push] (fn [_] nil))";
-        let pipeline =
-            load(source, "ci.fnl", "ci.fnl", HashMap::new()).expect("load should succeed");
+        let pipeline = Pipeline::load(source, "ci.fnl", "ci.fnl", HashMap::new())
+            .expect("load should succeed");
         let lines: Vec<usize> = pipeline
             .jobs()
             .iter()
@@ -389,7 +389,7 @@ mod tests {
 
     #[test]
     fn load_errors_on_bad_fennel() {
-        let result = load("{:bad {:}", "ci.fnl", "ci.fnl", HashMap::new());
+        let result = Pipeline::load("{:bad {:}", "ci.fnl", "ci.fnl", HashMap::new());
         assert!(result.is_err(), "malformed Fennel should fail");
     }
 
diff --git a/src/ci/run.rs b/src/ci/run.rs
index c9f941e..ea3840d 100644
--- a/src/ci/run.rs
+++ b/src/ci/run.rs
@@ -641,8 +641,13 @@ mod tests {
     }
 
     fn load(source: &str) -> Pipeline {
-        super::super::pipeline::load(source, "ci.fnl", "ci.fnl", std::collections::HashMap::new())
-            .expect("load should succeed")
+        super::super::pipeline::Pipeline::load(
+            source,
+            "ci.fnl",
+            "ci.fnl",
+            std::collections::HashMap::new(),
+        )
+        .expect("load should succeed")
     }
 
     #[test]