story-kit: merge 272_story_clear_merge_error_front_matter_when_story_leaves_merge_stage
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
//! the event so connected clients stay in sync.
|
||||
|
||||
use crate::config::{ProjectConfig, WatcherConfig};
|
||||
use crate::io::story_metadata::clear_front_matter_field;
|
||||
use crate::slog;
|
||||
use notify::{EventKind, RecommendedWatcher, RecursiveMode, Watcher, recommended_watcher};
|
||||
use serde::Serialize;
|
||||
@@ -190,6 +191,15 @@ fn flush_pending(
|
||||
("remove", item.to_string(), format!("story-kit: remove {item}"))
|
||||
};
|
||||
|
||||
// Strip stale merge_failure front matter from any story that has left 4_merge/.
|
||||
for (path, stage) in &additions {
|
||||
if *stage != "4_merge"
|
||||
&& let Err(e) = clear_front_matter_field(path, "merge_failure")
|
||||
{
|
||||
slog!("[watcher] Warning: could not clear merge_failure from {}: {e}", path.display());
|
||||
}
|
||||
}
|
||||
|
||||
slog!("[watcher] flush: {commit_msg}");
|
||||
match git_add_work_and_commit(git_root, &commit_msg) {
|
||||
Ok(committed) => {
|
||||
@@ -672,6 +682,128 @@ mod tests {
|
||||
assert!(rx.try_recv().is_err(), "no event for empty pending map");
|
||||
}
|
||||
|
||||
// ── flush_pending clears merge_failure ─────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn flush_pending_clears_merge_failure_when_leaving_merge_stage() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
init_git_repo(tmp.path());
|
||||
let stage_dir = make_stage_dir(tmp.path(), "2_current");
|
||||
let story_path = stage_dir.join("50_story_retry.md");
|
||||
fs::write(
|
||||
&story_path,
|
||||
"---\nname: Retry Story\nmerge_failure: \"conflicts detected\"\n---\n# Story\n",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (tx, _rx) = tokio::sync::broadcast::channel(16);
|
||||
let mut pending = HashMap::new();
|
||||
pending.insert(story_path.clone(), "2_current".to_string());
|
||||
|
||||
flush_pending(&pending, tmp.path(), &tx);
|
||||
|
||||
let contents = fs::read_to_string(&story_path).unwrap();
|
||||
assert!(
|
||||
!contents.contains("merge_failure"),
|
||||
"merge_failure should be stripped when story lands in 2_current"
|
||||
);
|
||||
assert!(contents.contains("name: Retry Story"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flush_pending_clears_merge_failure_when_moving_to_upcoming() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
init_git_repo(tmp.path());
|
||||
let stage_dir = make_stage_dir(tmp.path(), "1_upcoming");
|
||||
let story_path = stage_dir.join("51_story_reset.md");
|
||||
fs::write(
|
||||
&story_path,
|
||||
"---\nname: Reset Story\nmerge_failure: \"gate failed\"\n---\n# Story\n",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (tx, _rx) = tokio::sync::broadcast::channel(16);
|
||||
let mut pending = HashMap::new();
|
||||
pending.insert(story_path.clone(), "1_upcoming".to_string());
|
||||
|
||||
flush_pending(&pending, tmp.path(), &tx);
|
||||
|
||||
let contents = fs::read_to_string(&story_path).unwrap();
|
||||
assert!(
|
||||
!contents.contains("merge_failure"),
|
||||
"merge_failure should be stripped when story lands in 1_upcoming"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flush_pending_clears_merge_failure_when_moving_to_done() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
init_git_repo(tmp.path());
|
||||
let stage_dir = make_stage_dir(tmp.path(), "5_done");
|
||||
let story_path = stage_dir.join("52_story_done.md");
|
||||
fs::write(
|
||||
&story_path,
|
||||
"---\nname: Done Story\nmerge_failure: \"stale error\"\n---\n# Story\n",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (tx, _rx) = tokio::sync::broadcast::channel(16);
|
||||
let mut pending = HashMap::new();
|
||||
pending.insert(story_path.clone(), "5_done".to_string());
|
||||
|
||||
flush_pending(&pending, tmp.path(), &tx);
|
||||
|
||||
let contents = fs::read_to_string(&story_path).unwrap();
|
||||
assert!(
|
||||
!contents.contains("merge_failure"),
|
||||
"merge_failure should be stripped when story lands in 5_done"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flush_pending_preserves_merge_failure_when_in_merge_stage() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
init_git_repo(tmp.path());
|
||||
let stage_dir = make_stage_dir(tmp.path(), "4_merge");
|
||||
let story_path = stage_dir.join("53_story_merging.md");
|
||||
fs::write(
|
||||
&story_path,
|
||||
"---\nname: Merging Story\nmerge_failure: \"conflicts\"\n---\n# Story\n",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (tx, _rx) = tokio::sync::broadcast::channel(16);
|
||||
let mut pending = HashMap::new();
|
||||
pending.insert(story_path.clone(), "4_merge".to_string());
|
||||
|
||||
flush_pending(&pending, tmp.path(), &tx);
|
||||
|
||||
let contents = fs::read_to_string(&story_path).unwrap();
|
||||
assert!(
|
||||
contents.contains("merge_failure"),
|
||||
"merge_failure should be preserved when story is in 4_merge"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flush_pending_no_op_when_no_merge_failure() {
|
||||
let tmp = TempDir::new().unwrap();
|
||||
init_git_repo(tmp.path());
|
||||
let stage_dir = make_stage_dir(tmp.path(), "2_current");
|
||||
let story_path = stage_dir.join("54_story_clean.md");
|
||||
let original = "---\nname: Clean Story\n---\n# Story\n";
|
||||
fs::write(&story_path, original).unwrap();
|
||||
|
||||
let (tx, _rx) = tokio::sync::broadcast::channel(16);
|
||||
let mut pending = HashMap::new();
|
||||
pending.insert(story_path.clone(), "2_current".to_string());
|
||||
|
||||
flush_pending(&pending, tmp.path(), &tx);
|
||||
|
||||
let contents = fs::read_to_string(&story_path).unwrap();
|
||||
assert_eq!(contents, original, "file without merge_failure should be unchanged");
|
||||
}
|
||||
|
||||
// ── stage_for_path (additional edge cases) ────────────────────────────────
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user