use std::path::PathBuf;
use serde::Serialize;
use crate::config::RuntimeOptionOverrides;
use crate::context;
use crate::{
ActionPlan, Config, EnvironmentInput, Error, InitScriptDiscovery, Result, Worktree,
WorktreeOptions,
};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct CheckOptions {
pub cwd: Option<PathBuf>,
pub root: Option<PathBuf>,
pub environment: EnvironmentInput,
pub config: Option<PathBuf>,
pub no_init_script: bool,
pub strict: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum CheckAction {
MissingConfig,
RootWorktreeSkipped,
InitScript {
path: PathBuf,
},
Config {
path: PathBuf,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct CheckReport {
pub context: WorktreeSnapshot,
pub action: CheckAction,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct WorktreeSnapshot {
pub root_path: PathBuf,
pub worktree_path: PathBuf,
pub default_branch: String,
}
impl From<&Worktree> for WorktreeSnapshot {
fn from(context: &Worktree) -> Self {
Self {
root_path: context.root_path.clone(),
worktree_path: context.worktree_path.clone(),
default_branch: context.default_branch.clone(),
}
}
}
pub fn check(options: CheckOptions) -> Result<CheckReport> {
let env_options = RuntimeOptionOverrides::from_environment(&options.environment)?;
let pre_config_strict = env_options.pre_config_strict(options.strict);
let context = context::resolve(&WorktreeOptions {
cwd: options.cwd.clone(),
root: options.root.clone(),
environment: options.environment.clone(),
})?;
if context.root_path == context.worktree_path {
if pre_config_strict {
return Err(Error::RootWorktreeStrict);
}
return Ok(CheckReport {
context: WorktreeSnapshot::from(&context),
action: CheckAction::RootWorktreeSkipped,
});
}
if options.config.is_none() && !options.no_init_script {
let scripts = InitScriptDiscovery::discover(&context);
if let Some(path) = scripts.executable {
return Ok(CheckReport {
context: WorktreeSnapshot::from(&context),
action: CheckAction::InitScript { path },
});
}
}
match Config::discover_path(&context, options.config.as_deref())? {
Some(path) => {
let config = Config::load(&path, &context)?;
let plan_options = env_options.resolve(&config.options, options.strict);
ActionPlan::from_manifest(&path, &config, &context, plan_options.into())?;
Ok(CheckReport {
context: WorktreeSnapshot::from(&context),
action: CheckAction::Config { path },
})
}
None => {
if pre_config_strict {
Err(Error::NoConfigDetectedStrict)
} else {
Ok(CheckReport {
context: WorktreeSnapshot::from(&context),
action: CheckAction::MissingConfig,
})
}
}
}
}