use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum RepoMapMode {
#[default]
Override,
Floor,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct RepoMapConfig {
#[serde(default)]
pub mode: RepoMapMode,
#[serde(default)]
pub exceptions: Option<Vec<String>>,
#[serde(default = "default_min_confidence")]
pub min_confidence: f64,
}
pub const REPO_MAP_DEFAULT_EXCEPTIONS: [&str; 4] = ["qa", "security", "devops", "bug_fix"];
pub const REPO_MAP_DEFAULT_MIN_CONFIDENCE: f64 = 0.8;
fn default_min_confidence() -> f64 {
REPO_MAP_DEFAULT_MIN_CONFIDENCE
}
impl RepoMapConfig {
pub fn exceptions(&self) -> Vec<String> {
match &self.exceptions {
Some(list) => list.clone(),
None => REPO_MAP_DEFAULT_EXCEPTIONS
.iter()
.map(|s| s.to_string())
.collect(),
}
}
}
impl Default for RepoMapConfig {
fn default() -> Self {
Self {
mode: RepoMapMode::default(),
exceptions: None,
min_confidence: default_min_confidence(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::config::ClassificationConfig;
fn parse(yaml: &str) -> Result<ClassificationConfig, serde_yaml::Error> {
serde_yaml::from_str(yaml)
}
#[test]
fn the_block_defaults_to_override_and_parses_every_field() {
let absent = parse("repo_categories: {}\n").expect("absent");
assert_eq!(absent.repo_map, RepoMapConfig::default());
assert_eq!(absent.repo_map.mode, RepoMapMode::Override);
assert_eq!(absent.repo_map.exceptions, None);
assert_eq!(absent.repo_map.exceptions(), REPO_MAP_DEFAULT_EXCEPTIONS);
assert!((absent.repo_map.min_confidence - 0.8).abs() < 1e-12);
let empty = parse("repo_map: {}\n").expect("empty");
assert_eq!(empty.repo_map, RepoMapConfig::default());
let full = parse("repo_map:\n mode: floor\n exceptions: [qa]\n min_confidence: 0.9\n")
.expect("full");
assert_eq!(full.repo_map.mode, RepoMapMode::Floor);
assert_eq!(full.repo_map.exceptions(), ["qa"]);
assert!((full.repo_map.min_confidence - 0.9).abs() < 1e-12);
}
#[test]
fn unknown_keys_and_modes_fail_the_load() {
let err = parse("repo_map:\n mode: floor\n min_confidance: 0.9\n")
.expect_err("unknown key")
.to_string();
assert!(err.contains("min_confidance"), "{err}");
let err = parse("repo_map:\n mode: soft\n")
.expect_err("unknown mode")
.to_string();
assert!(err.contains("soft"), "{err}");
}
}