cargo-governor 2.0.0

Machine-First, LLM-Ready, CI/CD-Native release automation tool for Rust crates
Documentation
//! Version bump determination logic

use super::analysis::Analysis;
use governor_core::domain::version::BumpType;

/// Determine bump type from analysis
#[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
    }
}

/// Calculate confidence score for bump type
#[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)
}

/// Generate reasoning text for version bump
#[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}.")
        }
    }
}