storkit: merge 387_story_configurable_base_branch_name_in_project_toml

This commit is contained in:
dave
2026-03-25 13:30:48 +00:00
parent 96ebd7ecb8
commit a1a30bcc42
4 changed files with 157 additions and 3 deletions

View File

@@ -30,6 +30,12 @@ pub struct ProjectConfig {
/// Default: 2. Set to 0 to disable retry limits.
#[serde(default = "default_max_retries")]
pub max_retries: u32,
/// Optional base branch name (e.g. "main", "master", "develop").
/// When set, overrides the auto-detection logic (`detect_base_branch`) for all
/// worktree creation, merge operations, and agent prompt `{{base_branch}}` substitution.
/// When not set, the system falls back to `detect_base_branch` (reads current HEAD).
#[serde(default)]
pub base_branch: Option<String>,
}
/// Configuration for the filesystem watcher's sweep behaviour.
@@ -164,6 +170,8 @@ struct LegacyProjectConfig {
max_coders: Option<usize>,
#[serde(default = "default_max_retries")]
max_retries: u32,
#[serde(default)]
base_branch: Option<String>,
}
impl Default for ProjectConfig {
@@ -190,6 +198,7 @@ impl Default for ProjectConfig {
default_coder_model: None,
max_coders: None,
max_retries: default_max_retries(),
base_branch: None,
}
}
}
@@ -235,6 +244,7 @@ impl ProjectConfig {
default_coder_model: legacy.default_coder_model,
max_coders: legacy.max_coders,
max_retries: legacy.max_retries,
base_branch: legacy.base_branch,
};
validate_agents(&config.agent)?;
return Ok(config);
@@ -259,6 +269,7 @@ impl ProjectConfig {
default_coder_model: legacy.default_coder_model,
max_coders: legacy.max_coders,
max_retries: legacy.max_retries,
base_branch: legacy.base_branch,
};
validate_agents(&config.agent)?;
Ok(config)
@@ -271,6 +282,7 @@ impl ProjectConfig {
default_coder_model: legacy.default_coder_model,
max_coders: legacy.max_coders,
max_retries: legacy.max_retries,
base_branch: legacy.base_branch,
})
}
}
@@ -312,7 +324,9 @@ impl ProjectConfig {
.ok_or_else(|| "No agents configured".to_string())?,
};
let bb = base_branch.unwrap_or("master");
let bb = base_branch
.or(self.base_branch.as_deref())
.unwrap_or("master");
let aname = agent.name.as_str();
let render = |s: &str| {
s.replace("{{worktree_path}}", worktree_path)
@@ -858,6 +872,80 @@ runtime = "openai"
assert!(err.contains("unknown runtime 'openai'"));
}
// ── base_branch config ──────────────────────────────────────────────────
#[test]
fn base_branch_defaults_to_none() {
let toml_str = r#"
[[agent]]
name = "coder"
"#;
let config = ProjectConfig::parse(toml_str).unwrap();
assert_eq!(config.base_branch, None);
}
#[test]
fn base_branch_parsed_when_set() {
let toml_str = r#"
base_branch = "main"
[[agent]]
name = "coder"
"#;
let config = ProjectConfig::parse(toml_str).unwrap();
assert_eq!(config.base_branch, Some("main".to_string()));
}
#[test]
fn render_agent_args_uses_config_base_branch_when_caller_passes_none() {
let toml_str = r#"
base_branch = "develop"
[[agent]]
name = "coder"
prompt = "git difftool {{base_branch}}...HEAD"
"#;
let config = ProjectConfig::parse(toml_str).unwrap();
let (_, _, prompt) = config
.render_agent_args("/tmp/wt", "42_foo", None, None)
.unwrap();
assert!(
prompt.contains("develop"),
"Expected 'develop' in prompt, got: {prompt}"
);
}
#[test]
fn render_agent_args_caller_base_branch_takes_precedence_over_config() {
let toml_str = r#"
base_branch = "develop"
[[agent]]
name = "coder"
prompt = "git difftool {{base_branch}}...HEAD"
"#;
let config = ProjectConfig::parse(toml_str).unwrap();
let (_, _, prompt) = config
.render_agent_args("/tmp/wt", "42_foo", None, Some("feature-x"))
.unwrap();
assert!(
prompt.contains("feature-x"),
"Caller-supplied base_branch should win, got: {prompt}"
);
}
#[test]
fn project_toml_has_base_branch_master() {
let manifest_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let project_root = manifest_dir.parent().unwrap();
let config = ProjectConfig::load(project_root).unwrap();
assert_eq!(
config.base_branch,
Some("master".to_string()),
"project.toml must have base_branch = \"master\""
);
}
#[test]
fn project_toml_has_three_sonnet_coders() {
let manifest_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));