Skip to main content

migrate_guard/
config.rs

1//! `migrate-guard.toml` parsing.
2
3use crate::error::{GuardError, Result};
4use serde::Deserialize;
5use std::path::{Path, PathBuf};
6
7#[derive(Debug, Deserialize)]
8pub struct Config {
9    #[serde(default = "default_git")]
10    pub git: String,
11    #[serde(default = "default_base")]
12    pub base_ref: String,
13    #[serde(default = "default_globs")]
14    pub reference_globs: Vec<String>,
15    #[serde(rename = "dir", default)]
16    pub dirs: Vec<DirSpec>,
17}
18
19#[derive(Debug, Deserialize, Clone)]
20pub struct DirSpec {
21    pub role: String,
22    pub path: PathBuf,
23}
24
25fn default_git() -> String {
26    "git".into()
27}
28fn default_base() -> String {
29    "main".into()
30}
31fn default_globs() -> Vec<String> {
32    vec!["src/**/*.rs".into()]
33}
34
35impl Config {
36    /// Load `migrate-guard.toml` from `root`.
37    pub fn load(root: &Path) -> Result<Config> {
38        let path = root.join("migrate-guard.toml");
39        let text = std::fs::read_to_string(&path)
40            .map_err(|e| GuardError::Config(format!("reading {}: {e}", path.display())))?;
41        let cfg: Config = toml::from_str(&text)
42            .map_err(|e| GuardError::Config(format!("parsing {}: {e}", path.display())))?;
43        if cfg.dirs.is_empty() {
44            return Err(GuardError::Config("no [[dir]] entries".into()));
45        }
46        Ok(cfg)
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[test]
55    fn parses_full_config() {
56        let tmp = tempfile::tempdir().unwrap();
57        std::fs::write(
58            tmp.path().join("migrate-guard.toml"),
59            r#"
60base_ref = "trunk"
61[[dir]]
62role = "platform"
63path = "backend/migrations"
64[[dir]]
65role = "tenant"
66path = "crates/fastyoke-kernel/migrations_tenant"
67"#,
68        )
69        .unwrap();
70        let cfg = Config::load(tmp.path()).unwrap();
71        assert_eq!(cfg.base_ref, "trunk");
72        assert_eq!(cfg.git, "git"); // default
73        assert_eq!(cfg.dirs.len(), 2);
74        assert_eq!(cfg.dirs[0].role, "platform");
75    }
76
77    #[test]
78    fn rejects_no_dirs() {
79        let tmp = tempfile::tempdir().unwrap();
80        std::fs::write(
81            tmp.path().join("migrate-guard.toml"),
82            "base_ref = \"main\"\n",
83        )
84        .unwrap();
85        assert!(Config::load(tmp.path()).is_err());
86    }
87}