From 9bec65baf2eece9421cbe47741a09e5149313d8a Mon Sep 17 00:00:00 2001 From: BFlat Date: Mon, 2 Nov 2026 15:38:16 +0700 Subject: [PATCH] The change summary counts a comparison where files only moved as changed (#345) `app_changes_summarize` decided whether each comparison found changes. For records with `counts` it added added + removed + changed, which left out moves. So an archive or folder comparison whose only difference was a moved file (reported `identical: false`, `moved: 1`) counted as unchanged ("0 of 1 comparisons found changes"). A record's own `identical` verdict now decides when it has one, and moves count otherwise. Archive `counts.changed` keeps its meaning (content-edited files). **Verified:** a new test of the verdict: a move-only comparison is changed (with and without `identical`), and an identical one is not. The engine's compare tests, clippy and fmt pass. Fixes #286 --- crates/engine/src/tools/compare_tools.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/crates/engine/src/tools/compare_tools.rs b/crates/engine/src/tools/compare_tools.rs index 9ad648a8..b8a33034 100644 --- a/crates/engine/src/tools/compare_tools.rs +++ b/crates/engine/src/tools/compare_tools.rs @@ -483,9 +483,13 @@ fn comparison_is_changed(result: &Value) -> bool { if let Some(s) = result.get("overall").and_then(Value::as_str) { return s != "unchanged"; } + // A comparison that says whether the two are identical decides; a moved file counts (#286). + if let Some(same) = result.get("identical").and_then(Value::as_bool) { + return !same; + } if let Some(counts) = result.get("counts") { let n = |k: &str| counts.get(k).and_then(Value::as_u64).unwrap_or(0); - return n("added") + n("removed") + n("changed") > 0; + return n("added") + n("removed") + n("changed") + n("moved") > 0; } false } @@ -779,6 +783,15 @@ mod tests { use craft_anything_testkit as tk; use serde_json::{Value, json}; + /// #286: an archive comparison where a file only moved was summarised as unchanged. + #[test] + fn a_moved_file_is_a_change() { + let moved = json!({"identical": false, "counts": {"added": 0, "removed": 0, "changed": 0, "moved": 1, "unchanged": 0}}); + assert!(super::comparison_is_changed(&moved)); + assert!(super::comparison_is_changed(&json!({"counts": {"moved": 1}}))); + assert!(!super::comparison_is_changed(&json!({"identical": true, "counts": {"unchanged": 3}}))); + } + fn call_val(e: &Engine, id: &str, p: Value) -> Result { e.call(id, p, CallOptions::new(Caller::Cli)).map(|o| o.to_json()) }