Skip to content

Commit 06e364a

Browse files
committed
fix: keep an interrupted Casework inspection as the operator's request
An interrupt during the Casework inspection in rstack dev start or check became an unavailable inspection, so it reported the operational class. An interrupt is the operator's request and reports as domain, as an interrupted start does. Only other inspection failures become InspectionUnavailable, with their cause in the reason. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
1 parent aec3363 commit 06e364a

1 file changed

Lines changed: 65 additions & 24 deletions

File tree

‎crates/registry-bregctl/src/project_dev/products.rs‎

Lines changed: 65 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -830,20 +830,7 @@ impl InspectionUnavailable {
830830
remedy: remedy.to_owned(),
831831
}
832832
}
833-
}
834833

835-
/// An inspection that could not complete, keeping the cause in the reason. The
836-
/// cause comes from spawning the tool, its timeout, temporary files and the
837-
/// report parse; none of those messages carries a configured value.
838-
fn inspection_failed(field: &str, action: &str, error: &anyhow::Error) -> InspectionUnavailable {
839-
InspectionUnavailable::new(
840-
field,
841-
&format!("The selected `caseworkctl` helper could not {action}: {error:#}."),
842-
"Install the matching Casework tools or provide RSTACK_CASEWORKCTL_BIN, then run the check again.",
843-
)
844-
}
845-
846-
impl InspectionUnavailable {
847834
pub(super) fn field(&self) -> &str {
848835
&self.field
849836
}
@@ -857,6 +844,28 @@ impl InspectionUnavailable {
857844
}
858845
}
859846

847+
/// The error for an inspection that could not complete. An interrupt is the
848+
/// operator's request and stays as it is. Any other failure is an unavailable
849+
/// inspection whose reason keeps the cause; the cause comes from spawning the
850+
/// tool, its timeout, temporary files and the report parse, and none of those
851+
/// messages carries a configured value.
852+
fn inspection_failed(
853+
field: &str,
854+
action: &str,
855+
error: anyhow::Error,
856+
terminate: &AtomicBool,
857+
) -> anyhow::Error {
858+
if terminate.load(Ordering::Relaxed) {
859+
return error;
860+
}
861+
InspectionUnavailable::new(
862+
field,
863+
&format!("The selected `caseworkctl` helper could not {action}: {error:#}."),
864+
"Install the matching Casework tools or provide RSTACK_CASEWORKCTL_BIN, then run the check again.",
865+
)
866+
.into()
867+
}
868+
860869
struct SelectedProduct {
861870
field: String,
862871
root: PathBuf,
@@ -1089,9 +1098,12 @@ fn casework_principals(
10891098
).into());
10901099
}
10911100
Err(error) => {
1092-
return Err(
1093-
inspection_failed(&project.field, "inspect the Casework project", &error).into(),
1094-
);
1101+
return Err(inspection_failed(
1102+
&project.field,
1103+
"inspect the Casework project",
1104+
error,
1105+
terminate,
1106+
));
10951107
}
10961108
};
10971109
let status_profile = plan
@@ -1279,7 +1291,7 @@ fn check_casework_binding(
12791291
})();
12801292
let (status, report) = match checked {
12811293
Ok(checked) => checked,
1282-
Err(error) => return Err(inspection_failed(&project.field, action, &error).into()),
1294+
Err(error) => return Err(inspection_failed(&project.field, action, error, terminate)),
12831295
};
12841296
match casework_binding_check(status.code(), &report, &binding.id) {
12851297
BindingCheck::Accepted => Ok(()),
@@ -1295,9 +1307,9 @@ fn check_casework_binding(
12951307
BindingCheck::Unchecked => Err(inspection_failed(
12961308
&project.field,
12971309
action,
1298-
&anyhow::anyhow!("caseworkctl check did not report a result for the binding"),
1299-
)
1300-
.into()),
1310+
anyhow::anyhow!("caseworkctl check did not report a result for the binding"),
1311+
terminate,
1312+
)),
13011313
}
13021314
}
13031315

@@ -2557,13 +2569,42 @@ mod tests {
25572569
let terminate = AtomicBool::new(false);
25582570
let missing = Path::new("/nonexistent/caseworkctl");
25592571
let error = explain_casework_facts(missing, Path::new("."), &terminate).unwrap_err();
2560-
let reason = inspection_failed("products[0]", "inspect the Casework project", &error);
2572+
let failed = inspection_failed(
2573+
"products[0]",
2574+
"inspect the Casework project",
2575+
error,
2576+
&terminate,
2577+
);
2578+
assert_eq!(class(&failed), "operational");
2579+
let reason = failed
2580+
.downcast_ref::<InspectionUnavailable>()
2581+
.expect("an unavailable inspection")
2582+
.reason();
25612583
assert!(
2562-
reason.reason().contains(
2584+
reason.contains(
25632585
"could not inspect the Casework project: cannot start caseworkctl explain"
25642586
),
2565-
"{}",
2566-
reason.reason()
2587+
"{reason}"
2588+
);
2589+
}
2590+
2591+
#[test]
2592+
fn an_interrupted_inspection_stays_the_operators_request() {
2593+
let class =
2594+
|error: &anyhow::Error| super::super::error_report(error).0["error"]["class"].clone();
2595+
let terminate = AtomicBool::new(true);
2596+
let interrupted = anyhow::anyhow!("development product inspection was interrupted");
2597+
let failed = inspection_failed(
2598+
"products[0]",
2599+
"inspect the Casework project",
2600+
interrupted,
2601+
&terminate,
2602+
);
2603+
assert!(!failed.is::<InspectionUnavailable>());
2604+
assert_eq!(class(&failed), "domain");
2605+
assert_eq!(
2606+
failed.to_string(),
2607+
"development product inspection was interrupted"
25672608
);
25682609
}
25692610

0 commit comments

Comments
 (0)