Skip to content

Commit 7e5e798

Browse files
refactor: replace FetchLocalRunReport with leaner FetchLocalRun query
Add --base cli argument and simplify polling code 1. If a base run id is provided, we now use the `compareRunsPaginated` resolver and display results from there 2. If a base run id is not provided or if the base run id is not correct (missing, executor mismatch...), we display the single mode results This overall simplifies the polling code and gets rid of the artificial "for_run" and "for_exec" distinctions.
1 parent 39b6fe4 commit 7e5e798

12 files changed

Lines changed: 459 additions & 196 deletions

File tree

src/api_client.rs

Lines changed: 128 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -81,39 +81,12 @@ nest! {
8181

8282
#[derive(Serialize, Clone)]
8383
#[serde(rename_all = "camelCase")]
84-
pub struct FetchLocalRunReportVars {
84+
pub struct FetchLocalRunVars {
8585
pub owner: String,
8686
pub name: String,
8787
pub run_id: String,
8888
}
8989

90-
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
91-
pub enum ReportConclusion {
92-
AcknowledgedFailure,
93-
Failure,
94-
MissingBaseRun,
95-
NoBenchmarks,
96-
Success,
97-
}
98-
99-
impl Display for ReportConclusion {
100-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101-
match self {
102-
ReportConclusion::AcknowledgedFailure => {
103-
write!(f, "{}", style("Acknowledged Failure").yellow().bold())
104-
}
105-
ReportConclusion::Failure => write!(f, "{}", style("Failure").red().bold()),
106-
ReportConclusion::MissingBaseRun => {
107-
write!(f, "{}", style("Missing Base Run").yellow().bold())
108-
}
109-
ReportConclusion::NoBenchmarks => {
110-
write!(f, "{}", style("No Benchmarks").yellow().bold())
111-
}
112-
ReportConclusion::Success => write!(f, "{}", style("Success").green().bold()),
113-
}
114-
}
115-
}
116-
11790
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
11891
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
11992
pub enum RunStatus {
@@ -123,18 +96,23 @@ pub enum RunStatus {
12396
Processing,
12497
}
12598

99+
// Custom deserializer to convert string values to i64
100+
fn deserialize_i64_from_string<'de, D>(deserializer: D) -> Result<i64, D::Error>
101+
where
102+
D: serde::Deserializer<'de>,
103+
{
104+
use serde::de;
105+
let s = String::deserialize(deserializer)?;
106+
s.parse().map_err(de::Error::custom)
107+
}
108+
126109
nest! {
127110
#[derive(Debug, Deserialize, Serialize)]*
128111
#[serde(rename_all = "camelCase")]*
129-
pub struct FetchLocalRunReportRun {
112+
pub struct FetchLocalRunRun {
130113
pub id: String,
131114
pub status: RunStatus,
132115
pub url: String,
133-
pub head_reports: Vec<pub struct FetchLocalRunReportHeadReport {
134-
pub id: String,
135-
pub impact: Option<f64>,
136-
pub conclusion: ReportConclusion,
137-
}>,
138116
pub results: Vec<pub struct FetchLocalRunBenchmarkResult {
139117
pub value: f64,
140118
pub benchmark: pub struct FetchLocalRunBenchmark {
@@ -166,42 +144,111 @@ nest! {
166144
}
167145
}
168146

169-
// Custom deserializer to convert string values to i64
170-
fn deserialize_i64_from_string<'de, D>(deserializer: D) -> Result<i64, D::Error>
171-
where
172-
D: serde::Deserializer<'de>,
173-
{
174-
use serde::de;
175-
let s = String::deserialize(deserializer)?;
176-
s.parse().map_err(de::Error::custom)
147+
nest! {
148+
#[derive(Debug, Deserialize, Serialize)]*
149+
#[serde(rename_all = "camelCase")]*
150+
struct FetchLocalRunData {
151+
repository: struct FetchLocalRunRepository {
152+
run: FetchLocalRunRun,
153+
}
154+
}
155+
}
156+
157+
pub struct FetchLocalRunResponse {
158+
pub run: FetchLocalRunRun,
159+
}
160+
161+
#[derive(Serialize, Clone)]
162+
#[serde(rename_all = "camelCase")]
163+
pub struct CompareRunsVars {
164+
pub owner: String,
165+
pub name: String,
166+
pub base_run_id: String,
167+
pub head_run_id: String,
168+
}
169+
170+
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
171+
#[serde(rename_all = "PascalCase")]
172+
pub enum ResultComparisonCategory {
173+
Acknowledged,
174+
Archived,
175+
Ignored,
176+
Improvement,
177+
New,
178+
Regression,
179+
Skipped,
180+
Untouched,
181+
}
182+
183+
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
184+
pub enum BenchmarkReportStatus {
185+
Improvement,
186+
Missing,
187+
New,
188+
NoChange,
189+
Regression,
190+
}
191+
192+
impl Display for BenchmarkReportStatus {
193+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
194+
match self {
195+
BenchmarkReportStatus::Improvement => {
196+
write!(f, "{}", style("Improvement").green().bold())
197+
}
198+
BenchmarkReportStatus::Missing => write!(f, "{}", style("Missing").yellow().bold()),
199+
BenchmarkReportStatus::New => write!(f, "{}", style("New").cyan().bold()),
200+
BenchmarkReportStatus::NoChange => write!(f, "{}", style("No Change").dim()),
201+
BenchmarkReportStatus::Regression => write!(f, "{}", style("Regression").red().bold()),
202+
}
203+
}
177204
}
178205

179206
nest! {
180207
#[derive(Debug, Deserialize, Serialize)]*
181208
#[serde(rename_all = "camelCase")]*
182-
struct FetchLocalRunReportData {
183-
repository: pub struct FetchLocalRunReportRepository {
184-
settings: struct FetchLocalRunReportSettings {
185-
allowed_regression: f64,
186-
},
187-
run: FetchLocalRunReportRun,
188-
}
209+
pub struct CompareRunsBenchmarkResult {
210+
pub value: Option<f64>,
211+
pub base_value: Option<f64>,
212+
pub change: Option<f64>,
213+
pub category: ResultComparisonCategory,
214+
pub status: BenchmarkReportStatus,
215+
pub benchmark: pub struct CompareRunsBenchmark {
216+
pub name: String,
217+
pub executor: ExecutorName,
218+
},
219+
}
220+
}
221+
222+
nest! {
223+
#[derive(Debug, Deserialize, Serialize)]*
224+
#[serde(rename_all = "camelCase")]*
225+
pub struct CompareRunsHeadRun {
226+
pub id: String,
227+
pub status: RunStatus,
228+
pub url: String,
189229
}
190230
}
191231

192232
nest! {
193233
#[derive(Debug, Deserialize, Serialize)]*
194234
#[serde(rename_all = "camelCase")]*
195-
struct FetchLocalExecReportData {
196-
project: pub struct FetchLocalExecReportProject {
197-
run: FetchLocalRunReportRun,
235+
struct CompareRunsData {
236+
repository: struct CompareRunsRepository {
237+
settings: struct CompareRunsSettings {
238+
allowed_regression: f64,
239+
},
240+
paginated_compare_runs: pub struct CompareRunsComparison {
241+
pub impact: Option<f64>,
242+
pub head_run: CompareRunsHeadRun,
243+
pub result_comparisons: Vec<CompareRunsBenchmarkResult>,
244+
},
198245
}
199246
}
200247
}
201248

202-
pub struct FetchLocalRunReportResponse {
249+
pub struct CompareRunsResponse {
203250
pub allowed_regression: f64,
204-
pub run: FetchLocalRunReportRun,
251+
pub comparison: CompareRunsComparison,
205252
}
206253

207254
#[derive(Serialize, Clone)]
@@ -274,26 +321,44 @@ impl CodSpeedAPIClient {
274321
}
275322
}
276323

277-
pub async fn fetch_local_run_report(
278-
&self,
279-
vars: FetchLocalRunReportVars,
280-
) -> Result<FetchLocalRunReportResponse> {
324+
/// Returns `None` if the base run was not found.
325+
pub async fn compare_runs(&self, vars: CompareRunsVars) -> Result<Option<CompareRunsResponse>> {
281326
let response = self
282327
.gql_client
283-
.query_with_vars_unwrap::<FetchLocalRunReportData, FetchLocalRunReportVars>(
284-
include_str!("queries/FetchLocalRunReport.gql"),
285-
vars.clone(),
328+
.query_with_vars_unwrap::<CompareRunsData, CompareRunsVars>(
329+
include_str!("queries/CompareRuns.gql"),
330+
vars,
286331
)
287332
.await;
288333
match response {
289-
Ok(response) => Ok(FetchLocalRunReportResponse {
334+
Ok(response) => Ok(Some(CompareRunsResponse {
290335
allowed_regression: response.repository.settings.allowed_regression,
336+
comparison: response.repository.paginated_compare_runs,
337+
})),
338+
Err(err) if err.contains_error_code("UNAUTHENTICATED") => {
339+
bail!("Your session has expired, please login again using `codspeed auth login`")
340+
}
341+
Err(err) if err.contains_error_code("RUN_NOT_FOUND") => Ok(None),
342+
Err(err) => bail!("Failed to compare runs: {err}"),
343+
}
344+
}
345+
346+
pub async fn fetch_local_run(&self, vars: FetchLocalRunVars) -> Result<FetchLocalRunResponse> {
347+
let response = self
348+
.gql_client
349+
.query_with_vars_unwrap::<FetchLocalRunData, FetchLocalRunVars>(
350+
include_str!("queries/FetchLocalRun.gql"),
351+
vars,
352+
)
353+
.await;
354+
match response {
355+
Ok(response) => Ok(FetchLocalRunResponse {
291356
run: response.repository.run,
292357
}),
293358
Err(err) if err.contains_error_code("UNAUTHENTICATED") => {
294359
bail!("Your session has expired, please login again using `codspeed auth login`")
295360
}
296-
Err(err) => bail!("Failed to fetch local run report: {err}"),
361+
Err(err) => bail!("Failed to fetch local run: {err}"),
297362
}
298363
}
299364

src/cli/exec/mod.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ impl ExecArgs {
5959
fn build_orchestrator_config(
6060
args: ExecArgs,
6161
target: executor::BenchmarkTarget,
62+
poll_results_options: PollResultsOptions,
6263
) -> Result<OrchestratorConfig> {
6364
let modes = args.shared.resolve_modes()?;
6465
let raw_upload_url = args
@@ -90,7 +91,7 @@ fn build_orchestrator_config(
9091
allow_empty: args.shared.allow_empty,
9192
go_runner_version: args.shared.go_runner_version,
9293
show_full_output: args.shared.show_full_output,
93-
poll_results_options: PollResultsOptions::for_exec(),
94+
poll_results_options,
9495
extra_env: HashMap::new(),
9596
})
9697
}
@@ -103,12 +104,17 @@ pub async fn run(
103104
setup_cache_dir: Option<&Path>,
104105
) -> Result<()> {
105106
let merged_args = args.merge_with_project_config(project_config);
107+
let base_run_id = merged_args.shared.base.clone();
106108
let target = executor::BenchmarkTarget::Exec {
107109
command: merged_args.command.clone(),
108110
name: merged_args.name.clone(),
109111
walltime_args: merged_args.walltime_args.clone(),
110112
};
111-
let config = build_orchestrator_config(merged_args, target)?;
113+
let config = build_orchestrator_config(
114+
merged_args,
115+
target,
116+
PollResultsOptions::new(false, base_run_id),
117+
)?;
112118

113119
execute_config(config, api_client, codspeed_config, setup_cache_dir).await
114120
}

0 commit comments

Comments
 (0)