diff --git a/src/api_client.rs b/src/api_client.rs index cbaf8c1..13ec059 100644 --- a/src/api_client.rs +++ b/src/api_client.rs @@ -1,5 +1,8 @@ +use std::fmt::Display; + use crate::prelude::*; use crate::{app::Cli, config::CodSpeedConfig}; +use console::style; use gql_client::{Client as GQLClient, ClientConfig}; use nestify::nest; use serde::{Deserialize, Serialize}; @@ -77,6 +80,22 @@ pub enum ReportConclusion { MissingBaseRun, Success, } + +impl Display for ReportConclusion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ReportConclusion::AcknowledgedFailure => { + write!(f, "{}", style("Acknowledged Failure").yellow().bold()) + } + ReportConclusion::Failure => write!(f, "{}", style("Failure").red().bold()), + ReportConclusion::MissingBaseRun => { + write!(f, "{}", style("Missing Base Run").yellow().bold()) + } + ReportConclusion::Success => write!(f, "{}", style("Success").green().bold()), + } + } +} + #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct FetchLocalRunReportHeadReport { @@ -103,11 +122,19 @@ nest! { #[serde(rename_all = "camelCase")]* struct FetchLocalRunReportData { repository: pub struct FetchLocalRunReportRepository { - pub runs: Vec, + settings: struct FetchLocalRunReportSettings { + allowed_regression: f64, + }, + runs: Vec, } } } +pub struct FetchLocalRunReportResponse { + pub allowed_regression: f64, + pub run: FetchLocalRunReportRun, +} + impl CodSpeedAPIClient { pub async fn create_login_session(&self) -> Result { let response = self @@ -142,7 +169,7 @@ impl CodSpeedAPIClient { pub async fn fetch_local_run_report( &self, vars: FetchLocalRunReportVars, - ) -> Result { + ) -> Result { let response = self .gql_client .query_with_vars_unwrap::( @@ -151,15 +178,22 @@ impl CodSpeedAPIClient { ) .await; match response { - Ok(response) => match response.repository.runs.into_iter().next() { - Some(run) => Ok(run), - None => bail!( - "No runs found for owner: {}, name: {}, run_id: {}", - vars.owner, - vars.name, - vars.run_id - ), - }, + Ok(response) => { + let allowed_regression = response.repository.settings.allowed_regression; + + match response.repository.runs.into_iter().next() { + Some(run) => Ok(FetchLocalRunReportResponse { + allowed_regression, + run, + }), + None => bail!( + "No runs found for owner: {}, name: {}, run_id: {}", + vars.owner, + vars.name, + vars.run_id + ), + } + } Err(err) => bail!("Failed to fetch local run report: {}", err), } } diff --git a/src/queries/FetchLocalRunReport.gql b/src/queries/FetchLocalRunReport.gql index 9f0959a..e0b1f63 100644 --- a/src/queries/FetchLocalRunReport.gql +++ b/src/queries/FetchLocalRunReport.gql @@ -1,5 +1,8 @@ query FetchLocalRunReport($owner: String!, $name: String!, $runId: String!) { repository(owner: $owner, name: $name) { + settings { + allowedRegression + } runs(where: { id: { equals: $runId } }) { id status diff --git a/src/run/poll_results.rs b/src/run/poll_results.rs index 3ee42c6..a17b789 100644 --- a/src/run/poll_results.rs +++ b/src/run/poll_results.rs @@ -1,10 +1,11 @@ use std::time::Duration; +use console::style; use tokio::time::{sleep, Instant}; use url::Url; use crate::api_client::{ - CodSpeedAPIClient, FetchLocalRunReportRun, FetchLocalRunReportVars, RunStatus, + CodSpeedAPIClient, FetchLocalRunReportResponse, FetchLocalRunReportVars, RunStatus, }; use crate::prelude::*; @@ -30,7 +31,7 @@ pub async fn poll_results( run_id: run_id.clone(), }; - let run; + let response; loop { if start.elapsed() > RUN_PROCESSING_MAX_DURATION { bail!("Polling results timed out"); @@ -40,17 +41,18 @@ pub async fn poll_results( .fetch_local_run_report(fetch_local_run_report_vars.clone()) .await? { - FetchLocalRunReportRun { status, .. } if status != RunStatus::Completed => { + FetchLocalRunReportResponse { run, .. } if run.status != RunStatus::Completed => { sleep(Duration::from_secs(5)).await; } - run_from_api => { - run = run_from_api; + reponse_from_api => { + response = reponse_from_api; break; } } } - let report = run + let report = response + .run .head_reports .into_iter() .next() @@ -58,14 +60,28 @@ pub async fn poll_results( info!("Report completed, here are the results:"); if let Some(impact) = report.impact { - info!("Impact: {}%", (impact * 100.0).round()); + let rounded_impact = (impact * 100.0).round(); + let impact_text = if impact > 0.0 { + style(format!("+{}%", rounded_impact)).green().bold() + } else { + style(format!("{}%", rounded_impact)).red().bold() + }; + + info!( + "Impact: {} (allowed regression: -{}%)", + impact_text, + (response.allowed_regression * 100.0).round() + ); } - info!("Conclusion: {:?}", report.conclusion); + info!("Conclusion: {}", report.conclusion); let mut report_url = Url::parse(config.frontend_url.as_str())?; - report_url.set_path(format!("{}/{}/runs/{}", owner, name, run.id).as_str()); + report_url.set_path(format!("{}/{}/runs/{}", owner, name, response.run.id).as_str()); - info!("\nTo see the full report, visit: {}", report_url); + info!( + "\nTo see the full report, visit: {}", + style(report_url).blue().bold().underlined() + ); Ok(()) }