use std::path::{Path, PathBuf};
use std::process::Command;
use serde_json::json;
use crate::doctor::check::CheckResult;
use super::Ctx;
const BUILD_COMMIT: &str = env!("ORCHESTRATECTL_GIT_COMMIT");
pub fn check(_ctx: &Ctx) -> Vec<CheckResult> {
vec![result_for(BUILD_COMMIT, repository_head())]
}
fn result_for(build_commit: &str, reference: RepoHead) -> CheckResult {
match reference {
RepoHead::Head(head) if !is_recorded_commit(build_commit) => CheckResult::ok(
"binary.commit",
format!(
"running binary build commit unavailable ({build_commit}); repository comparison unavailable"
),
)
.with_details(json!({
"binary_commit": build_commit,
"repository_head": head,
"comparison": "unavailable",
})),
RepoHead::Head(head) if head == build_commit => CheckResult::ok(
"binary.commit",
format!("running binary commit {build_commit} matches repository HEAD"),
)
.with_details(json!({
"binary_commit": build_commit,
"repository_head": head,
"comparison": "match",
})),
RepoHead::Head(head) => CheckResult::warn(
"binary.commit",
format!(
"running binary commit {build_commit} differs from repository HEAD {head}"
),
"confirm that this is the intended binary for the current orchestratectl checkout",
)
.with_details(json!({
"binary_commit": build_commit,
"repository_head": head,
"comparison": "mismatch",
})),
RepoHead::Unavailable => CheckResult::ok(
"binary.commit",
format!(
"running binary commit {build_commit}; orchestratectl repository HEAD unavailable"
),
)
.with_details(json!({
"binary_commit": build_commit,
"repository_head": null,
"comparison": "unavailable",
})),
RepoHead::NotApplicable => CheckResult::ok(
"binary.commit",
format!(
"running binary commit {build_commit}; repository comparison not applicable"
),
)
.with_details(json!({
"binary_commit": build_commit,
"repository_head": null,
"comparison": "not_applicable",
})),
}
}
fn is_recorded_commit(commit: &str) -> bool {
commit.len() == 40 && commit.bytes().all(|byte| byte.is_ascii_hexdigit())
}
#[derive(Debug, PartialEq, Eq)]
enum RepoHead {
Head(String),
Unavailable,
NotApplicable,
}
fn repository_head() -> RepoHead {
let git = std::ffi::OsStr::new("git");
let cwd = match std::env::current_dir() {
Ok(cwd) => cwd,
Err(_) => return RepoHead::Unavailable,
};
if !cwd.ancestors().any(|path| path.join(".git").exists()) {
return RepoHead::NotApplicable;
}
let top = match git_stdout(git, &cwd, &["rev-parse", "--show-toplevel"]) {
Some(top) => PathBuf::from(top),
None => return RepoHead::Unavailable,
};
if !is_orchestratectl_checkout(&top) {
return RepoHead::NotApplicable;
}
match git_stdout(git, &top, &["rev-parse", "HEAD"]) {
Some(head) => RepoHead::Head(head),
None => RepoHead::Unavailable,
}
}
fn git_stdout(git: &std::ffi::OsStr, dir: &Path, args: &[&str]) -> Option<String> {
let output = Command::new(git)
.arg("-C")
.arg(dir)
.args(args)
.output()
.ok()?;
if !output.status.success() {
return None;
}
let stdout = String::from_utf8(output.stdout).ok()?;
let value = stdout.trim();
(!value.is_empty()).then(|| value.to_owned())
}
fn is_orchestratectl_checkout(root: &Path) -> bool {
let workspace = root.join("Cargo.toml");
let cli_manifest = root.join("crates/octl-cli/Cargo.toml");
if !workspace.is_file() || !cli_manifest.is_file() {
return false;
}
let Ok(body) = std::fs::read_to_string(cli_manifest) else {
return false;
};
let Ok(manifest) = body.parse::<toml::Value>() else {
return false;
};
manifest
.get("package")
.and_then(|package| package.get("name"))
.and_then(toml::Value::as_str)
== Some("orchestratectl")
}
#[cfg(test)]
mod tests {
use super::*;
use crate::doctor::check::CheckStatus;
#[test]
fn unrecorded_build_commit_is_not_a_false_mismatch() {
let result = result_for(
"unknown",
RepoHead::Head("1111111111111111111111111111111111111111".into()),
);
assert_eq!(result.status, CheckStatus::Ok);
let details = result.details.unwrap();
assert_eq!(details["comparison"], "unavailable");
assert_eq!(
details["repository_head"],
"1111111111111111111111111111111111111111"
);
}
#[test]
fn this_checkout_is_recognised() {
let root = Path::new(env!("CARGO_MANIFEST_DIR"))
.ancestors()
.nth(2)
.expect("workspace root");
assert!(is_orchestratectl_checkout(root), "{}", root.display());
}
}