1use std::process::Command;
9
10use crate::error::{Error, Result};
11
12#[derive(Debug, Clone)]
14pub enum Auth {
15 GhCli,
17
18 EnvVar(String),
20
21 Token(String),
23}
24
25impl Auth {
26 #[must_use]
30 pub fn auto() -> Self {
31 if std::env::var("GITHUB_TOKEN").is_ok() {
32 Self::EnvVar("GITHUB_TOKEN".into())
33 } else {
34 Self::GhCli
35 }
36 }
37
38 pub fn resolve(&self) -> Result<String> {
43 match self {
44 Self::GhCli => get_gh_token(),
45 Self::EnvVar(var) => std::env::var(var).map_err(|_| Error::NoToken),
46 Self::Token(t) => Ok(t.clone()),
47 }
48 }
49}
50
51impl Default for Auth {
52 fn default() -> Self {
53 Self::auto()
54 }
55}
56
57fn get_gh_token() -> Result<String> {
59 let output = Command::new("gh").args(["auth", "token"]).output()?;
60
61 if !output.status.success() {
62 return Err(Error::NoToken);
63 }
64
65 let token = String::from_utf8_lossy(&output.stdout).trim().to_string();
66
67 if token.is_empty() {
68 return Err(Error::NoToken);
69 }
70
71 Ok(token)
72}
73
74#[cfg(test)]
75#[allow(clippy::unwrap_used)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn test_auth_auto_prefers_env() {
81 let _auth = Auth::auto();
83 }
84
85 #[test]
86 fn test_token_auth() {
87 let auth = Auth::Token("test_token".into());
88 assert_eq!(auth.resolve().unwrap(), "test_token");
89 }
90}