huskies: merge 880
This commit is contained in:
@@ -40,6 +40,9 @@ pub struct UpcomingStory {
|
||||
/// Story numbers this story depends on.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub depends_on: Option<Vec<u32>>,
|
||||
/// Epic this item belongs to (numeric ID as string, e.g. "880").
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub epic_id: Option<String>,
|
||||
}
|
||||
|
||||
/// Validation outcome for a single story.
|
||||
@@ -92,17 +95,18 @@ pub fn load_pipeline_state(ctx: &AppContext) -> Result<PipelineState, String> {
|
||||
let sid = &item.story_id.0;
|
||||
let agent = agent_map.get(sid).cloned();
|
||||
|
||||
// Enrich with content-derived metadata (merge_failure, review_hold, qa).
|
||||
let (merge_failure, review_hold, qa) = crate::db::read_content(sid)
|
||||
// Enrich with content-derived metadata (merge_failure, review_hold, qa, epic_id).
|
||||
let (merge_failure, review_hold, qa, epic_id) = crate::db::read_content(sid)
|
||||
.and_then(|c| parse_front_matter(&c).ok())
|
||||
.map(|meta| {
|
||||
(
|
||||
meta.merge_failure,
|
||||
meta.review_hold,
|
||||
meta.qa.map(|m| m.as_str().to_string()),
|
||||
meta.epic,
|
||||
)
|
||||
})
|
||||
.unwrap_or((None, None, None));
|
||||
.unwrap_or((None, None, None, None));
|
||||
|
||||
let story = UpcomingStory {
|
||||
story_id: sid.clone(),
|
||||
@@ -136,6 +140,7 @@ pub fn load_pipeline_state(ctx: &AppContext) -> Result<PipelineState, String> {
|
||||
.collect(),
|
||||
)
|
||||
},
|
||||
epic_id,
|
||||
};
|
||||
match &item.stage {
|
||||
Stage::Upcoming => state.backlog.push(story), // upcoming shown with backlog
|
||||
@@ -201,38 +206,45 @@ pub fn load_upcoming_stories(_ctx: &AppContext) -> Result<Vec<UpcomingStory>, St
|
||||
let mut stories: Vec<UpcomingStory> = typed_items
|
||||
.into_iter()
|
||||
.filter(|item| matches!(item.stage, Stage::Backlog))
|
||||
.map(|item| UpcomingStory {
|
||||
story_id: item.story_id.0,
|
||||
name: if item.name.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(item.name)
|
||||
},
|
||||
error: None,
|
||||
merge_failure: None,
|
||||
agent: None,
|
||||
review_hold: None,
|
||||
qa: None,
|
||||
retry_count: if item.retry_count > 0 {
|
||||
Some(item.retry_count)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
blocked: if item.stage.is_blocked() {
|
||||
Some(true)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
depends_on: if item.depends_on.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
item.depends_on
|
||||
.iter()
|
||||
.filter_map(|d| d.0.split('_').next()?.parse::<u32>().ok())
|
||||
.collect(),
|
||||
)
|
||||
},
|
||||
.map(|item| {
|
||||
let sid = &item.story_id.0;
|
||||
let epic_id = crate::db::read_content(sid)
|
||||
.and_then(|c| parse_front_matter(&c).ok())
|
||||
.and_then(|meta| meta.epic);
|
||||
UpcomingStory {
|
||||
story_id: item.story_id.0.clone(),
|
||||
name: if item.name.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(item.name)
|
||||
},
|
||||
error: None,
|
||||
merge_failure: None,
|
||||
agent: None,
|
||||
review_hold: None,
|
||||
qa: None,
|
||||
retry_count: if item.retry_count > 0 {
|
||||
Some(item.retry_count)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
blocked: if item.stage.is_blocked() {
|
||||
Some(true)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
depends_on: if item.depends_on.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
item.depends_on
|
||||
.iter()
|
||||
.filter_map(|d| d.0.split('_').next()?.parse::<u32>().ok())
|
||||
.collect(),
|
||||
)
|
||||
},
|
||||
epic_id,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
stories.sort_by(|a, b| a.story_id.cmp(&b.story_id));
|
||||
|
||||
Reference in New Issue
Block a user