Skip to content

Commit 7917f2c

Browse files
committed
feat(auth): add --with-token flag to read token from stdin
1 parent 7e93351 commit 7917f2c

1 file changed

Lines changed: 56 additions & 35 deletions

File tree

src/cli/auth.rs

Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::io::Read;
12
use std::time::Duration;
23

34
use crate::api_client::{CodSpeedAPIClient, GetRepositoryVars};
@@ -22,7 +23,11 @@ pub struct AuthArgs {
2223
#[derive(Debug, Subcommand)]
2324
enum AuthCommands {
2425
/// Login to CodSpeed
25-
Login,
26+
Login {
27+
/// Read the token from standard input instead of running the OAuth flow
28+
#[arg(long)]
29+
with_token: bool,
30+
},
2631
/// Show the authentication status
2732
Status,
2833
}
@@ -33,54 +38,70 @@ pub async fn run(
3338
config_name: Option<&str>,
3439
) -> Result<()> {
3540
match args.command {
36-
AuthCommands::Login => login(api_client, config_name).await?,
41+
AuthCommands::Login { with_token } => login(api_client, config_name, with_token).await?,
3742
AuthCommands::Status => status(api_client).await?,
3843
}
3944
Ok(())
4045
}
4146

4247
const LOGIN_SESSION_MAX_DURATION: Duration = Duration::from_secs(60 * 5); // 5 minutes
4348

44-
async fn login(api_client: &CodSpeedAPIClient, config_name: Option<&str>) -> Result<()> {
49+
async fn login(
50+
api_client: &CodSpeedAPIClient,
51+
config_name: Option<&str>,
52+
with_token: bool,
53+
) -> Result<()> {
4554
debug!("Login to CodSpeed");
46-
start_group!("Creating login session");
47-
let login_session_payload = api_client.create_login_session().await?;
48-
end_group!();
4955

50-
if open::that(&login_session_payload.callback_url).is_ok() {
51-
info!("Your browser has been opened to complete the login process");
56+
let token = if with_token {
57+
let mut buf = String::new();
58+
std::io::stdin().read_to_string(&mut buf)?;
59+
let token = buf.trim().to_owned();
60+
if token.is_empty() {
61+
bail!("No token provided on stdin");
62+
}
63+
token
5264
} else {
53-
warn!("Failed to open the browser automatically, please open the URL manually");
54-
}
55-
info!(
56-
"Authentication URL: {}\n",
57-
style(login_session_payload.callback_url)
58-
.blue()
59-
.bold()
60-
.underlined()
61-
);
62-
63-
start_group!("Waiting for the login to be completed");
64-
let token;
65-
let start = Instant::now();
66-
loop {
67-
if start.elapsed() > LOGIN_SESSION_MAX_DURATION {
68-
bail!("Login session expired, please try again");
65+
start_group!("Creating login session");
66+
let login_session_payload = api_client.create_login_session().await?;
67+
end_group!();
68+
69+
if open::that(&login_session_payload.callback_url).is_ok() {
70+
info!("Your browser has been opened to complete the login process");
71+
} else {
72+
warn!("Failed to open the browser automatically, please open the URL manually");
6973
}
74+
info!(
75+
"Authentication URL: {}\n",
76+
style(login_session_payload.callback_url)
77+
.blue()
78+
.bold()
79+
.underlined()
80+
);
81+
82+
start_group!("Waiting for the login to be completed");
83+
let token;
84+
let start = Instant::now();
85+
loop {
86+
if start.elapsed() > LOGIN_SESSION_MAX_DURATION {
87+
bail!("Login session expired, please try again");
88+
}
7089

71-
match api_client
72-
.consume_login_session(&login_session_payload.session_id)
73-
.await?
74-
.token
75-
{
76-
Some(token_from_api) => {
77-
token = token_from_api;
78-
break;
90+
match api_client
91+
.consume_login_session(&login_session_payload.session_id)
92+
.await?
93+
.token
94+
{
95+
Some(token_from_api) => {
96+
token = token_from_api;
97+
break;
98+
}
99+
None => sleep(Duration::from_secs(5)).await,
79100
}
80-
None => sleep(Duration::from_secs(5)).await,
81101
}
82-
}
83-
end_group!();
102+
end_group!();
103+
token
104+
};
84105

85106
let mut config = CodSpeedConfig::load_with_override(config_name, None)?;
86107
config.auth.token = Some(token);

0 commit comments

Comments
 (0)