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