Skip to main content

anodizer_core/config/
partial.rs

1use schemars::JsonSchema;
2use serde::{Deserialize, Deserializer, Serialize};
3
4// ---------------------------------------------------------------------------
5// PartialConfig (split/merge CI fan-out)
6// ---------------------------------------------------------------------------
7
8#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
9#[serde(default, deny_unknown_fields)]
10pub struct PartialConfig {
11    /// How to split builds: "os" (by OS, default) or "target" (by full triple).
12    /// "os" groups all arch variants for the same OS into one split job.
13    /// "target" gives each unique target triple its own split job.
14    ///
15    /// The legacy `goos` spelling is accepted as a back-compat alias for `os`
16    /// (folded at parse time, with a deprecation warning); imported configs
17    /// keep loading.
18    #[serde(default, deserialize_with = "deserialize_partial_by")]
19    pub by: Option<String>,
20}
21
22/// Normalize `partial.by` at parse time so the legacy Go-style `goos` spelling
23/// folds into the canonical `os` value. Any other value passes through
24/// unchanged for the central validator (`config::validate_partial`) to accept
25/// or reject. A deprecation warning fires when the alias is hit.
26fn deserialize_partial_by<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
27where
28    D: Deserializer<'de>,
29{
30    let raw = Option::<String>::deserialize(deserializer)?;
31    Ok(raw.map(|v| {
32        if v == "goos" {
33            tracing::warn!(
34                "DEPRECATION: partial.by: 'goos' is renamed to 'os'. The 'goos' \
35                 spelling still works but will be removed in a future release; \
36                 switch to 'os'."
37            );
38            "os".to_string()
39        } else {
40            v
41        }
42    }))
43}
44
45#[cfg(test)]
46mod by_alias_tests {
47    use super::*;
48
49    /// The legacy `goos` spelling folds into the canonical `os` at parse time
50    /// so imported configs keep loading.
51    #[test]
52    fn goos_alias_folds_into_os() {
53        let cfg: PartialConfig = serde_yaml_ng::from_str("by: goos").unwrap();
54        assert_eq!(cfg.by.as_deref(), Some("os"));
55    }
56
57    #[test]
58    fn canonical_os_passes_through() {
59        let cfg: PartialConfig = serde_yaml_ng::from_str("by: os").unwrap();
60        assert_eq!(cfg.by.as_deref(), Some("os"));
61    }
62
63    #[test]
64    fn target_passes_through() {
65        let cfg: PartialConfig = serde_yaml_ng::from_str("by: target").unwrap();
66        assert_eq!(cfg.by.as_deref(), Some("target"));
67    }
68
69    /// A genuinely unknown value is left intact for the central validator
70    /// (`config::validate_partial`) to reject — the alias step only rewrites
71    /// `goos`.
72    #[test]
73    fn unknown_value_passes_through_unchanged() {
74        let cfg: PartialConfig = serde_yaml_ng::from_str("by: bogus").unwrap();
75        assert_eq!(cfg.by.as_deref(), Some("bogus"));
76    }
77}