huskies: merge 487_story_display_story_dependencies_in_web_ui_and_chat_commands
This commit is contained in:
@@ -111,6 +111,12 @@ fn build_triage_dump(
|
||||
if let Some(ref mf) = m.merge_failure {
|
||||
fields.push(format!("**merge_failure:** {mf}"));
|
||||
}
|
||||
if let Some(ref deps) = m.depends_on
|
||||
&& !deps.is_empty()
|
||||
{
|
||||
let nums: Vec<String> = deps.iter().map(|n| format!("#{n}")).collect();
|
||||
fields.push(format!("**depends_on:** {}", nums.join(", ")));
|
||||
}
|
||||
if !fields.is_empty() {
|
||||
out.push_str("**Front matter:**\n");
|
||||
for f in &fields {
|
||||
@@ -445,6 +451,23 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn whatsup_shows_depends_on_field() {
|
||||
let tmp = tempfile::TempDir::new().unwrap();
|
||||
write_story_file(
|
||||
tmp.path(),
|
||||
"2_current",
|
||||
"55_story_depends_story.md",
|
||||
"---\nname: Depends Story\ndepends_on: [477, 478]\n---\n",
|
||||
);
|
||||
let output = status_triage_cmd(tmp.path(), "55").unwrap();
|
||||
assert!(
|
||||
output.contains("depends_on") || output.contains("#477"),
|
||||
"should show depends_on field: {output}"
|
||||
);
|
||||
assert!(output.contains("478"), "should list all dependency numbers: {output}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn whatsup_no_worktree_shows_not_created() {
|
||||
let tmp = tempfile::TempDir::new().unwrap();
|
||||
|
||||
@@ -50,6 +50,9 @@ pub struct UpcomingStory {
|
||||
/// True when the story has exceeded its retry limit and will not be auto-assigned.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub blocked: Option<bool>,
|
||||
/// Story numbers this story depends on.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub depends_on: Option<Vec<u32>>,
|
||||
}
|
||||
|
||||
pub struct StoryValidationResult {
|
||||
@@ -143,12 +146,12 @@ fn load_stage_items(
|
||||
.to_string();
|
||||
let contents = fs::read_to_string(&path)
|
||||
.map_err(|e| format!("Failed to read story file {}: {e}", path.display()))?;
|
||||
let (name, error, merge_failure, review_hold, qa, retry_count, blocked) = match parse_front_matter(&contents) {
|
||||
Ok(meta) => (meta.name, None, meta.merge_failure, meta.review_hold, meta.qa.map(|m| m.as_str().to_string()), meta.retry_count, meta.blocked),
|
||||
Err(e) => (None, Some(e.to_string()), None, None, None, None, None),
|
||||
let (name, error, merge_failure, review_hold, qa, retry_count, blocked, depends_on) = match parse_front_matter(&contents) {
|
||||
Ok(meta) => (meta.name, None, meta.merge_failure, meta.review_hold, meta.qa.map(|m| m.as_str().to_string()), meta.retry_count, meta.blocked, meta.depends_on),
|
||||
Err(e) => (None, Some(e.to_string()), None, None, None, None, None, None),
|
||||
};
|
||||
let agent = agent_map.get(&story_id).cloned();
|
||||
stories.push(UpcomingStory { story_id, name, error, merge_failure, agent, review_hold, qa, retry_count, blocked });
|
||||
stories.push(UpcomingStory { story_id, name, error, merge_failure, agent, review_hold, qa, retry_count, blocked, depends_on });
|
||||
}
|
||||
|
||||
stories.sort_by(|a, b| a.story_id.cmp(&b.story_id));
|
||||
@@ -526,6 +529,32 @@ mod tests {
|
||||
assert_eq!(item.agent.as_ref().unwrap().status, "pending");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pipeline_state_includes_depends_on() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let backlog = tmp.path().join(".huskies/work/1_backlog");
|
||||
fs::create_dir_all(&backlog).unwrap();
|
||||
fs::write(
|
||||
backlog.join("20_story_dependent.md"),
|
||||
"---\nname: Dependent Story\ndepends_on: [10, 11]\n---\n",
|
||||
)
|
||||
.unwrap();
|
||||
fs::write(
|
||||
backlog.join("21_story_independent.md"),
|
||||
"---\nname: Independent Story\n---\n",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let ctx = crate::http::context::AppContext::new_test(tmp.path().to_path_buf());
|
||||
let state = load_pipeline_state(&ctx).unwrap();
|
||||
|
||||
let dependent = state.backlog.iter().find(|s| s.story_id == "20_story_dependent").unwrap();
|
||||
assert_eq!(dependent.depends_on, Some(vec![10, 11]));
|
||||
|
||||
let independent = state.backlog.iter().find(|s| s.story_id == "21_story_independent").unwrap();
|
||||
assert_eq!(independent.depends_on, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_upcoming_parses_metadata() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
|
||||
@@ -795,6 +795,7 @@ mod tests {
|
||||
qa: None,
|
||||
retry_count: None,
|
||||
blocked: None,
|
||||
depends_on: None,
|
||||
};
|
||||
let resp = WsResponse::PipelineState {
|
||||
backlog: vec![story],
|
||||
@@ -937,6 +938,7 @@ mod tests {
|
||||
qa: None,
|
||||
retry_count: None,
|
||||
blocked: None,
|
||||
depends_on: None,
|
||||
}],
|
||||
current: vec![UpcomingStory {
|
||||
story_id: "2_story_b".to_string(),
|
||||
@@ -948,6 +950,7 @@ mod tests {
|
||||
qa: None,
|
||||
retry_count: None,
|
||||
blocked: None,
|
||||
depends_on: None,
|
||||
}],
|
||||
qa: vec![],
|
||||
merge: vec![],
|
||||
@@ -961,6 +964,7 @@ mod tests {
|
||||
qa: None,
|
||||
retry_count: None,
|
||||
blocked: None,
|
||||
depends_on: None,
|
||||
}],
|
||||
};
|
||||
let resp: WsResponse = state.into();
|
||||
@@ -1121,6 +1125,7 @@ mod tests {
|
||||
qa: None,
|
||||
retry_count: None,
|
||||
blocked: None,
|
||||
depends_on: None,
|
||||
}],
|
||||
qa: vec![],
|
||||
merge: vec![],
|
||||
|
||||
Reference in New Issue
Block a user