From cc75ed52c133afc59565e06a29446f595aa3e838 Mon Sep 17 00:00:00 2001 From: Sir Starch Date: Sun, 11 Oct 2026 22:54:24 +0200 Subject: [PATCH] fix(cli): skip recorded batch view and save steps (#3058) (#3143) Co-authored-by: Brandon Thomas Co-authored-by: Claude Opus 5.5 --- apps/photocraft-cli/src/lib.rs | 3 +++ apps/photocraft-cli/tests/cli.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/apps/photocraft-cli/src/lib.rs b/apps/photocraft-cli/src/lib.rs index 1cd595b3..4af8839e 100644 --- a/apps/photocraft-cli/src/lib.rs +++ b/apps/photocraft-cli/src/lib.rs @@ -434,6 +434,9 @@ fn batch(a: &Args, out: &mut dyn Write, err: &mut dyn Write) -> R { h.session.actions.list = set.clone(); h.open(input).map_err(|e| e.to_string())?; for (id, p) in &actions { + if photocraft_engine::actions_cmds::shell_view_command(id) || photocraft_engine::actions_cmds::shell_save_command(id) { + continue; + } let r = h.command_run(id, p.clone()).map_err(|e| format!("`{id}`: {e}"))?; // A failed step inside a called action makes this file an error, not a saved result. if let Some(e) = photocraft_engine::actions_cmds::nested_failure(id, &r) { diff --git a/apps/photocraft-cli/tests/cli.rs b/apps/photocraft-cli/tests/cli.rs index a6d5c34e..de04c3bf 100644 --- a/apps/photocraft-cli/tests/cli.rs +++ b/apps/photocraft-cli/tests/cli.rs @@ -264,6 +264,37 @@ fn batch_applies_actions_to_directory() { std::fs::remove_dir_all(d).unwrap(); } +#[test] +fn batch_skips_recorded_view_and_save_steps() { + let d = tmp("batch-shell-steps"); + let input = d.join("in"); + std::fs::create_dir_all(&input).unwrap(); + let source = input.join("a.png"); + write_png(&source, 12, 8, 3); + let original = std::fs::read(&source).unwrap(); + let recorded_save = d.join("recorded-save.psd"); + let mut cases = Vec::new(); + for (name, id) in [("zoom-in", "view.zoomIn"), ("zoom-out", "view.zoomOut"), ("fit", "view.fitOnScreen"), ("actual-pixels", "view.actualPixels")] { + cases.push((name, json!([[id, {}], ["image.imageRotation.90cw", {}]]).to_string())); + } + cases.push(("save", json!([["file.save", {}], ["image.imageRotation.90cw", {}]]).to_string())); + cases.push(("save-as", json!([["file.saveAs", {"path": recorded_save.to_string_lossy()}], ["image.imageRotation.90cw", {}]]).to_string())); + + for (name, actions) in cases { + let o = batch_with(&d, &input, name, &actions, &[]); + let (stdout, stderr) = (String::from_utf8_lossy(&o.stdout), String::from_utf8_lossy(&o.stderr)); + assert!(o.status.success(), "{name}: {stdout}\n{stderr}"); + assert!(stdout.contains("1 succeeded, 0 failed"), "{name}: {stdout}"); + let output = d.join(name).join("a.png"); + let (info, _) = ok(bin().arg("info").arg(&output)); + let info: Value = serde_json::from_str(&info).unwrap(); + assert_eq!((info["width"].as_u64(), info["height"].as_u64()), (Some(8), Some(12)), "{name}: {info}"); + assert_eq!(std::fs::read(&source).unwrap(), original, "{name} changed its input"); + assert!(!recorded_save.exists(), "{name} wrote the recorded Save As path"); + } + std::fs::remove_dir_all(d).unwrap(); +} + #[test] fn parse_actions_formats() { let a = photocraft_cli::parse_actions(r#"[{"command":"a","params":{"x":1}},{"id":"b"}]"#).unwrap();