From 477bef1af309fa7666cf66d843902266db14de5a Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Wed, 11 Mar 2026 13:44:36 +0100 Subject: [PATCH 1/2] feat: skip respository resolve with `--skip-upload` Since we are not going to upload the result anyway, we should still be able to perform the run if the API is not available. This allows offline usage during dev or in a very controlled sandbox environment that only outputs profile. --- src/run_environment/local/provider.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/run_environment/local/provider.rs b/src/run_environment/local/provider.rs index 9d1d528c..fd7ba6fc 100644 --- a/src/run_environment/local/provider.rs +++ b/src/run_environment/local/provider.rs @@ -57,7 +57,11 @@ impl LocalProvider { .map(|ctx| ctx.root_path.clone()) .unwrap_or_else(|| current_dir.to_string_lossy().to_string()); - let resolved = Self::resolve_repository(config, api_client, git_context.as_ref()).await?; + let resolved = if !config.skip_upload { + Self::resolve_repository(config, api_client, git_context.as_ref()).await? + } else { + Self::dummy_resolved_repository(git_context.as_ref()) + }; let expected_run_parts_count = config.expected_run_parts_count(); @@ -84,6 +88,21 @@ impl LocalProvider { }) } + /// Create a dummy resolved repository, resolved offline when --skip-upload is used and we don't need to resolve the actual repository information from the API + fn dummy_resolved_repository(git_context: Option<&GitContext>) -> ResolvedRepository { + let (ref_, head_ref) = git_context + .and_then(|ctx| Self::get_git_ref_info(&ctx.root_path).ok()) + .unwrap_or_else(|| (FAKE_COMMIT_REF.to_string(), None)); + + ResolvedRepository { + provider: RepositoryProvider::GitHub, + owner: "local".to_string(), + name: "local".to_string(), + ref_, + head_ref, + } + } + /// Resolve repository information from override, git remote, or API fallback async fn resolve_repository( config: &OrchestratorConfig, From aa418e66c60a9ec98835bbbc233d3c18259dc2eb Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Wed, 11 Mar 2026 14:11:51 +0100 Subject: [PATCH 2/2] feat: check if user is logged in before doing a local run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Repo found a. Logged in: user is set, repositoryOverview is set — repo found b. NOT logged in: user is null, repositoryOverview is set => bails with "session expired" 2. REPOSITORY_NOT_FOUND => falls through to `get_or_create_project_repository` a. Logged in: `get_or_create_project_repository` succeeds b. NOT logged in: `get_or_create_project_repository` fails, bail with "session expired" --- src/api_client.rs | 14 ++++++++++++-- src/queries/GetRepository.gql | 3 +++ src/run_environment/local/provider.rs | 9 +++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/api_client.rs b/src/api_client.rs index f740a583..03b9e469 100644 --- a/src/api_client.rs +++ b/src/api_client.rs @@ -232,7 +232,10 @@ nest! { struct GetRepositoryData { repository_overview: Option + }>, + user: Option, } } @@ -327,7 +330,14 @@ impl CodSpeedAPIClient { ) .await; match response { - Ok(response) => Ok(response.repository_overview), + Ok(response) => { + if response.user.is_none() { + bail!( + "Your session has expired, please login again using `codspeed auth login`" + ); + } + Ok(response.repository_overview) + } Err(err) if err.contains_error_code("REPOSITORY_NOT_FOUND") => Ok(None), Err(err) if err.contains_error_code("UNAUTHENTICATED") => { bail!("Your session has expired, please login again using `codspeed auth login`") diff --git a/src/queries/GetRepository.gql b/src/queries/GetRepository.gql index c6d547cf..b39e6f70 100644 --- a/src/queries/GetRepository.gql +++ b/src/queries/GetRepository.gql @@ -3,6 +3,9 @@ query Repository( $name: String! $provider: RepositoryProvider ) { + user { + id + } repositoryOverview(owner: $owner, name: $name, provider: $provider) { ... on Repository { id diff --git a/src/run_environment/local/provider.rs b/src/run_environment/local/provider.rs index fd7ba6fc..7511b952 100644 --- a/src/run_environment/local/provider.rs +++ b/src/run_environment/local/provider.rs @@ -104,6 +104,15 @@ impl LocalProvider { } /// Resolve repository information from override, git remote, or API fallback + /// + /// When there is no explicit repository override, this flow also makes sure the user is logged in with a valid token + /// 1. Repo found + /// a. Logged in: user is set, repositoryOverview is set — repo found + /// b. NOT logged in: user is null, repositoryOverview is set => bails with "session expired" + /// + /// 2. REPOSITORY_NOT_FOUND => falls through to `get_or_create_project_repository` + /// a. Logged in: `get_or_create_project_repository` succeeds + /// b. NOT logged in: `get_or_create_project_repository` fails, bail with "session expired" async fn resolve_repository( config: &OrchestratorConfig, api_client: &CodSpeedAPIClient,