use super::analysis::Analysis;
use governor_core::domain::version::BumpType;
#[must_use]
pub const fn analyze_bump_type(analysis: &Analysis) -> BumpType {
if !analysis.breaking.is_empty() {
BumpType::Major
} else if !analysis.features.is_empty() {
BumpType::Minor
} else if !analysis.fixes.is_empty() {
BumpType::Patch
} else {
BumpType::None
}
}
#[must_use]
pub fn calculate_confidence(analysis: &Analysis, bump_type: BumpType) -> f64 {
let total_changeloggable =
analysis.breaking.len() + analysis.features.len() + analysis.fixes.len();
if total_changeloggable == 0 {
return 0.5;
}
let base_confidence = match bump_type {
BumpType::Major if !analysis.breaking.is_empty() => 0.95,
BumpType::Minor if !analysis.features.is_empty() => 0.90,
BumpType::Patch if !analysis.fixes.is_empty() => 0.85,
_ => 0.70,
};
let total = total_changeloggable + analysis.other;
let conventional_ratio = if total == 0 {
0.0
} else {
#[allow(clippy::cast_precision_loss)]
{
let total_changeloggable_f64 = total_changeloggable as f64;
let total_f64 = total as f64;
total_changeloggable_f64 / total_f64
}
};
base_confidence * 0.5f64.mul_add(conventional_ratio, 0.5)
}
#[must_use]
pub fn generate_reasoning(
analysis: &Analysis,
bump_type: BumpType,
current: &governor_core::domain::version::SemanticVersion,
recommended: &governor_core::domain::version::SemanticVersion,
) -> String {
match bump_type {
BumpType::Major if !analysis.breaking.is_empty() => {
format!(
"Breaking changes detected ({}). Bumping from {} to {}.",
analysis.breaking.len(),
current,
recommended
)
}
BumpType::Minor if !analysis.features.is_empty() => {
format!(
"New features detected ({}). Bumping from {} to {}.",
analysis.features.len(),
current,
recommended
)
}
BumpType::Patch if !analysis.fixes.is_empty() => {
format!(
"Bug fixes detected ({}). Bumping from {} to {}.",
analysis.fixes.len(),
current,
recommended
)
}
_ => {
format!("No significant changes detected. Version remains at {current}.")
}
}
}