11mod auth;
22pub ( crate ) mod exec;
33pub ( crate ) mod experimental;
4+ mod profile;
45pub ( crate ) mod run;
56pub ( crate ) mod samply;
67mod setup;
@@ -16,7 +17,7 @@ use std::path::PathBuf;
1617
1718use crate :: {
1819 api_client:: CodSpeedAPIClient ,
19- config:: CodSpeedConfig ,
20+ config:: { CodSpeedConfig , ResolvedProfileConfig } ,
2021 executor:: helpers:: command:: CommandBuilder ,
2122 local_logger:: { CODSPEED_U8_COLOR_CODE , init_local_logger} ,
2223 prelude:: * ,
@@ -41,14 +42,8 @@ fn create_styles() -> Styles {
4142#[ command( version, about = "The CodSpeed CLI tool" , styles = create_styles( ) ) ]
4243pub struct Cli {
4344 /// The URL of the CodSpeed GraphQL API
44- #[ arg(
45- long,
46- env = "CODSPEED_API_URL" ,
47- global = true ,
48- hide = true ,
49- default_value = "https://gql.codspeed.io/"
50- ) ]
51- pub api_url : String ,
45+ #[ arg( long, env = "CODSPEED_API_URL" , global = true , hide = true ) ]
46+ pub api_url : Option < String > ,
5247
5348 /// The OAuth token to use for all requests
5449 #[ arg( long, env = "CODSPEED_OAUTH_TOKEN" , global = true , hide = true ) ]
@@ -60,6 +55,10 @@ pub struct Cli {
6055 #[ arg( long, env = "CODSPEED_CONFIG_NAME" , global = true ) ]
6156 pub config_name : Option < String > ,
6257
58+ /// The CodSpeed profile to use
59+ #[ arg( long, env = "CODSPEED_PROFILE" , global = true ) ]
60+ pub profile : Option < String > ,
61+
6362 /// Path to project configuration file (codspeed.yaml)
6463 /// If provided, loads config from this path. Otherwise, searches for config files
6564 /// in the current directory and upward to the git root.
@@ -88,6 +87,8 @@ enum Commands {
8887 Exec ( Box < exec:: ExecArgs > ) ,
8988 /// Manage the CLI authentication state
9089 Auth ( auth:: AuthArgs ) ,
90+ /// Manage CodSpeed profiles
91+ Profile ( profile:: ProfileArgs ) ,
9192 /// Pre-install the codspeed executors
9293 Setup ( setup:: SetupArgs ) ,
9394 /// Show the overall status of CodSpeed (authentication, tools, system)
@@ -130,7 +131,8 @@ impl InternalCommands {
130131
131132pub async fn run ( ) -> Result < ( ) > {
132133 let cli = Cli :: parse ( ) ;
133- let mut api_client = build_api_client ( & cli) ?;
134+ let resolved_profile = resolve_profile_config ( & cli) ?;
135+ let mut api_client = build_api_client ( & cli, & resolved_profile) ;
134136
135137 // Discover project configuration file
136138 let discovered_config = DiscoveredProjectConfig :: discover_and_load (
@@ -158,6 +160,7 @@ pub async fn run() -> Result<()> {
158160 run:: run (
159161 * args,
160162 & mut api_client,
163+ & resolved_profile,
161164 discovered_config. as_ref ( ) ,
162165 setup_cache_dir,
163166 )
@@ -168,14 +171,33 @@ pub async fn run() -> Result<()> {
168171 exec:: run (
169172 * args,
170173 & mut api_client,
174+ & resolved_profile,
171175 discovered_config. as_ref ( ) . map ( |d| & d. config ) ,
172176 setup_cache_dir,
173177 )
174178 . await ?
175179 }
176- Commands :: Auth ( args) => auth:: run ( args, & api_client, cli. config_name . as_deref ( ) ) . await ?,
180+ Commands :: Auth ( args) => {
181+ auth:: run (
182+ args,
183+ & api_client,
184+ cli. config_name . as_deref ( ) ,
185+ & resolved_profile. name ,
186+ )
187+ . await ?
188+ }
189+ Commands :: Profile ( args) => {
190+ profile:: run ( args, cli. config_name . as_deref ( ) , cli. profile . as_deref ( ) ) ?
191+ }
177192 Commands :: Setup ( args) => setup:: run ( args, setup_cache_dir) . await ?,
178- Commands :: Status => status:: run ( & api_client) . await ?,
193+ Commands :: Status => {
194+ status:: run (
195+ & api_client,
196+ cli. config_name . as_deref ( ) ,
197+ & resolved_profile. name ,
198+ )
199+ . await ?
200+ }
179201 Commands :: Use ( args) => use_mode:: run ( args) ?,
180202 Commands :: Show => show:: run ( ) ?,
181203 Commands :: Update => update:: run ( ) . await ?,
@@ -193,28 +215,35 @@ pub async fn run() -> Result<()> {
193215/// Priority (most specific first):
194216/// 1. `--token` / `CODSPEED_TOKEN` — run/exec-level override
195217/// 2. `--oauth-token` / `CODSPEED_OAUTH_TOKEN` and the persisted CLI
196- /// token — both live on disk and are loaded together by
197- /// [`CodSpeedConfig::load_with_override`].
198- ///
199- /// The CLI config file is only read when no explicit token was passed,
200- /// so an invocation like `codspeed run --token <X>` never touches the
201- /// user's `~/.config/codspeed/`.
202- fn build_api_client ( cli : & Cli ) -> Result < CodSpeedAPIClient > {
218+ /// token from the selected profile.
219+ fn resolve_profile_config ( cli : & Cli ) -> Result < ResolvedProfileConfig > {
220+ let config = CodSpeedConfig :: load_with_override ( cli. config_name . as_deref ( ) , None ) ?;
221+ if matches ! ( & cli. command, Commands :: Auth ( _) | Commands :: Profile ( _) ) {
222+ Ok ( config. resolve_profile_or_default (
223+ cli. profile . as_deref ( ) ,
224+ cli. oauth_token . as_deref ( ) ,
225+ cli. api_url . as_deref ( ) ,
226+ None ,
227+ ) )
228+ } else {
229+ config. resolve_profile (
230+ cli. profile . as_deref ( ) ,
231+ cli. oauth_token . as_deref ( ) ,
232+ cli. api_url . as_deref ( ) ,
233+ None ,
234+ )
235+ }
236+ }
237+
238+ fn build_api_client ( cli : & Cli , resolved_profile : & ResolvedProfileConfig ) -> CodSpeedAPIClient {
203239 let explicit = match & cli. command {
204240 Commands :: Run ( args) => args. shared . token . clone ( ) ,
205241 Commands :: Exec ( args) => args. shared . token . clone ( ) ,
206242 _ => None ,
207243 } ;
208244 let token = match explicit {
209245 Some ( token) => Some ( token) ,
210- None => {
211- CodSpeedConfig :: load_with_override (
212- cli. config_name . as_deref ( ) ,
213- cli. oauth_token . as_deref ( ) ,
214- ) ?
215- . auth
216- . token
217- }
246+ None => resolved_profile. auth . token . clone ( ) ,
218247 } ;
219- Ok ( CodSpeedAPIClient :: new ( token, cli . api_url . clone ( ) ) )
248+ CodSpeedAPIClient :: new ( token, resolved_profile . api_url . clone ( ) )
220249}
0 commit comments