use std::path::{Path, PathBuf};
use crate::types::StageMode;
use worktrunk::git::Repository;
pub fn resolve_stage_mode(flag: Option<StageMode>, repo: &Repository) -> StageMode {
if let Some(mode) = flag {
return mode;
}
project_config_path(repo)
.and_then(|p| stage_from_file(&p))
.or_else(|| user_config_path().and_then(|p| stage_from_file(&p)))
.unwrap_or(StageMode::All)
}
fn project_config_path(repo: &Repository) -> Option<PathBuf> {
repo.project_config_path().ok().flatten()
}
fn user_config_path() -> Option<PathBuf> {
worktrunk::config::config_path()
}
fn stage_from_file(path: &Path) -> Option<StageMode> {
let text = std::fs::read_to_string(path).ok()?;
let value: toml::Value = text.parse().ok()?;
match value.get("wip")?.get("stage")?.as_str()? {
"all" => Some(StageMode::All),
"tracked" => Some(StageMode::Tracked),
"none" => Some(StageMode::None),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::testutil::with_env_config;
use std::fs;
use std::process::Command;
fn temp_repo() -> (tempfile::TempDir, Repository) {
let dir = tempfile::tempdir().unwrap();
let ok = Command::new("git")
.args(["init", "-b", "main"])
.current_dir(dir.path())
.status()
.unwrap()
.success();
assert!(ok);
let repo = Repository::at(dir.path()).unwrap();
(dir, repo)
}
#[test]
fn flag_beats_everything() {
let (dir, repo) = temp_repo();
fs::create_dir_all(dir.path().join(".config")).unwrap();
fs::write(
dir.path().join(".config/wt.toml"),
"[wip]\nstage = \"none\"\n",
)
.unwrap();
assert_eq!(
resolve_stage_mode(Some(StageMode::Tracked), &repo),
StageMode::Tracked
);
}
#[test]
fn project_config_applies_without_flag() {
let (dir, repo) = temp_repo();
fs::create_dir_all(dir.path().join(".config")).unwrap();
fs::write(
dir.path().join(".config/wt.toml"),
"[wip]\nstage = \"tracked\"\n",
)
.unwrap();
assert_eq!(resolve_stage_mode(None, &repo), StageMode::Tracked);
}
#[test]
fn missing_config_defaults_to_all() {
let (dir, repo) = temp_repo();
let result = with_env_config(&dir.path().join("no-such-config.toml"), || {
resolve_stage_mode(None, &repo)
});
assert_eq!(result, StageMode::All);
}
#[test]
fn malformed_config_degrades_to_default() {
let (dir, repo) = temp_repo();
fs::create_dir_all(dir.path().join(".config")).unwrap();
fs::write(
dir.path().join(".config/wt.toml"),
"[wip]\nstage = \"banana\"\n",
)
.unwrap();
let result = with_env_config(&dir.path().join("no-such-config.toml"), || {
resolve_stage_mode(None, &repo)
});
assert_eq!(result, StageMode::All);
}
#[test]
fn user_config_applies_without_project_config() {
let (_dir, repo) = temp_repo();
let user_dir = tempfile::tempdir().unwrap();
let user_config = user_dir.path().join("config.toml");
fs::write(&user_config, "[wip]\nstage = \"tracked\"\n").unwrap();
let result = with_env_config(&user_config, || resolve_stage_mode(None, &repo));
assert_eq!(result, StageMode::Tracked);
}
#[test]
fn stage_from_file_parses_all_modes() {
let dir = tempfile::tempdir().unwrap();
for (val, want) in [
("all", StageMode::All),
("tracked", StageMode::Tracked),
("none", StageMode::None),
] {
let p = dir.path().join("c.toml");
fs::write(&p, format!("[wip]\nstage = \"{val}\"\n")).unwrap();
assert_eq!(stage_from_file(&p), Some(want));
}
}
}