-
Notifications
You must be signed in to change notification settings - Fork 94
/
Copy pathcheck.rs
133 lines (113 loc) · 5.05 KB
/
check.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use prettytable::{cell, row, Table};
use serde::Serialize;
use structopt::StructOpt;
use rover_client::query::graph::check;
use crate::command::RoverStdout;
use crate::utils::client::StudioClientConfig;
use crate::utils::git::GitContext;
use crate::utils::loaders::load_schema_from_flag;
use crate::utils::parsers::{
parse_graph_ref, parse_query_count_threshold, parse_query_percentage_threshold,
parse_schema_source, parse_validation_period, GraphRef, SchemaSource, ValidationPeriod,
};
use crate::Result;
#[derive(Debug, Serialize, StructOpt)]
pub struct Check {
/// <NAME>@<VARIANT> of graph in Apollo Studio to validate.
/// @<VARIANT> may be left off, defaulting to @current
#[structopt(name = "GRAPH_REF", parse(try_from_str = parse_graph_ref))]
#[serde(skip_serializing)]
graph: GraphRef,
/// Name of configuration profile to use
#[structopt(long = "profile", default_value = "default")]
#[serde(skip_serializing)]
profile_name: String,
/// The schema file to push
/// Can pass `-` to use stdin instead of a file
#[structopt(long, short = "s", parse(try_from_str = parse_schema_source))]
#[serde(skip_serializing)]
schema: SchemaSource,
/// The minimum number of times a query or mutation must have been executed
/// in order to be considered in the check operation
#[structopt(long, parse(try_from_str = parse_query_count_threshold))]
query_count_threshold: Option<i64>,
/// Minimum percentage of times a query or mutation must have been executed
/// in the time window, relative to total request count, for it to be
/// considered in the check. Valid numbers are in the range 0 <= x <= 100
#[structopt(long, parse(try_from_str = parse_query_percentage_threshold))]
query_percentage_threshold: Option<f64>,
/// Size of the time window with which to validate schema against (in seconds)
#[structopt(long, parse(try_from_str = parse_validation_period))]
validation_period: Option<ValidationPeriod>,
}
impl Check {
pub fn run(
&self,
client_config: StudioClientConfig,
git_context: GitContext,
) -> Result<RoverStdout> {
let client = client_config.get_client(&self.profile_name)?;
let sdl = load_schema_from_flag(&self.schema, std::io::stdin())?;
let res = check::run(
check::check_schema_query::Variables {
graph_id: self.graph.name.clone(),
variant: Some(self.graph.variant.clone()),
schema: Some(sdl),
git_context: git_context.into(),
config: check::check_schema_query::HistoricQueryParameters {
query_count_threshold: self.query_count_threshold,
query_count_threshold_percentage: self.query_percentage_threshold,
from: self.validation_period.clone().unwrap_or_default().from,
to: self.validation_period.clone().unwrap_or_default().to,
// we don't support configuring these, but we can't leave them out
excluded_clients: None,
ignored_operations: None,
included_variants: None,
},
},
&client,
)?;
tracing::info!(
"Validated the proposed subgraph against metrics from {}",
&self.graph
);
let num_changes = res.changes.len();
let msg = match num_changes {
0 => "There is no difference between the proposed graph and the graph that already exists in the graph registry. Try making a change to your proposed graph before running this command.".to_string(),
_ => format!("Compared {} schema changes against {} operations", res.changes.len(), res.number_of_checked_operations),
};
tracing::info!("{}", &msg);
let num_failures = print_changes(&res.changes);
if let Some(url) = res.target_url {
tracing::info!("View full details here");
tracing::info!("{}", url.to_string());
}
match num_failures {
0 => Ok(RoverStdout::None),
1 => Err(anyhow::anyhow!("Encountered 1 failure.").into()),
_ => Err(anyhow::anyhow!("Encountered {} failures.", num_failures).into()),
}
}
}
fn print_changes(
checks: &[check::check_schema_query::CheckSchemaQueryServiceCheckSchemaDiffToPreviousChanges],
) -> u64 {
let mut num_failures = 0;
if !checks.is_empty() {
let mut table = Table::new();
table.add_row(row!["Change", "Code", "Description"]);
for check in checks {
let change = match check.severity {
check::check_schema_query::ChangeSeverity::NOTICE => "PASS",
check::check_schema_query::ChangeSeverity::FAILURE => {
num_failures += 1;
"FAIL"
}
_ => unreachable!("Unknown change severity"),
};
table.add_row(row![change, check.code, check.description]);
}
eprintln!("{}", table);
}
num_failures
}