From 8350914516d911c9ecc06175e9cf8c5b67663b88 Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Tue, 1 Apr 2025 19:16:45 +0200 Subject: [PATCH] feat: allow specifying oauth token through CLI --- src/api_client.rs | 10 +++----- src/app.rs | 10 ++++++-- src/config.rs | 26 ++++++++++++++----- src/run/mod.rs | 7 +++-- src/run/run_environment/local/provider.rs | 31 +++++++++++++++++++++++ 5 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/api_client.rs b/src/api_client.rs index 809a984c..55e0bf10 100644 --- a/src/api_client.rs +++ b/src/api_client.rs @@ -12,15 +12,13 @@ pub struct CodSpeedAPIClient { unauthenticated_gql_client: GQLClient, } -impl TryFrom<&Cli> for CodSpeedAPIClient { +impl TryFrom<(&Cli, &CodSpeedConfig)> for CodSpeedAPIClient { type Error = Error; - fn try_from(args: &Cli) -> Result { - let codspeed_config = CodSpeedConfig::load()?; - + fn try_from((args, codspeed_config): (&Cli, &CodSpeedConfig)) -> Result { Ok(Self { - gql_client: build_gql_api_client(&codspeed_config, args.api_url.clone(), true), + gql_client: build_gql_api_client(codspeed_config, args.api_url.clone(), true), unauthenticated_gql_client: build_gql_api_client( - &codspeed_config, + codspeed_config, args.api_url.clone(), false, ), diff --git a/src/app.rs b/src/app.rs index 2386180a..c92db85d 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,6 +1,7 @@ use crate::{ api_client::CodSpeedAPIClient, auth, + config::CodSpeedConfig, local_logger::{init_local_logger, CODSPEED_U8_COLOR_CODE}, prelude::*, run, setup, @@ -33,6 +34,10 @@ pub struct Cli { )] pub api_url: String, + /// The OAuth token to use for all requests + #[arg(long, env = "CODSPEED_OAUTH_TOKEN", global = true, hide = true)] + pub oauth_token: Option, + #[command(subcommand)] command: Commands, } @@ -49,7 +54,8 @@ enum Commands { pub async fn run() -> Result<()> { let cli = Cli::parse(); - let api_client = CodSpeedAPIClient::try_from(&cli)?; + let codspeed_config = CodSpeedConfig::load_with_override(cli.oauth_token.as_deref())?; + let api_client = CodSpeedAPIClient::try_from((&cli, &codspeed_config))?; match cli.command { Commands::Run(_) => {} // Run is responsible for its own logger initialization @@ -59,7 +65,7 @@ pub async fn run() -> Result<()> { } match cli.command { - Commands::Run(args) => run::run(args, &api_client).await?, + Commands::Run(args) => run::run(args, &api_client, &codspeed_config).await?, Commands::Auth(args) => auth::run(args, &api_client).await?, Commands::Setup => setup::setup().await?, } diff --git a/src/config.rs b/src/config.rs index 3fc6435c..bac05e85 100644 --- a/src/config.rs +++ b/src/config.rs @@ -36,27 +36,39 @@ impl Default for CodSpeedConfig { } impl CodSpeedConfig { - /// Load the configuration. If it does not exist, store and return a default configuration - pub fn load() -> Result { + /// Load the configuration. If it does not exist, return a default configuration. + /// + /// If oauth_token_override is provided, the token from the loaded configuration will be + /// ignored, and the override will be used instead + pub fn load_with_override(oauth_token_override: Option<&str>) -> Result { let config_path = get_configuration_file_path(); - match fs::read(&config_path) { + let mut config = match fs::read(&config_path) { Ok(config_str) => { let config = serde_yaml::from_slice(&config_str).context(format!( "Failed to parse CodSpeed config at {}", config_path.display() ))?; debug!("Config loaded from {}", config_path.display()); - Ok(config) + config } Err(e) if e.kind() == std::io::ErrorKind::NotFound => { debug!("Config file not found at {}", config_path.display()); - let config = CodSpeedConfig::default(); - config.persist()?; - Ok(config) + CodSpeedConfig::default() } Err(e) => bail!("Failed to load config: {}", e), + }; + + if let Some(oauth_token) = oauth_token_override { + config.auth.token = Some(oauth_token.to_owned()); } + + Ok(config) + } + + /// Load the configuration. If it does not exist, return a default configuration. + pub fn load() -> Result { + Self::load_with_override(None) } /// Persist changes to the configuration diff --git a/src/run/mod.rs b/src/run/mod.rs index f0dc492a..6b9e1073 100644 --- a/src/run/mod.rs +++ b/src/run/mod.rs @@ -133,11 +133,14 @@ impl RunArgs { } } -pub async fn run(args: RunArgs, api_client: &CodSpeedAPIClient) -> Result<()> { +pub async fn run( + args: RunArgs, + api_client: &CodSpeedAPIClient, + codspeed_config: &CodSpeedConfig, +) -> Result<()> { let output_json = args.message_format == Some(MessageFormat::Json); let mut config = Config::try_from(args)?; let provider = run_environment::get_provider(&config)?; - let codspeed_config = CodSpeedConfig::load()?; let logger = Logger::new(&provider)?; if provider.get_run_environment() != RunEnvironment::Local { diff --git a/src/run/run_environment/local/provider.rs b/src/run/run_environment/local/provider.rs index 7285679a..6f38fbe9 100644 --- a/src/run/run_environment/local/provider.rs +++ b/src/run/run_environment/local/provider.rs @@ -3,9 +3,12 @@ use simplelog::SharedLogger; use crate::local_logger::get_local_logger; use crate::prelude::*; +use crate::run::check_system::SystemInfo; use crate::run::config::RepositoryOverride; use crate::run::helpers::{parse_git_remote, GitRemote}; use crate::run::run_environment::{RunEnvironment, RunPart}; +use crate::run::runner::ExecutorName; +use crate::run::uploader::{Runner, UploadMetadata}; use crate::run::{ config::Config, helpers::find_repository_root, @@ -141,6 +144,34 @@ impl RunEnvironmentProvider for LocalProvider { }) } + fn get_upload_metadata( + &self, + config: &Config, + system_info: &SystemInfo, + archive_hash: &str, + executor_name: ExecutorName, + ) -> Result { + let run_environment_metadata = self.get_run_environment_metadata()?; + + Ok(UploadMetadata { + version: Some(6), + tokenless: config.token.is_none(), + repository_provider: self.get_repository_provider(), + commit_hash: run_environment_metadata.ref_.clone(), + run_environment_metadata, + profile_md5: archive_hash.into(), + runner: Runner { + name: "codspeed-runner".into(), + version: crate::VERSION.into(), + instruments: config.instruments.get_active_instrument_names(), + executor: executor_name, + system_info: system_info.clone(), + }, + run_environment: self.get_run_environment(), + run_part: self.get_run_provider_run_part(), + }) + } + /// For local runs have, we cannot really send anything here fn get_run_provider_run_part(&self) -> Option { None