fix: expose notification MR origin checks as typed entries
This commit is contained in:
@@ -249,6 +249,15 @@ impl References {
|
||||
add(&mut refs.tickets, row, "ticket");
|
||||
add(&mut refs.mrs, row, "merge_request_id");
|
||||
}
|
||||
// MR origin checks are independent of capture and of the selected item page.
|
||||
// Other check kinds identify Jobs/events, not published MR Objects.
|
||||
for check in array(data, "source_checks") {
|
||||
if check.get("resource_kind").and_then(Value::as_str)
|
||||
== Some("merge_request_events")
|
||||
{
|
||||
add(&mut refs.mrs, check, "reference");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {} // Tag/answer/tracking-history/delivery identifiers and prose are domain data.
|
||||
}
|
||||
|
||||
@@ -303,3 +303,44 @@ fn assignment_event_and_tag_identifiers_do_not_create_child_objects_or_text_link
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diagnostics_mr_origin_references_are_independent_of_capture_and_item_page() {
|
||||
for items in [
|
||||
json!([]),
|
||||
json!([{"ticket":"T-42","merge_request_id":null}]),
|
||||
] {
|
||||
for root in ["", "/changes"] {
|
||||
let data = json!({"items":items,"next_cursor":"opaque-MR-999",
|
||||
"source_checks":[
|
||||
{"resource_kind":"merge_request_events","reference":"MR-1","origin_present":true,"captured":false},
|
||||
{"resource_kind":"job_result","reference":"MR-2","origin_present":true,"captured":true},
|
||||
{"resource_kind":"source_event","reference":"mr-event:MR-3:event","origin_present":true,"captured":true},
|
||||
{"resource_kind":"future_kind","reference":"MR-4","origin_present":true,"captured":false}
|
||||
]});
|
||||
let output = projected("notification_diagnostics", data.clone(), root, "");
|
||||
assert_eq!(output["data"], data);
|
||||
let expected = if root.is_empty() {
|
||||
json!([{"id":"MR-1"}])
|
||||
} else {
|
||||
json!([{"id":"MR-1","entry":"/changes/MR-1"}])
|
||||
};
|
||||
assert_eq!(output["links"]["merge_requests"], expected);
|
||||
assert!(output.get("entry").is_none());
|
||||
let descriptor = InterfaceDescriptor {
|
||||
format: INTERFACE_FORMAT_V1.into(),
|
||||
documentation: None,
|
||||
types: vec![],
|
||||
operations: vec![OperationDeclaration {
|
||||
name: "notification_diagnostics".into(),
|
||||
documentation: None,
|
||||
parameters: vec![],
|
||||
returns: declaration("notification_diagnostics", false).unwrap(),
|
||||
}],
|
||||
};
|
||||
descriptor
|
||||
.validate_result("notification_diagnostics", &json_to_wip(&output).unwrap())
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1169,3 +1169,113 @@ async fn retained_ticket_result_mr_reference_is_model_navigation_not_body_or_sna
|
||||
assert_eq!(client.requests().len(), 2);
|
||||
client.assert_authorizations_consumed();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn diagnostics_uncaptured_mr_origin_is_typed_lazy_model_navigation_even_on_empty_pages() {
|
||||
for published in [false, true] {
|
||||
let page = json!({"items":[],"next_cursor":"opaque-next",
|
||||
"source_checks":[{"resource_kind":"merge_request_events","reference":"MR-1","origin_present":true,"captured":false}]});
|
||||
let mut responses = vec![crate::worker::WorkspaceResponse {
|
||||
status: 200,
|
||||
body: page.to_string(),
|
||||
}];
|
||||
let mut authorizations = vec![expected_authorization(
|
||||
"notification.diagnostics.read",
|
||||
"merge_request",
|
||||
Some(("merge_request_id", "MR-1")),
|
||||
)];
|
||||
if published {
|
||||
responses.push(crate::worker::WorkspaceResponse {
|
||||
status: 200,
|
||||
body: json!({"merge_request_id":"MR-1","ticket_ids":[],"thread":[]}).to_string(),
|
||||
});
|
||||
authorizations.push(expected_authorization(
|
||||
"merge_request.read",
|
||||
"merge_request",
|
||||
Some(("merge_request_id", "MR-1")),
|
||||
));
|
||||
}
|
||||
let client =
|
||||
Arc::new(ScriptedWorkspaceClient::new(responses).with_authorizations(authorizations));
|
||||
let mut registry = WipMountRegistry::new();
|
||||
let tickets = registry.allocate_namespace("ticket", "cases").unwrap();
|
||||
let changes = registry
|
||||
.allocate_namespace("merge-request", "changes")
|
||||
.unwrap();
|
||||
crate::feature::builtin::ticket::mount_workspace_http_ticket_wip(
|
||||
&mut registry,
|
||||
client.clone(),
|
||||
crate::feature::builtin::ticket::TicketFeatureAccess::read_only(),
|
||||
None,
|
||||
&tickets,
|
||||
)
|
||||
.unwrap();
|
||||
if published {
|
||||
crate::feature::builtin::merge_request::mount_workspace_http_merge_request_wip(
|
||||
&mut registry,
|
||||
client.clone(),
|
||||
manifest::MergeRequestFeatureConfig {
|
||||
show: true,
|
||||
..Default::default()
|
||||
},
|
||||
None,
|
||||
&changes,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
let mut engine = Engine::<_, Mutable, ()>::new_annotated(DummyClient);
|
||||
let runtime = install_wip_mode_with_mounts(
|
||||
&mut engine,
|
||||
None,
|
||||
"diagnostics-origin-model".into(),
|
||||
registry,
|
||||
)
|
||||
.unwrap();
|
||||
let tools = engine.tool_server_handle();
|
||||
tools.flush_pending();
|
||||
let collection = ticket_result_model_inspect(&tools, &json!("/cases")).await;
|
||||
let result=ticket_result_model_invoke(&tools,&collection,"notification_diagnostics",json!({"filter":{"merge_request":"/changes/MR-1"},"page":{"cursor":"previous-page","limit":1}})).await;
|
||||
assert_eq!(result["data"], page);
|
||||
assert_eq!(result["links"]["merge_requests"][0]["id"], "MR-1");
|
||||
assert_eq!(
|
||||
client.requests().len(),
|
||||
1,
|
||||
"origin reference never prefetches current MR"
|
||||
);
|
||||
let declaration = runtime
|
||||
.host
|
||||
.projection("/cases")
|
||||
.unwrap()
|
||||
.descriptor
|
||||
.operations
|
||||
.into_iter()
|
||||
.find(|op| op.name == "notification_diagnostics")
|
||||
.unwrap();
|
||||
let mut entries = vec![];
|
||||
ticket_result_declared_entries(&declaration.returns.r#type, &result, &mut entries);
|
||||
if published {
|
||||
assert_eq!(entries, vec!["/changes/MR-1"]);
|
||||
let mr =
|
||||
ticket_result_model_inspect(&tools, &result["links"]["merge_requests"][0]["entry"])
|
||||
.await;
|
||||
let interface = ticket_result_model_inspect(&tools, &mr["interfaces"][0]["path"]).await;
|
||||
assert!(
|
||||
interface["interface_signature"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.contains("read(")
|
||||
);
|
||||
ticket_result_model_invoke(&tools, &mr, "read", json!({})).await;
|
||||
assert_eq!(client.requests().len(), 2);
|
||||
} else {
|
||||
assert!(entries.is_empty());
|
||||
assert!(result["links"]["merge_requests"][0].get("entry").is_none());
|
||||
}
|
||||
client.assert_authorizations_consumed();
|
||||
let request = &client.requests()[0];
|
||||
assert!(request.path.contains("cursor=previous-page"));
|
||||
assert!(request.path.contains("merge_request_id=MR-1"));
|
||||
let tree = ticket_result_model_call(&tools, "Tree", json!({"path":"/","depth":3})).await;
|
||||
assert!(!tree.to_string().contains("/changes/MR-1"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user