story-kit: merge 151_story_split_archived_into_done_and_archived_with_time_based_promotion
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2031,9 +2031,9 @@ fn item_source_dir(project_root: &Path, _item_id: &str) -> PathBuf {
|
||||
project_root.join(".story_kit").join("work").join("1_upcoming")
|
||||
}
|
||||
|
||||
/// Return the archive directory path for a work item (always work/5_archived/).
|
||||
/// Return the done directory path for a work item (always work/5_done/).
|
||||
fn item_archive_dir(project_root: &Path, _item_id: &str) -> PathBuf {
|
||||
project_root.join(".story_kit").join("work").join("5_archived")
|
||||
project_root.join(".story_kit").join("work").join("5_done")
|
||||
}
|
||||
|
||||
/// Move a work item (story, bug, or spike) from `work/1_upcoming/` to `work/2_current/`.
|
||||
@@ -2075,21 +2075,22 @@ pub fn move_story_to_current(project_root: &Path, story_id: &str) -> Result<(),
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Move a story from `work/2_current/` to `work/5_archived/` and auto-commit.
|
||||
/// Move a story from `work/2_current/` to `work/5_done/` and auto-commit.
|
||||
///
|
||||
/// * If the story is in `2_current/`, it is moved to `5_archived/` and committed.
|
||||
/// * If the story is in `4_merge/`, it is moved to `5_archived/` and committed.
|
||||
/// * If the story is already in `5_archived/`, this is a no-op (idempotent).
|
||||
/// * If the story is not found in `2_current/`, `4_merge/`, or `5_archived/`, an error is returned.
|
||||
/// * If the story is in `2_current/`, it is moved to `5_done/` and committed.
|
||||
/// * If the story is in `4_merge/`, it is moved to `5_done/` and committed.
|
||||
/// * If the story is already in `5_done/` or `6_archived/`, this is a no-op (idempotent).
|
||||
/// * If the story is not found in `2_current/`, `4_merge/`, `5_done/`, or `6_archived/`, an error is returned.
|
||||
pub fn move_story_to_archived(project_root: &Path, story_id: &str) -> Result<(), String> {
|
||||
let sk = project_root.join(".story_kit").join("work");
|
||||
let current_path = sk.join("2_current").join(format!("{story_id}.md"));
|
||||
let merge_path = sk.join("4_merge").join(format!("{story_id}.md"));
|
||||
let archived_dir = sk.join("5_archived");
|
||||
let archived_path = archived_dir.join(format!("{story_id}.md"));
|
||||
let done_dir = sk.join("5_done");
|
||||
let done_path = done_dir.join(format!("{story_id}.md"));
|
||||
let archived_path = sk.join("6_archived").join(format!("{story_id}.md"));
|
||||
|
||||
if archived_path.exists() {
|
||||
// Already archived — idempotent, nothing to do.
|
||||
if done_path.exists() || archived_path.exists() {
|
||||
// Already in done or archived — idempotent, nothing to do.
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -2104,17 +2105,17 @@ pub fn move_story_to_archived(project_root: &Path, story_id: &str) -> Result<(),
|
||||
));
|
||||
};
|
||||
|
||||
std::fs::create_dir_all(&archived_dir)
|
||||
.map_err(|e| format!("Failed to create work/5_archived/ directory: {e}"))?;
|
||||
std::fs::rename(&source_path, &archived_path)
|
||||
.map_err(|e| format!("Failed to move story '{story_id}' to 5_archived/: {e}"))?;
|
||||
std::fs::create_dir_all(&done_dir)
|
||||
.map_err(|e| format!("Failed to create work/5_done/ directory: {e}"))?;
|
||||
std::fs::rename(&source_path, &done_path)
|
||||
.map_err(|e| format!("Failed to move story '{story_id}' to 5_done/: {e}"))?;
|
||||
|
||||
let from_dir = if source_path == current_path {
|
||||
"work/2_current/"
|
||||
} else {
|
||||
"work/4_merge/"
|
||||
};
|
||||
slog!("[lifecycle] Moved story '{story_id}' from {from_dir} to work/5_archived/");
|
||||
slog!("[lifecycle] Moved story '{story_id}' from {from_dir} to work/5_done/");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -2192,11 +2193,11 @@ pub fn move_story_to_qa(project_root: &Path, story_id: &str) -> Result<(), Strin
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Move a bug from `work/2_current/` or `work/1_upcoming/` to `work/5_archived/` and auto-commit.
|
||||
/// Move a bug from `work/2_current/` or `work/1_upcoming/` to `work/5_done/` and auto-commit.
|
||||
///
|
||||
/// * If the bug is in `2_current/`, it is moved to `5_archived/` and committed.
|
||||
/// * If the bug is still in `1_upcoming/` (never started), it is moved directly to `5_archived/`.
|
||||
/// * If the bug is already in `5_archived/`, this is a no-op (idempotent).
|
||||
/// * If the bug is in `2_current/`, it is moved to `5_done/` and committed.
|
||||
/// * If the bug is still in `1_upcoming/` (never started), it is moved directly to `5_done/`.
|
||||
/// * If the bug is already in `5_done/`, this is a no-op (idempotent).
|
||||
/// * If the bug is not found anywhere, an error is returned.
|
||||
pub fn close_bug_to_archive(project_root: &Path, bug_id: &str) -> Result<(), String> {
|
||||
let sk = project_root.join(".story_kit").join("work");
|
||||
@@ -2220,12 +2221,12 @@ pub fn close_bug_to_archive(project_root: &Path, bug_id: &str) -> Result<(), Str
|
||||
};
|
||||
|
||||
std::fs::create_dir_all(&archive_dir)
|
||||
.map_err(|e| format!("Failed to create work/5_archived/ directory: {e}"))?;
|
||||
.map_err(|e| format!("Failed to create work/5_done/ directory: {e}"))?;
|
||||
std::fs::rename(&source_path, &archive_path)
|
||||
.map_err(|e| format!("Failed to move bug '{bug_id}' to 5_archived/: {e}"))?;
|
||||
.map_err(|e| format!("Failed to move bug '{bug_id}' to 5_done/: {e}"))?;
|
||||
|
||||
slog!(
|
||||
"[lifecycle] Closed bug '{bug_id}' → work/5_archived/"
|
||||
"[lifecycle] Closed bug '{bug_id}' → work/5_done/"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
@@ -3676,7 +3677,7 @@ mod tests {
|
||||
close_bug_to_archive(root, "2_bug_test").unwrap();
|
||||
|
||||
assert!(!current.join("2_bug_test.md").exists());
|
||||
assert!(root.join(".story_kit/work/5_archived/2_bug_test.md").exists());
|
||||
assert!(root.join(".story_kit/work/5_done/2_bug_test.md").exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -3691,7 +3692,7 @@ mod tests {
|
||||
close_bug_to_archive(root, "3_bug_test").unwrap();
|
||||
|
||||
assert!(!upcoming.join("3_bug_test.md").exists());
|
||||
assert!(root.join(".story_kit/work/5_archived/3_bug_test.md").exists());
|
||||
assert!(root.join(".story_kit/work/5_done/3_bug_test.md").exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -3944,7 +3945,7 @@ mod tests {
|
||||
move_story_to_archived(root, "22_story_test").unwrap();
|
||||
|
||||
assert!(!merge_dir.join("22_story_test.md").exists());
|
||||
assert!(root.join(".story_kit/work/5_archived/22_story_test.md").exists());
|
||||
assert!(root.join(".story_kit/work/5_done/22_story_test.md").exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -4036,10 +4037,10 @@ mod tests {
|
||||
report.success || report.gate_output.contains("Failed to run") || !report.gates_passed,
|
||||
"report should be coherent: {report:?}"
|
||||
);
|
||||
// Story should be archived if gates passed
|
||||
// Story should be in done if gates passed
|
||||
if report.story_archived {
|
||||
let archived = repo.join(".story_kit/work/5_archived/23_test.md");
|
||||
assert!(archived.exists(), "archived file should exist");
|
||||
let done = repo.join(".story_kit/work/5_done/23_test.md");
|
||||
assert!(done.exists(), "done file should exist");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5737,8 +5738,8 @@ theirs
|
||||
assert_eq!(remaining.len(), 1, "only the other story's agent should remain");
|
||||
assert_eq!(remaining[0].story_id, "61_story_other");
|
||||
|
||||
// Story file should be in 5_archived/
|
||||
assert!(root.join(".story_kit/work/5_archived/60_story_cleanup.md").exists());
|
||||
// Story file should be in 5_done/
|
||||
assert!(root.join(".story_kit/work/5_done/60_story_cleanup.md").exists());
|
||||
}
|
||||
|
||||
// ── bug 154: merge worktree installs frontend deps ────────────────────
|
||||
|
||||
Reference in New Issue
Block a user