1+ use std:: io:: Read ;
12use std:: time:: Duration ;
23
34use crate :: api_client:: { CodSpeedAPIClient , GetRepositoryVars } ;
@@ -22,7 +23,11 @@ pub struct AuthArgs {
2223#[ derive( Debug , Subcommand ) ]
2324enum 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
4247const 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