pub mod commits;
pub mod impact;
pub mod recommendations;
pub mod version;
pub use commits::analyze_commits;
pub use impact::simulate_downstream_impact;
pub use recommendations::generate_recommendations;
pub use version::{create_version_diff, determine_target_version, get_current_version};
use crate::cli::{OutputFormat, SimulateOpts};
use crate::error::{CommandExitCode, Result};
use governor_core::domain::version::SemanticVersion;
use governor_core::traits::source_control::SourceControl;
use governor_git::GitAdapter;
use serde_json::json;
use std::path::PathBuf;
pub struct SimulateService {
workspace_path: String,
opts: SimulateOpts,
}
impl SimulateService {
pub const fn new(workspace_path: String, opts: SimulateOpts) -> Self {
Self {
workspace_path,
opts,
}
}
pub async fn execute(&self, _format: OutputFormat) -> Result<CommandExitCode> {
let start_time = std::time::Instant::now();
let current_version_str = get_current_version(&self.workspace_path)?;
let current = SemanticVersion::parse(¤t_version_str).map_err(|e| {
crate::error::Error::Version(format!("Failed to parse current version: {e}"))
})?;
let target_version =
determine_target_version(&self.workspace_path, self.opts.version.as_deref(), ¤t)
.await?;
let config = governor_git::GitAdapterConfig {
repository_path: Some(PathBuf::from(&self.workspace_path)),
..Default::default()
};
let git = GitAdapter::open(config).map_err(|e| {
crate::error::Error::Config(format!("Failed to open git repository: {e}"))
})?;
let commits = git
.get_commits_since(None)
.await
.map_err(|e| crate::error::Error::Git(format!("Failed to get commits: {e}")))?;
let (breaking, features, fixes, other) = analyze_commits(&commits);
let downstream_count = self.opts.downstream_crates.unwrap_or(0);
let downstream_impact = if downstream_count > 0 {
simulate_downstream_impact(downstream_count, &target_version)
} else {
Vec::new()
};
let version_diff = create_version_diff(¤t, &target_version);
let response = json!({
"success": true,
"command": "simulate",
"workspace": self.workspace_path,
"result": {
"version_diff": version_diff,
"changes": {
"breaking_changes": breaking.len(),
"features": features.len(),
"fixes": fixes.len(),
"other": other,
},
"breaking_details": breaking,
"features_details": features,
"fixes_details": fixes,
"downstream_impact": downstream_impact,
"recommendations": generate_recommendations(breaking.len(), features.len(), fixes.len()),
},
"metrics": {
"execution_time_ms": start_time.elapsed().as_millis(),
"git_operations": 1,
"api_calls": 0,
}
});
println!("{}", serde_json::to_string_pretty(&response).unwrap());
Ok(CommandExitCode::Success)
}
}