1use log::{debug, info, warn};
2use octocrab::Octocrab;
3use std::env;
4use std::error::Error;
5use tokio::process::Command;
6
7const ENV_GH_TOKEN: &str = "GH_TOKEN";
8const ENV_GITHUB_TOKEN: &str = "GITHUB_TOKEN";
9const COMMAND_GH: &str = "gh";
10const COMMAND_GH_AUTH_TOKEN_ARGS: [&str; 2] = ["auth", "token"];
11
12async fn get_github_pat() -> Result<Option<String>, Box<dyn Error>> {
13 let env_gh_token = env::var(ENV_GH_TOKEN);
15 let env_github_token = env::var(ENV_GITHUB_TOKEN);
16 if let Ok(env_token) = env_gh_token.or(env_github_token) {
17 info!("Found GH_TOKEN or GITHUB_TOKEN.");
18 return Ok(Some(env_token));
19 }
20
21 debug!("Falling back to the `gh auth token` command.");
23 let command_result = Command::new(COMMAND_GH)
24 .args(COMMAND_GH_AUTH_TOKEN_ARGS)
25 .output()
26 .await;
27
28 match command_result {
29 Ok(command_output) if command_output.status.success() => {
30 info!("Retrieved a token from the `gh auth token` command.");
31 return Ok(Some(
32 String::from_utf8(command_output.stdout)?.trim().to_string(),
33 ));
34 }
35 Ok(command_output) => {
36 debug!(
37 "The `gh auth token` command failed with {}.",
38 command_output.status
39 );
40 }
41 Err(e) => {
42 debug!("Could not run the `gh` command: {}.", e);
43 }
44 }
45
46 warn!(
48 "Failed to retrieve GitHub Personal Access Token (PAT) from your environment. It will call the API anonymously. Be careful of the API rate limit! You can set the PAT using environment variables (`GH_TOKEN` or `GITHUB_TOKEN`), or log in using the command `gh auth login`."
49 );
50 Ok(None)
51}
52
53pub async fn init_octocrab() -> Result<Octocrab, Box<dyn Error>> {
54 let mut builder = Octocrab::builder();
55
56 let pat_result = get_github_pat().await?;
57 if let Some(pat) = pat_result {
58 debug!("Initializing the GitHub client with a personal access token.");
59 builder = builder.personal_token(pat);
60 }
61
62 Ok(builder.build()?)
63}