huskies: merge 974
This commit is contained in:
@@ -344,6 +344,8 @@ fn map_stage_move_to_event(
|
||||
(Stage::MergeFailure { .. }, "current") => Ok(PipelineEvent::FixupRequested),
|
||||
// Story 972: send MergeFailure story back to Qa for a QA agent to re-review.
|
||||
(Stage::MergeFailure { .. }, "qa") => Ok(PipelineEvent::ReQueuedForQa),
|
||||
// Story 974: reopen a Done story for a post-merge hotfix.
|
||||
(Stage::Done { .. }, "current") => Ok(PipelineEvent::HotfixRequested),
|
||||
(
|
||||
Stage::Archived {
|
||||
reason: ArchiveReason::Blocked { .. },
|
||||
@@ -809,6 +811,61 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
// ── Story 974: Done → Coding hotfix tests ────────────────────────────────
|
||||
|
||||
/// AC1 (story 974): move_story_to_stage to "current" from Done succeeds
|
||||
/// and lands the story in Coding stage so auto-assign can pick it up.
|
||||
#[test]
|
||||
fn move_story_to_stage_from_done_lands_in_coding() {
|
||||
crate::crdt_state::init_for_test();
|
||||
crate::db::ensure_content_store();
|
||||
|
||||
let story_id = "99974_story_hotfix_done_to_coding";
|
||||
crate::db::write_item_with_content(
|
||||
story_id,
|
||||
"done",
|
||||
"---\nname: Hotfix Test\n---\n",
|
||||
crate::db::ItemMeta::named("Hotfix Test"),
|
||||
);
|
||||
|
||||
move_story_to_stage(story_id, "current").expect("move from Done to Coding must succeed");
|
||||
|
||||
let item = crate::pipeline_state::read_typed(story_id)
|
||||
.expect("CRDT read must succeed")
|
||||
.expect("item must exist");
|
||||
assert_eq!(
|
||||
item.stage.dir_name(),
|
||||
"coding",
|
||||
"story must be in coding after hotfix move"
|
||||
);
|
||||
}
|
||||
|
||||
/// AC1 (story 974): retry_count is reset to 0 after Done→Coding so the
|
||||
/// fresh coder session starts clean.
|
||||
#[test]
|
||||
fn move_story_from_done_to_coding_resets_retry_count() {
|
||||
crate::crdt_state::init_for_test();
|
||||
crate::db::ensure_content_store();
|
||||
|
||||
let story_id = "99975_story_hotfix_retry_count";
|
||||
crate::db::write_item_with_content(
|
||||
story_id,
|
||||
"done",
|
||||
"---\nname: Hotfix Retry Count\n---\n",
|
||||
crate::db::ItemMeta::named("Hotfix Retry Count"),
|
||||
);
|
||||
|
||||
move_story_to_stage(story_id, "current").expect("move from Done to Coding must succeed");
|
||||
|
||||
let retry_count = crate::crdt_state::read_item(story_id)
|
||||
.expect("CRDT item must exist")
|
||||
.retry_count();
|
||||
assert_eq!(
|
||||
retry_count, 0,
|
||||
"retry_count must be 0 after hotfix move so coder starts fresh"
|
||||
);
|
||||
}
|
||||
|
||||
/// Bug 226: feature_branch_has_unmerged_changes returns false when no
|
||||
/// feature branch exists.
|
||||
#[test]
|
||||
|
||||
@@ -993,4 +993,40 @@ fn move_story_merge_to_current_succeeds() {
|
||||
);
|
||||
}
|
||||
|
||||
// ── Story 974: Done → Coding (hotfix) ─────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn hotfix_requested_from_done_lands_in_coding() {
|
||||
let done = Stage::Done {
|
||||
merged_at: chrono::Utc::now(),
|
||||
merge_commit: sha("abc123"),
|
||||
};
|
||||
let result = transition(done, PipelineEvent::HotfixRequested).unwrap();
|
||||
assert!(
|
||||
matches!(result, Stage::Coding),
|
||||
"Done + HotfixRequested must land in Coding; got: {:?}",
|
||||
result
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hotfix_requested_rejected_from_non_done_stages() {
|
||||
for stage in [
|
||||
Stage::Backlog,
|
||||
Stage::Coding,
|
||||
Stage::Qa,
|
||||
Stage::Merge {
|
||||
feature_branch: fb("feature/story-1"),
|
||||
commits_ahead: nz(1),
|
||||
},
|
||||
] {
|
||||
let result = transition(stage.clone(), PipelineEvent::HotfixRequested);
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"HotfixRequested must be rejected from {:?}",
|
||||
stage
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ── ProjectionError Display ─────────────────────────────────────────
|
||||
|
||||
@@ -74,6 +74,8 @@ pub enum PipelineEvent {
|
||||
ReQueuedForQa,
|
||||
/// Story 973: user aborts an in-flight merge, sending the story back to Coding.
|
||||
MergeAborted,
|
||||
/// Story 974: user re-opens a Done story for a post-merge hotfix, sending it back to Coding.
|
||||
HotfixRequested,
|
||||
}
|
||||
|
||||
// ── Per-node execution events ───────────────────────────────────────────────
|
||||
@@ -120,6 +122,7 @@ pub fn event_label(e: &PipelineEvent) -> &'static str {
|
||||
PipelineEvent::FixupRequested => "FixupRequested",
|
||||
PipelineEvent::ReQueuedForQa => "ReQueuedForQa",
|
||||
PipelineEvent::MergeAborted => "MergeAborted",
|
||||
PipelineEvent::HotfixRequested => "HotfixRequested",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,6 +319,12 @@ pub fn transition(state: Stage, event: PipelineEvent) -> Result<Stage, Transitio
|
||||
// ── MergeAborted: Merge → Coding (abort in-flight merge) ─────────
|
||||
(Merge { .. }, MergeAborted) => Ok(Coding),
|
||||
|
||||
// ── HotfixRequested: Done → Coding (post-merge hotfix) ───────────
|
||||
// Allows reopening a completed story so a coder can apply a hotfix.
|
||||
// A fresh feature branch is forked from master when auto-assign spawns
|
||||
// the coder.
|
||||
(Done { .. }, HotfixRequested) => Ok(Coding),
|
||||
|
||||
// ── MergemasterAttempted: MergeFailure → MergeFailureFinal ─────
|
||||
(MergeFailure { reason, .. }, MergemasterAttempted) => Ok(MergeFailureFinal { reason }),
|
||||
(MergeFailureFinal { reason }, MergemasterAttempted) => Ok(MergeFailureFinal { reason }),
|
||||
|
||||
Reference in New Issue
Block a user