fix: add --all to cargo fmt in script/test and autoformat codebase
cargo fmt without --all fails with "Failed to find targets" in workspace repos. This was blocking every story's gates. Also ran cargo fmt --all to fix all existing formatting issues. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,18 +1,15 @@
|
||||
//! Pipeline advance — moves stories forward through pipeline stages after agent completion.
|
||||
use crate::config::ProjectConfig;
|
||||
use crate::io::watcher::WatcherEvent;
|
||||
use crate::slog;
|
||||
use crate::slog_error;
|
||||
use crate::slog_warn;
|
||||
use crate::io::watcher::WatcherEvent;
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tokio::sync::broadcast;
|
||||
|
||||
use super::super::super::{
|
||||
CompletionReport, PipelineStage,
|
||||
agent_config_stage, pipeline_stage,
|
||||
};
|
||||
use super::super::super::{CompletionReport, PipelineStage, agent_config_stage, pipeline_stage};
|
||||
use super::super::{AgentPool, StoryAgent};
|
||||
|
||||
impl AgentPool {
|
||||
@@ -66,14 +63,16 @@ impl AgentPool {
|
||||
"[pipeline] Coder '{agent_name}' passed gates for '{story_id}'. \
|
||||
qa: server — moving directly to merge."
|
||||
);
|
||||
if let Err(e) =
|
||||
crate::agents::lifecycle::move_story_to_merge(&project_root, story_id)
|
||||
{
|
||||
if let Err(e) = crate::agents::lifecycle::move_story_to_merge(
|
||||
&project_root,
|
||||
story_id,
|
||||
) {
|
||||
slog_error!(
|
||||
"[pipeline] Failed to move '{story_id}' to 4_merge/: {e}"
|
||||
);
|
||||
} else {
|
||||
self.start_mergemaster_or_block(&project_root, story_id).await;
|
||||
self.start_mergemaster_or_block(&project_root, story_id)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
crate::io::story_metadata::QaMode::Agent => {
|
||||
@@ -81,13 +80,17 @@ impl AgentPool {
|
||||
"[pipeline] Coder '{agent_name}' passed gates for '{story_id}'. \
|
||||
qa: agent — moving to QA."
|
||||
);
|
||||
if let Err(e) = crate::agents::lifecycle::move_story_to_qa(&project_root, story_id) {
|
||||
if let Err(e) =
|
||||
crate::agents::lifecycle::move_story_to_qa(&project_root, story_id)
|
||||
{
|
||||
slog_error!("[pipeline] Failed to move '{story_id}' to 3_qa/: {e}");
|
||||
} else if let Err(e) = self
|
||||
.start_agent(&project_root, story_id, Some("qa"), None, None)
|
||||
.await
|
||||
{
|
||||
slog_error!("[pipeline] Failed to start qa agent for '{story_id}': {e}");
|
||||
slog_error!(
|
||||
"[pipeline] Failed to start qa agent for '{story_id}': {e}"
|
||||
);
|
||||
}
|
||||
}
|
||||
crate::io::story_metadata::QaMode::Human => {
|
||||
@@ -95,7 +98,9 @@ impl AgentPool {
|
||||
"[pipeline] Coder '{agent_name}' passed gates for '{story_id}'. \
|
||||
qa: human — holding for human review."
|
||||
);
|
||||
if let Err(e) = crate::agents::lifecycle::move_story_to_qa(&project_root, story_id) {
|
||||
if let Err(e) =
|
||||
crate::agents::lifecycle::move_story_to_qa(&project_root, story_id)
|
||||
{
|
||||
slog_error!("[pipeline] Failed to move '{story_id}' to 3_qa/: {e}");
|
||||
} else {
|
||||
write_review_hold_to_store(story_id);
|
||||
@@ -104,7 +109,8 @@ impl AgentPool {
|
||||
}
|
||||
} else {
|
||||
// Increment retry count and check if blocked.
|
||||
if let Some(reason) = should_block_story(story_id, config.max_retries, "coder") {
|
||||
if let Some(reason) = should_block_story(story_id, config.max_retries, "coder")
|
||||
{
|
||||
// Story has exceeded retry limit — do not restart.
|
||||
let _ = self.watcher_tx.send(WatcherEvent::StoryBlocked {
|
||||
story_id: story_id.to_string(),
|
||||
@@ -144,13 +150,14 @@ impl AgentPool {
|
||||
.clone()
|
||||
.unwrap_or_else(|| project_root.clone());
|
||||
let cp = coverage_path.clone();
|
||||
let coverage_result =
|
||||
tokio::task::spawn_blocking(move || crate::agents::gates::run_coverage_gate(&cp))
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
slog_warn!("[pipeline] Coverage gate task panicked: {e}");
|
||||
Ok((false, format!("Coverage gate task panicked: {e}")))
|
||||
});
|
||||
let coverage_result = tokio::task::spawn_blocking(move || {
|
||||
crate::agents::gates::run_coverage_gate(&cp)
|
||||
})
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
slog_warn!("[pipeline] Coverage gate task panicked: {e}");
|
||||
Ok((false, format!("Coverage gate task panicked: {e}")))
|
||||
});
|
||||
let (coverage_passed, coverage_output) = match coverage_result {
|
||||
Ok(pair) => pair,
|
||||
Err(e) => (false, e),
|
||||
@@ -184,17 +191,21 @@ impl AgentPool {
|
||||
"[pipeline] QA passed gates and coverage for '{story_id}'. \
|
||||
Moving directly to merge."
|
||||
);
|
||||
if let Err(e) =
|
||||
crate::agents::lifecycle::move_story_to_merge(&project_root, story_id)
|
||||
{
|
||||
if let Err(e) = crate::agents::lifecycle::move_story_to_merge(
|
||||
&project_root,
|
||||
story_id,
|
||||
) {
|
||||
slog_error!(
|
||||
"[pipeline] Failed to move '{story_id}' to 4_merge/: {e}"
|
||||
);
|
||||
} else {
|
||||
self.start_mergemaster_or_block(&project_root, story_id).await;
|
||||
self.start_mergemaster_or_block(&project_root, story_id)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
} else if let Some(reason) = should_block_story(story_id, config.max_retries, "qa-coverage") {
|
||||
} else if let Some(reason) =
|
||||
should_block_story(story_id, config.max_retries, "qa-coverage")
|
||||
{
|
||||
// Story has exceeded retry limit — do not restart.
|
||||
let _ = self.watcher_tx.send(WatcherEvent::StoryBlocked {
|
||||
story_id: story_id.to_string(),
|
||||
@@ -217,7 +228,8 @@ impl AgentPool {
|
||||
slog_error!("[pipeline] Failed to restart qa for '{story_id}': {e}");
|
||||
}
|
||||
}
|
||||
} else if let Some(reason) = should_block_story(story_id, config.max_retries, "qa") {
|
||||
} else if let Some(reason) = should_block_story(story_id, config.max_retries, "qa")
|
||||
{
|
||||
// Story has exceeded retry limit — do not restart.
|
||||
let _ = self.watcher_tx.send(WatcherEvent::StoryBlocked {
|
||||
story_id: story_id.to_string(),
|
||||
@@ -272,13 +284,14 @@ impl AgentPool {
|
||||
"[pipeline] Mergemaster completed for '{story_id}'. Running post-merge tests on master."
|
||||
);
|
||||
let root = project_root.clone();
|
||||
let test_result =
|
||||
tokio::task::spawn_blocking(move || crate::agents::gates::run_project_tests(&root))
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
slog_warn!("[pipeline] Post-merge test task panicked: {e}");
|
||||
Ok((false, format!("Test task panicked: {e}")))
|
||||
});
|
||||
let test_result = tokio::task::spawn_blocking(move || {
|
||||
crate::agents::gates::run_project_tests(&root)
|
||||
})
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
slog_warn!("[pipeline] Post-merge test task panicked: {e}");
|
||||
Ok((false, format!("Test task panicked: {e}")))
|
||||
});
|
||||
let (passed, output) = match test_result {
|
||||
Ok(pair) => pair,
|
||||
Err(e) => (false, e),
|
||||
@@ -309,7 +322,9 @@ impl AgentPool {
|
||||
slog!(
|
||||
"[pipeline] Story '{story_id}' done. Worktree preserved for inspection."
|
||||
);
|
||||
} else if let Some(reason) = should_block_story(story_id, config.max_retries, "mergemaster") {
|
||||
} else if let Some(reason) =
|
||||
should_block_story(story_id, config.max_retries, "mergemaster")
|
||||
{
|
||||
// Story has exceeded retry limit — do not restart.
|
||||
let _ = self.watcher_tx.send(WatcherEvent::StoryBlocked {
|
||||
story_id: story_id.to_string(),
|
||||
@@ -564,7 +579,10 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
crate::db::ensure_content_store();
|
||||
crate::db::write_content("9909_story_agent_qa", "---\nname: Test\nqa: agent\n---\ntest");
|
||||
crate::db::write_content(
|
||||
"9909_story_agent_qa",
|
||||
"---\nname: Test\nqa: agent\n---\ntest",
|
||||
);
|
||||
|
||||
let pool = AgentPool::new_test(3001);
|
||||
pool.run_pipeline_advance(
|
||||
@@ -758,10 +776,26 @@ stage = "qa"
|
||||
let root = tmp.path();
|
||||
|
||||
// Init a bare git repo on master with one empty commit.
|
||||
Command::new("git").args(["init"]).current_dir(root).output().unwrap();
|
||||
Command::new("git").args(["config", "user.email", "test@test.com"]).current_dir(root).output().unwrap();
|
||||
Command::new("git").args(["config", "user.name", "Test"]).current_dir(root).output().unwrap();
|
||||
Command::new("git").args(["commit", "--allow-empty", "-m", "init"]).current_dir(root).output().unwrap();
|
||||
Command::new("git")
|
||||
.args(["init"])
|
||||
.current_dir(root)
|
||||
.output()
|
||||
.unwrap();
|
||||
Command::new("git")
|
||||
.args(["config", "user.email", "test@test.com"])
|
||||
.current_dir(root)
|
||||
.output()
|
||||
.unwrap();
|
||||
Command::new("git")
|
||||
.args(["config", "user.name", "Test"])
|
||||
.current_dir(root)
|
||||
.output()
|
||||
.unwrap();
|
||||
Command::new("git")
|
||||
.args(["commit", "--allow-empty", "-m", "init"])
|
||||
.current_dir(root)
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
// Create a feature branch that points at master HEAD (zero commits ahead).
|
||||
// This replicates the incident where the worktree was reset to master.
|
||||
@@ -775,7 +809,11 @@ stage = "qa"
|
||||
let current = root.join(".huskies/work/2_current");
|
||||
fs::create_dir_all(¤t).unwrap();
|
||||
fs::create_dir_all(root.join(".huskies/work/4_merge")).unwrap();
|
||||
fs::write(current.join("9919_story_no_commits.md"), "---\nname: Test\n---\n").unwrap();
|
||||
fs::write(
|
||||
current.join("9919_story_no_commits.md"),
|
||||
"---\nname: Test\n---\n",
|
||||
)
|
||||
.unwrap();
|
||||
crate::db::ensure_content_store();
|
||||
crate::db::write_content("9919_story_no_commits", "---\nname: Test\n---\n");
|
||||
|
||||
@@ -835,8 +873,8 @@ stage = "qa"
|
||||
|
||||
#[tokio::test]
|
||||
async fn pipeline_advance_picks_up_waiting_qa_stories_after_completion() {
|
||||
use std::fs;
|
||||
use super::super::super::auto_assign::is_agent_free;
|
||||
use std::fs;
|
||||
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let root = tmp.path();
|
||||
@@ -908,8 +946,7 @@ stage = "qa"
|
||||
// After pipeline advance, auto_assign should have started QA on story 293.
|
||||
let agents = pool.agents.lock().unwrap();
|
||||
let qa_on_293 = agents.values().any(|a| {
|
||||
a.agent_name == "qa"
|
||||
&& matches!(a.status, AgentStatus::Pending | AgentStatus::Running)
|
||||
a.agent_name == "qa" && matches!(a.status, AgentStatus::Pending | AgentStatus::Running)
|
||||
});
|
||||
assert!(
|
||||
qa_on_293,
|
||||
@@ -940,10 +977,26 @@ stage = "qa"
|
||||
let root = tmp.path();
|
||||
|
||||
// Init a git repo so post-merge tests would pass if they ran.
|
||||
Command::new("git").args(["init"]).current_dir(root).output().unwrap();
|
||||
Command::new("git").args(["config", "user.email", "test@test.com"]).current_dir(root).output().unwrap();
|
||||
Command::new("git").args(["config", "user.name", "Test"]).current_dir(root).output().unwrap();
|
||||
Command::new("git").args(["commit", "--allow-empty", "-m", "init"]).current_dir(root).output().unwrap();
|
||||
Command::new("git")
|
||||
.args(["init"])
|
||||
.current_dir(root)
|
||||
.output()
|
||||
.unwrap();
|
||||
Command::new("git")
|
||||
.args(["config", "user.email", "test@test.com"])
|
||||
.current_dir(root)
|
||||
.output()
|
||||
.unwrap();
|
||||
Command::new("git")
|
||||
.args(["config", "user.name", "Test"])
|
||||
.current_dir(root)
|
||||
.output()
|
||||
.unwrap();
|
||||
Command::new("git")
|
||||
.args(["commit", "--allow-empty", "-m", "init"])
|
||||
.current_dir(root)
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
// Set up pipeline dirs.
|
||||
fs::create_dir_all(root.join(".huskies/work/5_done")).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user