use std::path::PathBuf;
use std::process::{Command, Stdio};
use anyhow::{bail, Result};
pub fn which(bin: &str) -> Option<PathBuf> {
let path = std::env::var_os("PATH")?;
for dir in std::env::split_paths(&path) {
let candidate = dir.join(bin);
if candidate.is_file() {
return Some(candidate);
}
}
None
}
pub fn gh_auth_ok() -> bool {
if which("gh").is_none() {
return false;
}
Command::new("gh")
.args(["auth", "status"])
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.map(|s| s.success())
.unwrap_or(false)
}
pub fn ensure_gh_auth_and_access(repo: &str) -> Result<()> {
if which("gh").is_none() {
bail!(
"GitHub CLI (`gh`) not found on PATH.\n\
Install from https://cli.github.com, then run `gh auth login`."
);
}
if !gh_auth_ok() {
bail!(
"`gh auth status` failed — run `gh auth login` first.\n\
(Cloning {repo} requires read access.)"
);
}
let access = Command::new("gh")
.args(["api", &format!("repos/{}", repo)])
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.map(|s| s.success())
.unwrap_or(false);
if !access {
bail!(
"your GitHub account doesn't have read access to {repo}.\n\
If you're an in-house contributor, ask the team to add you to the org."
);
}
Ok(())
}