Skip to content

Commit c9869e7

Browse files
fix: Error if the check workflow fails but all known tasks succeed (#1280)
Rover currently only fails a check if the tasks it knows about haven't errored. This causes issues when Studio introduces new tasks, as old versions of Rover will mistakenly think a check succeeded when it failed. This PR: - Introduces a new error variant (`RoverClientError::OtherCheckTaskFailure`) and code (`E036`) to convey when this occurs. - Updates `CheckResponse::try_new()` to return this error when the operations check succeeds, but the check workflow has not. If you'd like to test this out, please ping me on Slack (as the new task that would elicit this error is currently feature-flagged in Studio). Co-authored-by: Avery Harnish <[email protected]>
1 parent 8c649ef commit c9869e7

File tree

9 files changed

+53
-5
lines changed

9 files changed

+53
-5
lines changed

crates/rover-client/src/error.rs

+20
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,14 @@ pub enum RoverClientError {
139139
check_response: CheckResponse,
140140
},
141141

142+
// While checking the proposed schema, the operations task (and also build task, if run) succeeded,
143+
// but other check tasks failed.
144+
#[error("{}", other_check_task_failure_msg(.has_build_task))]
145+
OtherCheckTaskFailure {
146+
has_build_task: bool,
147+
target_url: String,
148+
},
149+
142150
/// This error occurs when a user has a malformed Graph Ref
143151
#[error("Graph IDs must be in the format <NAME> or <NAME>@<VARIANT>, where <NAME> can only contain letters, numbers, or the characters `-` or `_`, and must be 64 characters or less. <VARIANT> must be 64 characters or less.")]
144152
InvalidGraphRef,
@@ -179,6 +187,18 @@ pub enum RoverClientError {
179187
ChecksTimeoutError { url: Option<String> },
180188
}
181189

190+
fn other_check_task_failure_msg(has_build_task: &bool) -> String {
191+
let succeeding_tasks = if *has_build_task {
192+
"The build and operations tasks".to_string()
193+
} else {
194+
"The operations task".to_string()
195+
};
196+
format!(
197+
"{} succeeded, but other check tasks failed.",
198+
succeeding_tasks
199+
)
200+
}
201+
182202
fn operation_check_error_msg(check_response: &CheckResponse) -> String {
183203
let failure_count = check_response.get_failure_count();
184204
let plural = match failure_count {

crates/rover-client/src/operations/graph/check_workflow/runner.rs

+1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ fn get_check_response_from_data(
108108
changes,
109109
status,
110110
graph_ref,
111+
false,
111112
core_schema_modified,
112113
)
113114
}

crates/rover-client/src/operations/subgraph/check_workflow/runner.rs

+1
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ fn get_check_response_from_data(
120120
changes,
121121
status,
122122
graph_ref,
123+
true,
123124
core_schema_modified,
124125
)
125126
} else {

crates/rover-client/src/shared/check_response.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::cmp::Ordering;
21
use std::fmt::{self, Display};
32
use std::str::FromStr;
43

@@ -31,6 +30,7 @@ impl CheckResponse {
3130
changes: Vec<SchemaChange>,
3231
result: ChangeSeverity,
3332
graph_ref: GraphRef,
33+
has_build_task: bool,
3434
core_schema_modified: bool,
3535
) -> Result<CheckResponse, RoverClientError> {
3636
let mut failure_count = 0;
@@ -49,13 +49,21 @@ impl CheckResponse {
4949
core_schema_modified,
5050
};
5151

52-
match failure_count.cmp(&0) {
53-
Ordering::Equal => Ok(check_response),
54-
Ordering::Greater => Err(RoverClientError::OperationCheckFailure {
52+
if failure_count > 0 {
53+
return Err(RoverClientError::OperationCheckFailure {
5554
graph_ref,
5655
check_response,
56+
});
57+
}
58+
match check_response.result {
59+
ChangeSeverity::PASS => Ok(check_response),
60+
ChangeSeverity::FAIL => Err(RoverClientError::OtherCheckTaskFailure {
61+
has_build_task,
62+
target_url: check_response.target_url.unwrap_or_else(||
63+
// Note that graph IDs and variants don't need percent-encoding due to their regex restrictions.
64+
format!("https://studio.apollographql.com/graph/{}/checks?variant={}", graph_ref.name, graph_ref.variant)
65+
)
5766
}),
58-
Ordering::Less => unreachable!("Somehow encountered a negative number of failures."),
5967
}
6068
}
6169

src/command/output.rs

+2
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,7 @@ mod tests {
835835
ChangeSeverity::PASS,
836836
graph_ref,
837837
true,
838+
true,
838839
);
839840
if let Ok(mock_check_response) = mock_check_response {
840841
let actual_json: JsonOutput = RoverOutput::CheckResponse(mock_check_response).into();
@@ -891,6 +892,7 @@ mod tests {
891892
],
892893
ChangeSeverity::FAIL, graph_ref,
893894
false,
895+
false,
894896
);
895897

896898
if let Err(operation_check_failure) = check_response {

src/error/metadata/code.rs

+2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub enum Code {
4141
E033,
4242
E034,
4343
E035,
44+
E036,
4445
}
4546

4647
impl Display for Code {
@@ -89,6 +90,7 @@ impl Code {
8990
(Code::E033, include_str!("./codes/E033.md").to_string()),
9091
(Code::E034, include_str!("./codes/E034.md").to_string()),
9192
(Code::E035, include_str!("./codes/E035.md").to_string()),
93+
(Code::E036, include_str!("./codes/E036.md").to_string()),
9294
];
9395
contents.into_iter().collect()
9496
}

src/error/metadata/codes/E036.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This check error occurs when the operations task (and build task, if run) have succeeded, but some other check task has failed. Please view the check in [Apollo Studio](https://studio.apollographql.com/) at the provided link to see the failure reason. You can read more about client checks [here](https://www.apollographql.com/docs/studio/schema-checks/).

src/error/metadata/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,15 @@ impl From<&mut saucer::Error> for Metadata {
8989
}),
9090
Some(Code::E030),
9191
),
92+
RoverClientError::OtherCheckTaskFailure {
93+
has_build_task: _,
94+
target_url,
95+
} => (
96+
Some(Suggestion::FixOtherCheckTaskFailure {
97+
target_url: target_url.clone(),
98+
}),
99+
Some(Code::E036),
100+
),
92101
RoverClientError::SubgraphIntrospectionNotAvailable => {
93102
(Some(Suggestion::UseFederatedGraph), Some(Code::E007))
94103
}

src/error/metadata/suggestion.rs

+4
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ pub enum Suggestion {
4343
FixOperationsInSchema {
4444
graph_ref: GraphRef,
4545
},
46+
FixOtherCheckTaskFailure {
47+
target_url: String,
48+
},
4649
IncreaseClientTimeout,
4750
IncreaseChecksTimeout {
4851
url: Option<String>,
@@ -162,6 +165,7 @@ impl Display for Suggestion {
162165
Suggestion::FixSubgraphSchema { graph_ref, subgraph } => format!("The changes in the schema you proposed for subgraph {} are incompatible with supergraph {}. See {} for more information on resolving build errors.", Yellow.normal().paint(subgraph.to_string()), Yellow.normal().paint(graph_ref.to_string()), Cyan.normal().paint("https://www.apollographql.com/docs/federation/errors/")),
163166
Suggestion::FixCompositionErrors => format!("The subgraph schemas you provided are incompatible with each other. See {} for more information on resolving build errors.", Cyan.normal().paint("https://www.apollographql.com/docs/federation/errors/")),
164167
Suggestion::FixOperationsInSchema { graph_ref } => format!("The changes in the schema you proposed are incompatible with graph {}. See {} for more information on resolving operation check errors.", Yellow.normal().paint(graph_ref.to_string()), Cyan.normal().paint("https://www.apollographql.com/docs/studio/schema-checks/")),
168+
Suggestion::FixOtherCheckTaskFailure { target_url } => format!("See {} to view the failure reason for the check.", Cyan.normal().paint(target_url)),
165169
Suggestion::IncreaseClientTimeout => "You can try increasing the timeout value by passing a higher value to the --client-timeout option.".to_string(),
166170
Suggestion::IncreaseChecksTimeout {url} => format!("You can try increasing the timeout value by setting APOLLO_CHECKS_TIMEOUT_SECONDS to a higher value in your env. The default value is 300 seconds. You can also view the live check progress by visiting {}.", Cyan.normal().paint(url.clone().unwrap_or_else(|| "https://studio.apollographql.com".to_string()))),
167171
Suggestion::FixChecksInput { graph_ref } => format!("Graph {} has no published schema or is not a composition variant. Please publish a schema or use a different variant.", Yellow.normal().paint(graph_ref.to_string())),

0 commit comments

Comments
 (0)