-
Notifications
You must be signed in to change notification settings - Fork 94
/
Copy pathcheck.rs
139 lines (119 loc) · 4.64 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
134
135
136
137
138
139
use prettytable::{cell, row, Table};
use serde::Serialize;
use structopt::StructOpt;
use crate::Result;
use rover_client::query::subgraph::check;
use crate::client::StudioClientConfig;
use crate::command::RoverStdout;
use crate::utils::loaders::load_schema_from_flag;
use crate::utils::parsers::{parse_graph_ref, parse_schema_source, GraphRef, SchemaSource};
#[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 the subgraph to validate
#[structopt(long = "name")]
#[serde(skip_serializing)]
subgraph: String,
/// 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,
}
impl Check {
pub fn run(&self, client_config: StudioClientConfig) -> Result<RoverStdout> {
let client = client_config.get_client(&self.profile_name)?;
let sdl = load_schema_from_flag(&self.schema, std::io::stdin())?;
let partial_schema = check::check_partial_schema_query::PartialSchemaInput {
sdl: Some(sdl),
// we never need to send the hash since the back end computes it from SDL
hash: None,
};
let res = check::run(
check::check_partial_schema_query::Variables {
graph_id: self.graph.name.clone(),
variant: self.graph.variant.clone(),
partial_schema,
implementing_service_name: self.subgraph.clone(),
},
&client,
)?;
tracing::info!("Checked the proposed subgraph against {}", &self.graph);
match res {
check::CheckResponse::CompositionErrors(composition_errors) => {
handle_composition_errors(&composition_errors)
}
check::CheckResponse::CheckResult(check_result) => handle_checks(check_result),
}
}
}
fn handle_checks(check_result: check::CheckResult) -> Result<RoverStdout> {
let num_changes = check_result.changes.len();
let msg = match num_changes {
0 => "There were no changes detected in the composed schema.".to_string(),
_ => format!(
"Compared {} schema changes against {} operations",
check_result.changes.len(),
check_result.number_of_checked_operations
),
};
tracing::info!("{}", &msg);
let mut num_failures = 0;
if !check_result.changes.is_empty() {
let mut table = Table::new();
table.add_row(row!["Change", "Code", "Description"]);
for check in check_result.changes {
let change = match check.severity {
check::check_partial_schema_query::ChangeSeverity::NOTICE => "PASS",
check::check_partial_schema_query::ChangeSeverity::FAILURE => {
num_failures += 1;
"FAIL"
}
_ => unreachable!("Unknown change severity"),
};
table.add_row(row![change, check.code, check.description]);
}
eprintln!("{}", table);
}
if let Some(url) = check_result.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 while checking your subgraph.").into()),
_ => Err(anyhow::anyhow!(
"Encountered {} failures while checking your subgraph.",
num_failures
)
.into()),
}
}
fn handle_composition_errors(
composition_errors: &[check::check_partial_schema_query::CheckPartialSchemaQueryServiceCheckPartialSchemaCompositionValidationResultErrors],
) -> Result<RoverStdout> {
let mut num_failures = 0;
for error in composition_errors {
num_failures += 1;
tracing::error!("{}", &error.message);
}
match num_failures {
0 => Ok(RoverStdout::None),
1 => Err(
anyhow::anyhow!("Encountered 1 composition error while composing the subgraph.").into(),
),
_ => Err(anyhow::anyhow!(
"Encountered {} composition errors while composing the subgraph.",
num_failures
)
.into()),
}
}