use crate::error::{CommandExitCode, Result};
use crate::meta::CargoConfig;
use governor_owners::{OwnersClient, OwnersDiff, resolve_owners, validate_not_empty};
pub struct CheckService {
config: CargoConfig,
client: OwnersClient,
}
impl CheckService {
pub const fn new(config: CargoConfig) -> Self {
Self {
config,
client: OwnersClient::new(),
}
}
pub async fn execute(&self, all: bool) -> Result<CommandExitCode> {
let packages: Vec<_> = if all {
self.config.packages.iter().collect()
} else {
self.config.current_package().into_iter().collect()
};
let mut has_drift = false;
for pkg in packages {
let drift = self.check_package(pkg).await?;
has_drift = has_drift || drift;
}
if has_drift {
Ok(CommandExitCode::DriftDetected)
} else {
Ok(CommandExitCode::Success)
}
}
async fn check_package(&self, pkg: &crate::meta::PackageConfig) -> Result<bool> {
println!("Checking owners for '{}'...", pkg.name);
let workspace_config = self.config.workspace.as_ref();
let package_config = pkg.owners.as_ref();
if workspace_config.is_none() && package_config.is_none() {
println!(" (no owners configured, skipping)");
println!();
return Ok(false);
}
let resolved = Self::resolve_owners(pkg, workspace_config);
if let Err(e) = validate_not_empty(&resolved.owners, &pkg.name) {
eprintln!(" Error: {e}");
return Ok(true);
}
let current_owners = self.fetch_current_owners(&pkg.name).await;
let current = match current_owners {
Ok(owners) => owners,
Err(e) => {
eprintln!(" Error: {e}");
return Ok(true);
}
};
let diff = OwnersDiff::calculate(¤t, &resolved.owners);
if diff.is_empty() {
println!(" OK: Owners match configuration.");
} else {
println!(" Drift detected:");
println!("{diff}");
println!(" Run 'cargo governor owners sync' to apply changes.");
}
println!();
Ok(!diff.is_empty())
}
fn resolve_owners(
pkg: &crate::meta::PackageConfig,
workspace_config: Option<&governor_owners::WorkspaceOwnersConfig>,
) -> governor_owners::ResolvedOwners {
let workspace = workspace_config.cloned().unwrap_or_default();
let package = pkg.owners.clone().unwrap_or_default();
resolve_owners(&workspace, &package)
}
async fn fetch_current_owners(&self, crate_name: &str) -> Result<Vec<String>> {
self.client
.list_owners(crate_name)
.await
.map_err(|e| crate::error::Error::Owners(e.to_string()))
}
}