1use crate::errors::AppError;
6use std::process::Command;
7
8pub fn is_installed() -> bool {
10 Command::new("gh")
11 .arg("--version")
12 .output()
13 .map(|o| o.status.success())
14 .unwrap_or(false)
15}
16
17pub fn is_authenticated() -> bool {
19 Command::new("gh")
20 .args(["auth", "status"])
21 .output()
22 .map(|o| o.status.success())
23 .unwrap_or(false)
24}
25
26pub fn get_token() -> Result<String, AppError> {
28 let output = Command::new("gh")
29 .args(["auth", "token"])
30 .output()
31 .map_err(|e| AppError::auth(format!("Failed to run 'gh auth token': {}", e)))?;
32
33 if !output.status.success() {
34 let stderr = String::from_utf8_lossy(&output.stderr);
35 return Err(AppError::auth(format!(
36 "gh auth token failed: {}",
37 stderr.trim()
38 )));
39 }
40
41 let token = String::from_utf8(output.stdout)
42 .map_err(|_| AppError::auth("Invalid UTF-8 in token output"))?
43 .trim()
44 .to_string();
45
46 if token.is_empty() {
47 return Err(AppError::auth("gh auth token returned empty token"));
48 }
49
50 Ok(token)
51}
52
53pub fn get_username() -> Result<String, AppError> {
55 let output = Command::new("gh")
56 .args(["api", "user", "--jq", ".login"])
57 .output()
58 .map_err(|e| AppError::auth(format!("Failed to get username from gh: {}", e)))?;
59
60 if !output.status.success() {
61 let stderr = String::from_utf8_lossy(&output.stderr);
62 return Err(AppError::auth(format!(
63 "Failed to get username: {}",
64 stderr.trim()
65 )));
66 }
67
68 let username = String::from_utf8(output.stdout)
69 .map_err(|_| AppError::auth("Invalid UTF-8 in username output"))?
70 .trim()
71 .to_string();
72
73 if username.is_empty() {
74 return Err(AppError::auth("gh returned empty username"));
75 }
76
77 Ok(username)
78}
79
80pub fn get_token_for_host(host: &str) -> Result<String, AppError> {
82 let output = Command::new("gh")
83 .args(["auth", "token", "--hostname", host])
84 .output()
85 .map_err(|e| {
86 AppError::auth(format!(
87 "Failed to run 'gh auth token --hostname {}': {}",
88 host, e
89 ))
90 })?;
91
92 if !output.status.success() {
93 let stderr = String::from_utf8_lossy(&output.stderr);
94 return Err(AppError::auth(format!(
95 "gh auth token for {} failed: {}",
96 host,
97 stderr.trim()
98 )));
99 }
100
101 let token = String::from_utf8(output.stdout)
102 .map_err(|_| AppError::auth("Invalid UTF-8 in token output"))?
103 .trim()
104 .to_string();
105
106 if token.is_empty() {
107 return Err(AppError::auth(format!(
108 "gh auth token for {} returned empty token",
109 host
110 )));
111 }
112
113 Ok(token)
114}
115
116#[cfg(test)]
117#[path = "gh_cli_tests.rs"]
118mod tests;