Merge latest develop after WIP namespace integration
Normal merge of develop@5a4c823c preserves integrated T-698 controller/native projections alongside the T-692/T-693 reconciliation. Target branch remains untouched. Validation after this target movement: root cargo check; full worker(serial) and workspace-server tests; cargo fmt --all -- --check; git diff --check HEAD. Earlier reconciliation passed session-store, server-api generated/OpenAPI, full Web and production browser-shell checks.
This commit is contained in:
@@ -1594,12 +1594,12 @@ where
|
||||
let engine = worker.engine_mut();
|
||||
|
||||
if feature_config.merge_request.any() && wip_mode {
|
||||
let feature_route = wip_mount_registry
|
||||
.allocate_feature_route("merge-request")
|
||||
let namespace_route = wip_mount_registry
|
||||
.allocate_namespace("merge-request", "merge-requests")
|
||||
.map_err(|error| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
format!("allocate Merge Request WIP route: {error}"),
|
||||
format!("allocate Merge Request WIP namespace: {error}"),
|
||||
)
|
||||
})?;
|
||||
crate::feature::builtin::merge_request::mount_workspace_http_merge_request_wip(
|
||||
@@ -1607,7 +1607,7 @@ where
|
||||
workspace_client.clone(),
|
||||
feature_config.merge_request,
|
||||
wip_permissions.clone(),
|
||||
&feature_route,
|
||||
&namespace_route,
|
||||
)
|
||||
.map_err(|error| {
|
||||
std::io::Error::new(
|
||||
@@ -1624,12 +1624,12 @@ where
|
||||
intake: feature_config.ticket.intake,
|
||||
workflow: feature_config.ticket.workflow,
|
||||
};
|
||||
let feature_route = wip_mount_registry
|
||||
.allocate_feature_route("ticket")
|
||||
let namespace_route = wip_mount_registry
|
||||
.allocate_namespace("ticket", "tickets")
|
||||
.map_err(|error| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
format!("allocate Ticket WIP route: {error}"),
|
||||
format!("allocate Ticket WIP namespace: {error}"),
|
||||
)
|
||||
})?;
|
||||
crate::feature::builtin::ticket::mount_workspace_http_ticket_wip(
|
||||
@@ -1637,7 +1637,7 @@ where
|
||||
workspace_client.clone(),
|
||||
ticket_access,
|
||||
wip_permissions.clone(),
|
||||
&feature_route,
|
||||
&namespace_route,
|
||||
)
|
||||
.map_err(|error| {
|
||||
std::io::Error::new(
|
||||
@@ -1658,19 +1658,19 @@ where
|
||||
engine.register_tool(definition);
|
||||
}
|
||||
if wip_mode {
|
||||
let feature_route = wip_mount_registry
|
||||
.allocate_feature_route("objective")
|
||||
let namespace_route = wip_mount_registry
|
||||
.allocate_namespace("objective", "objectives")
|
||||
.map_err(|error| {
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
format!("allocate Objective WIP route: {error}"),
|
||||
format!("allocate Objective WIP namespace: {error}"),
|
||||
)
|
||||
})?;
|
||||
crate::feature::builtin::objective::mount_workspace_http_objective_wip(
|
||||
&mut wip_mount_registry,
|
||||
workspace_client.clone(),
|
||||
wip_permissions.clone(),
|
||||
&feature_route,
|
||||
&namespace_route,
|
||||
)
|
||||
.map_err(|error| {
|
||||
std::io::Error::new(
|
||||
|
||||
@@ -5,9 +5,9 @@ use crate::feature::{
|
||||
};
|
||||
use crate::permission::permission_action_for;
|
||||
use crate::wip::{
|
||||
WipCallContext, WipDynamicItem, WipDynamicItemResolver, WipDynamicMount, WipFeatureRoute,
|
||||
WipMountError, WipMountRegistry, WipOperationError, WipOperationHandler, WipOperationOutput,
|
||||
WipProjection, WipProjectionKind, json_to_wip, wip_to_json,
|
||||
WipCallContext, WipDynamicItem, WipDynamicItemResolver, WipDynamicMount, WipMountError,
|
||||
WipMountRegistry, WipNamespaceRoute, WipOperationError, WipOperationHandler,
|
||||
WipOperationOutput, WipProjection, WipProjectionKind, json_to_wip, wip_to_json,
|
||||
};
|
||||
use crate::worker::{WorkspaceClient, WorkspaceRequest, WorkspaceRequestMethod};
|
||||
use agen::tool::{Tool, ToolError, ToolExecutionContext, ToolMeta, ToolOutput};
|
||||
@@ -529,7 +529,7 @@ fn native_merge_request_tools(
|
||||
let (meta, tool) = definition(client.clone(), kind)();
|
||||
jsonschema::validator_for(&meta.input_schema).map_err(|error| {
|
||||
WipMountError::InvalidProjection {
|
||||
route: "/features/merge-request/merge-requests".into(),
|
||||
route: "/merge-requests".into(),
|
||||
message: format!("Merge Request tool schema cannot be retained: {error}"),
|
||||
}
|
||||
})?;
|
||||
@@ -562,9 +562,9 @@ pub fn mount_workspace_http_merge_request_wip(
|
||||
client: Arc<dyn WorkspaceClient>,
|
||||
config: MergeRequestFeatureConfig,
|
||||
permissions: Option<ToolPermissionConfig>,
|
||||
feature_route: &WipFeatureRoute,
|
||||
namespace_route: &WipNamespaceRoute,
|
||||
) -> Result<(), WipMountError> {
|
||||
let collection_route = feature_route.child("merge-requests")?;
|
||||
let collection_route = namespace_route.root().to_string();
|
||||
let tools = native_merge_request_tools(client, config)?;
|
||||
let claimed_tools = tools
|
||||
.iter()
|
||||
@@ -1049,7 +1049,7 @@ fn merge_request_operation_declaration(
|
||||
.get("properties")
|
||||
.and_then(Value::as_object)
|
||||
.ok_or_else(|| WipMountError::InvalidProjection {
|
||||
route: "/features/merge-request/merge-requests".into(),
|
||||
route: "/merge-requests".into(),
|
||||
message: format!(
|
||||
"Merge Request tool `{}` schema has no properties",
|
||||
tool.name
|
||||
@@ -1474,7 +1474,9 @@ mod tests {
|
||||
#[test]
|
||||
fn native_mount_uses_host_route_and_accepts_only_one_canonical_item_segment() {
|
||||
let mut registry = WipMountRegistry::new();
|
||||
let feature_route = registry.allocate_feature_route("merge-request").unwrap();
|
||||
let namespace_route = registry
|
||||
.allocate_namespace("merge-request", "merge-requests")
|
||||
.unwrap();
|
||||
mount_workspace_http_merge_request_wip(
|
||||
&mut registry,
|
||||
Arc::new(TestWorkspaceHttpClient::new("workspace", "http://unused")),
|
||||
@@ -1484,17 +1486,14 @@ mod tests {
|
||||
..Default::default()
|
||||
},
|
||||
None,
|
||||
&feature_route,
|
||||
&namespace_route,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
registry.routes().collect::<Vec<_>>(),
|
||||
["/features/merge-request/merge-requests"]
|
||||
);
|
||||
assert_eq!(registry.routes().collect::<Vec<_>>(), ["/merge-requests"]);
|
||||
let resolver = MergeRequestItemResolver {
|
||||
tools: HashMap::new(),
|
||||
permissions: None,
|
||||
collection_route: "/features/merge-request/merge-requests".into(),
|
||||
collection_route: "/merge-requests".into(),
|
||||
revisions: Arc::new(Mutex::new(MergeRequestRevisionState::default())),
|
||||
};
|
||||
assert!(
|
||||
@@ -1645,7 +1644,7 @@ mod tests {
|
||||
let resolver = MergeRequestItemResolver {
|
||||
tools: HashMap::new(),
|
||||
permissions: None,
|
||||
collection_route: "/features/merge-request/merge-requests".into(),
|
||||
collection_route: "/merge-requests".into(),
|
||||
revisions: Arc::clone(&revisions),
|
||||
};
|
||||
let first = resolver.resolve("MR-1").unwrap().object.validator;
|
||||
|
||||
@@ -21,9 +21,9 @@ use wip_protocol::{
|
||||
|
||||
use crate::permission::permission_action_for;
|
||||
use crate::wip::{
|
||||
WipCallContext, WipDynamicItem, WipDynamicItemResolver, WipDynamicMount, WipFeatureRoute,
|
||||
WipMountError, WipMountRegistry, WipOperationError, WipOperationHandler, WipOperationOutput,
|
||||
WipProjection, WipProjectionKind, json_to_wip, wip_to_json,
|
||||
WipCallContext, WipDynamicItem, WipDynamicItemResolver, WipDynamicMount, WipMountError,
|
||||
WipMountRegistry, WipNamespaceRoute, WipOperationError, WipOperationHandler,
|
||||
WipOperationOutput, WipProjection, WipProjectionKind, json_to_wip, wip_to_json,
|
||||
};
|
||||
use crate::worker::{WorkspaceClient, WorkspaceRequest, WorkspaceRequestMethod};
|
||||
|
||||
@@ -551,9 +551,9 @@ pub fn mount_workspace_http_objective_wip(
|
||||
registry: &mut WipMountRegistry,
|
||||
client: Arc<dyn WorkspaceClient>,
|
||||
permissions: Option<ToolPermissionConfig>,
|
||||
feature_route: &WipFeatureRoute,
|
||||
namespace_route: &WipNamespaceRoute,
|
||||
) -> Result<(), WipMountError> {
|
||||
let collection_route = feature_route.child("objectives")?;
|
||||
let collection_route = namespace_route.root().to_string();
|
||||
let backend = WorkspaceHttpObjectiveBackend::new(client);
|
||||
let revisions = Arc::new(Mutex::new(ObjectiveRevisionState::default()));
|
||||
let collection_descriptor = objective_collection_descriptor();
|
||||
@@ -1775,7 +1775,9 @@ mod tests {
|
||||
}));
|
||||
|
||||
let mut registry = WipMountRegistry::new();
|
||||
let feature_route = registry.allocate_feature_route("objective").unwrap();
|
||||
let namespace_route = registry
|
||||
.allocate_namespace("objective", "objectives")
|
||||
.unwrap();
|
||||
mount_workspace_http_objective_wip(
|
||||
&mut registry,
|
||||
Arc::new(crate::worker::TestWorkspaceHttpClient::new(
|
||||
@@ -1783,18 +1785,16 @@ mod tests {
|
||||
"http://backend",
|
||||
)),
|
||||
None,
|
||||
&feature_route,
|
||||
&namespace_route,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
registry.routes().collect::<Vec<_>>(),
|
||||
["/features/objective/objectives"]
|
||||
assert_eq!(registry.routes().collect::<Vec<_>>(), ["/objectives"]);
|
||||
assert_eq!(namespace_route.root(), "/objectives");
|
||||
assert!(
|
||||
registry
|
||||
.allocate_namespace("objective", "../tickets")
|
||||
.is_err()
|
||||
);
|
||||
assert_eq!(
|
||||
feature_route.child("objectives").unwrap(),
|
||||
"/features/objective/objectives"
|
||||
);
|
||||
assert!(feature_route.child("../tickets").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1805,7 +1805,7 @@ mod tests {
|
||||
crate::worker::TestWorkspaceHttpClient::new("workspace", "http://backend"),
|
||||
)),
|
||||
permissions: None,
|
||||
collection_route: "/features/objective/objectives".into(),
|
||||
collection_route: "/objectives".into(),
|
||||
revisions: Arc::clone(&revisions),
|
||||
};
|
||||
let initial = resolver.resolve("O-3").unwrap();
|
||||
@@ -1971,7 +1971,7 @@ mod tests {
|
||||
let collection = ObjectiveCollectionWipHandler {
|
||||
backend,
|
||||
permissions: None,
|
||||
collection_route: "/features/objective/objectives".into(),
|
||||
collection_route: "/objectives".into(),
|
||||
revisions: Arc::new(Mutex::new(ObjectiveRevisionState::default())),
|
||||
};
|
||||
let result = collection
|
||||
@@ -2013,7 +2013,7 @@ mod tests {
|
||||
let collection = ObjectiveCollectionWipHandler {
|
||||
backend: backend.clone(),
|
||||
permissions: None,
|
||||
collection_route: "/features/objective/objectives".into(),
|
||||
collection_route: "/objectives".into(),
|
||||
revisions: Arc::clone(&revisions),
|
||||
};
|
||||
let context = || WipCallContext {
|
||||
@@ -2170,7 +2170,7 @@ mod tests {
|
||||
crate::worker::TestWorkspaceHttpClient::new("workspace", base_url),
|
||||
)),
|
||||
permissions: None,
|
||||
collection_route: "/features/objective/objectives".into(),
|
||||
collection_route: "/objectives".into(),
|
||||
revisions: Arc::new(Mutex::new(ObjectiveRevisionState::default())),
|
||||
};
|
||||
let output = match handler
|
||||
@@ -2191,10 +2191,7 @@ mod tests {
|
||||
let output = crate::wip::wip_to_json(&output.value).unwrap();
|
||||
assert_eq!(output["next_cursor"], "next-page");
|
||||
assert_eq!(output["has_more"], true);
|
||||
assert_eq!(
|
||||
output["objectives"][0]["path"],
|
||||
"/features/objective/objectives/O-3"
|
||||
);
|
||||
assert_eq!(output["objectives"][0]["path"], "/objectives/O-3");
|
||||
assert_eq!(output["objectives"][0]["linked_tickets"][0], "T-7");
|
||||
assert!(!output.to_string().contains("00001OBJECTIVE"));
|
||||
assert!(!output.to_string().contains("00001TICKET"));
|
||||
@@ -2243,7 +2240,7 @@ mod tests {
|
||||
let resolver = ObjectiveItemResolver {
|
||||
backend: backend.clone(),
|
||||
permissions: None,
|
||||
collection_route: "/features/objective/objectives".into(),
|
||||
collection_route: "/objectives".into(),
|
||||
revisions: Arc::clone(&revisions),
|
||||
};
|
||||
let before = resolver.resolve("O-3").unwrap().object.validator;
|
||||
|
||||
@@ -34,9 +34,9 @@ use crate::feature::{
|
||||
};
|
||||
use crate::permission::permission_action_for;
|
||||
use crate::wip::{
|
||||
WipCallContext, WipDynamicItem, WipDynamicItemResolver, WipDynamicMount, WipFeatureRoute,
|
||||
WipMountError, WipMountRegistry, WipOperationError, WipOperationHandler, WipOperationOutput,
|
||||
WipProjection, WipProjectionKind, json_to_wip, wip_to_json,
|
||||
WipCallContext, WipDynamicItem, WipDynamicItemResolver, WipDynamicMount, WipMountError,
|
||||
WipMountRegistry, WipNamespaceRoute, WipOperationError, WipOperationHandler,
|
||||
WipOperationOutput, WipProjection, WipProjectionKind, json_to_wip, wip_to_json,
|
||||
};
|
||||
use crate::worker::{WorkspaceClient, WorkspaceRequest, WorkspaceRequestMethod};
|
||||
use agen::tool::{Tool, ToolError, ToolExecutionContext, ToolMeta, ToolOutput};
|
||||
@@ -1377,7 +1377,7 @@ fn native_ticket_tools(
|
||||
let (meta, tool) = definition();
|
||||
let projection = native_ticket_operation(&meta.name).ok_or_else(|| {
|
||||
WipMountError::InvalidProjection {
|
||||
route: "/features/ticket/tickets".into(),
|
||||
route: "/tickets".into(),
|
||||
message: format!(
|
||||
"enabled Ticket tool `{}` has no native projection",
|
||||
meta.name
|
||||
@@ -1386,7 +1386,7 @@ fn native_ticket_tools(
|
||||
})?;
|
||||
jsonschema::validator_for(&meta.input_schema).map_err(|error| {
|
||||
WipMountError::InvalidProjection {
|
||||
route: "/features/ticket/tickets".into(),
|
||||
route: "/tickets".into(),
|
||||
message: format!("Ticket tool schema cannot be retained: {error}"),
|
||||
}
|
||||
})?;
|
||||
@@ -1418,9 +1418,9 @@ pub fn mount_workspace_http_ticket_wip(
|
||||
client: Arc<dyn WorkspaceClient>,
|
||||
access: TicketFeatureAccess,
|
||||
permissions: Option<ToolPermissionConfig>,
|
||||
feature_route: &WipFeatureRoute,
|
||||
namespace_route: &WipNamespaceRoute,
|
||||
) -> Result<(), WipMountError> {
|
||||
let collection_route = feature_route.child("tickets")?;
|
||||
let collection_route = namespace_route.root().to_string();
|
||||
let tools = native_ticket_tools(client, access)?;
|
||||
let claimed_tools = tools
|
||||
.iter()
|
||||
@@ -1920,7 +1920,7 @@ fn ticket_operation_declaration(
|
||||
.get("properties")
|
||||
.and_then(Value::as_object)
|
||||
.ok_or_else(|| WipMountError::InvalidProjection {
|
||||
route: "/features/ticket/tickets".into(),
|
||||
route: "/tickets".into(),
|
||||
message: format!("Ticket tool `{}` schema has no properties", tool.name),
|
||||
})?;
|
||||
let required = tool
|
||||
@@ -2103,7 +2103,7 @@ mod tests {
|
||||
#[test]
|
||||
fn native_ticket_mount_uses_host_route_and_rejects_non_ticket_children() {
|
||||
let mut registry = WipMountRegistry::new();
|
||||
let feature_route = registry.allocate_feature_route("ticket").unwrap();
|
||||
let namespace_route = registry.allocate_namespace("ticket", "tickets").unwrap();
|
||||
mount_workspace_http_ticket_wip(
|
||||
&mut registry,
|
||||
Arc::new(crate::worker::TestWorkspaceHttpClient::new(
|
||||
@@ -2112,20 +2112,21 @@ mod tests {
|
||||
)),
|
||||
TicketFeatureAccess::review(),
|
||||
None,
|
||||
&feature_route,
|
||||
&namespace_route,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
registry.routes().collect::<Vec<_>>(),
|
||||
["/features/ticket/tickets"]
|
||||
assert_eq!(registry.routes().collect::<Vec<_>>(), ["/tickets"]);
|
||||
assert!(
|
||||
registry
|
||||
.allocate_namespace("ticket", "../objectives")
|
||||
.is_err()
|
||||
);
|
||||
assert!(feature_route.child("../objectives").is_err());
|
||||
|
||||
let revisions = Arc::new(Mutex::new(TicketRevisionState::default()));
|
||||
let resolver = TicketItemResolver {
|
||||
tools: HashMap::new(),
|
||||
permissions: None,
|
||||
collection_route: "/features/ticket/tickets".into(),
|
||||
collection_route: "/tickets".into(),
|
||||
revisions,
|
||||
};
|
||||
assert!(resolver.resolve("T-42").is_some());
|
||||
@@ -2189,7 +2190,7 @@ mod tests {
|
||||
let resolver = TicketItemResolver {
|
||||
tools: HashMap::new(),
|
||||
permissions: None,
|
||||
collection_route: "/features/ticket/tickets".into(),
|
||||
collection_route: "/tickets".into(),
|
||||
revisions: Arc::clone(&revisions),
|
||||
};
|
||||
let unobserved_internal = resolver.resolve("00001TICKET").unwrap().object.validator;
|
||||
@@ -2243,7 +2244,7 @@ mod tests {
|
||||
let resolver = TicketItemResolver {
|
||||
tools: HashMap::new(),
|
||||
permissions: None,
|
||||
collection_route: "/features/ticket/tickets".into(),
|
||||
collection_route: "/tickets".into(),
|
||||
revisions: Arc::clone(&revisions),
|
||||
};
|
||||
let target_v1 = resolver.resolve("T-43").unwrap().object.validator;
|
||||
|
||||
+1423
-124
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user