refactor: make workspace API own workdir projections
This commit is contained in:
Generated
+1
@@ -6590,6 +6590,7 @@ dependencies = [
|
|||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"workspace-api",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ sha2.workspace = true
|
|||||||
tempfile.workspace = true
|
tempfile.workspace = true
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
tokio = { workspace = true, features = ["process", "rt", "sync", "time"] }
|
tokio = { workspace = true, features = ["process", "rt", "sync", "time"] }
|
||||||
|
workspace-api = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
|
|||||||
+17
-139
@@ -6,7 +6,11 @@
|
|||||||
//! [`crate::http`].
|
//! [`crate::http`].
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
|
||||||
|
pub use workspace_api::{
|
||||||
|
WorkingDirectoryCleanupTarget, WorkingDirectoryMaterializerKind as MaterializerKind,
|
||||||
|
WorkingDirectoryOccupancy, WorkingDirectoryStatusKind, WorkingDirectorySummary,
|
||||||
|
};
|
||||||
|
|
||||||
/// Stable Workspace identity for a Worker hosted by a Runtime.
|
/// Stable Workspace identity for a Worker hosted by a Runtime.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
@@ -26,83 +30,6 @@ impl RuntimeWorkerRef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum MaterializerKind {
|
|
||||||
#[default]
|
|
||||||
RuntimeGitCache,
|
|
||||||
/// Legacy persisted value from the pre-cache local `git worktree` materializer.
|
|
||||||
LocalGitWorktree,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum WorkingDirectoryStatusKind {
|
|
||||||
Active,
|
|
||||||
CleanupPending,
|
|
||||||
Corrupted,
|
|
||||||
NotFound,
|
|
||||||
Unknown,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WorkingDirectoryStatusKind {
|
|
||||||
pub const fn as_str(&self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
Self::Active => "active",
|
|
||||||
Self::CleanupPending => "cleanup_pending",
|
|
||||||
Self::Corrupted => "corrupted",
|
|
||||||
Self::NotFound => "not_found",
|
|
||||||
Self::Unknown => "unknown",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for WorkingDirectoryStatusKind {
|
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
formatter.write_str(self.as_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
#[serde(deny_unknown_fields)]
|
|
||||||
pub struct WorkingDirectoryCleanupTarget {
|
|
||||||
pub kind: String,
|
|
||||||
pub working_directory_id: String,
|
|
||||||
pub repository_id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Durable Workspace occupancy projection for one Workdir.
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
|
|
||||||
pub struct WorkingDirectoryOccupancy {
|
|
||||||
#[serde(flatten)]
|
|
||||||
pub worker: RuntimeWorkerRef,
|
|
||||||
pub display_name: String,
|
|
||||||
pub linked_at: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for WorkingDirectoryOccupancy {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[serde(deny_unknown_fields)]
|
|
||||||
struct Wire {
|
|
||||||
runtime_id: String,
|
|
||||||
worker_id: String,
|
|
||||||
display_name: String,
|
|
||||||
linked_at: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
let wire = Wire::deserialize(deserializer)?;
|
|
||||||
Ok(Self {
|
|
||||||
worker: RuntimeWorkerRef::new(wire.runtime_id, wire.worker_id),
|
|
||||||
display_name: wire.display_name,
|
|
||||||
linked_at: wire.linked_at,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Immutable materialization provenance retained by Workspace inventory.
|
/// Immutable materialization provenance retained by Workspace inventory.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
@@ -139,67 +66,6 @@ pub struct WorkingDirectoryCurrentObservation {
|
|||||||
pub occupied_by: Option<WorkingDirectoryOccupancy>,
|
pub occupied_by: Option<WorkingDirectoryOccupancy>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
#[serde(deny_unknown_fields)]
|
|
||||||
pub struct WorkingDirectorySummary {
|
|
||||||
pub working_directory_id: String,
|
|
||||||
pub repository_id: String,
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
pub creation_selector: Option<String>,
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
pub creation_ref: Option<String>,
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
pub creation_tree: Option<String>,
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
pub current_selector: Option<String>,
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
pub current_ref: Option<String>,
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
pub current_tree: Option<String>,
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
pub observed_at_epoch_seconds: Option<u64>,
|
|
||||||
pub materializer_kind: MaterializerKind,
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
pub cleanup_target: Option<WorkingDirectoryCleanupTarget>,
|
|
||||||
pub status: WorkingDirectoryStatusKind,
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
pub cleanliness: Option<String>,
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
pub primary_worker_id: Option<String>,
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
pub occupied_by: Option<WorkingDirectoryOccupancy>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WorkingDirectorySummary {
|
|
||||||
/// Workspace-managed inventory rows carry explicit cleanup authority.
|
|
||||||
pub fn is_workspace_managed(&self) -> bool {
|
|
||||||
self.cleanup_target.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn provenance(&self) -> WorkingDirectoryProvenance {
|
|
||||||
WorkingDirectoryProvenance {
|
|
||||||
creation_selector: self.creation_selector.clone(),
|
|
||||||
creation_ref: self.creation_ref.clone(),
|
|
||||||
creation_tree: self.creation_tree.clone(),
|
|
||||||
materializer_kind: self.materializer_kind.clone(),
|
|
||||||
cleanup_target: self.cleanup_target.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn current_observation(&self) -> WorkingDirectoryCurrentObservation {
|
|
||||||
WorkingDirectoryCurrentObservation {
|
|
||||||
current_selector: self.current_selector.clone(),
|
|
||||||
current_ref: self.current_ref.clone(),
|
|
||||||
current_tree: self.current_tree.clone(),
|
|
||||||
observed_at_epoch_seconds: self.observed_at_epoch_seconds,
|
|
||||||
status: self.status.clone(),
|
|
||||||
cleanliness: self.cleanliness.clone(),
|
|
||||||
primary_worker_id: self.primary_worker_id.clone(),
|
|
||||||
occupied_by: self.occupied_by.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -220,6 +86,18 @@ mod tests {
|
|||||||
assert_eq!(serde_json::to_value(status).unwrap(), expected);
|
assert_eq!(serde_json::to_value(status).unwrap(), expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn workspace_workdir_projection_reexports_workspace_api_authority() {
|
||||||
|
assert_eq!(
|
||||||
|
std::any::TypeId::of::<WorkingDirectorySummary>(),
|
||||||
|
std::any::TypeId::of::<workspace_api::WorkingDirectorySummary>()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
std::any::TypeId::of::<WorkingDirectoryOccupancy>(),
|
||||||
|
std::any::TypeId::of::<workspace_api::WorkingDirectoryOccupancy>()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
|||||||
@@ -113,10 +113,11 @@ pub struct Diagnostic {
|
|||||||
///
|
///
|
||||||
/// The value identifies stable materialization provenance without exposing a
|
/// The value identifies stable materialization provenance without exposing a
|
||||||
/// provider path, Runtime handle, or session identity.
|
/// provider path, Runtime handle, or session identity.
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum WorkingDirectoryMaterializerKind {
|
pub enum WorkingDirectoryMaterializerKind {
|
||||||
|
#[default]
|
||||||
RuntimeGitCache,
|
RuntimeGitCache,
|
||||||
LocalGitWorktree,
|
LocalGitWorktree,
|
||||||
}
|
}
|
||||||
@@ -132,15 +133,21 @@ pub enum WorkingDirectoryStatusKind {
|
|||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for WorkingDirectoryStatusKind {
|
impl WorkingDirectoryStatusKind {
|
||||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
pub const fn as_str(&self) -> &'static str {
|
||||||
formatter.write_str(match self {
|
match self {
|
||||||
Self::Active => "active",
|
Self::Active => "active",
|
||||||
Self::CleanupPending => "cleanup_pending",
|
Self::CleanupPending => "cleanup_pending",
|
||||||
Self::Corrupted => "corrupted",
|
Self::Corrupted => "corrupted",
|
||||||
Self::NotFound => "not_found",
|
Self::NotFound => "not_found",
|
||||||
Self::Unknown => "unknown",
|
Self::Unknown => "unknown",
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for WorkingDirectoryStatusKind {
|
||||||
|
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
formatter.write_str(self.as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,6 +206,13 @@ pub struct WorkingDirectorySummary {
|
|||||||
pub occupied_by: Option<WorkingDirectoryOccupancy>,
|
pub occupied_by: Option<WorkingDirectoryOccupancy>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WorkingDirectorySummary {
|
||||||
|
/// Workspace-managed inventory rows carry explicit cleanup authority.
|
||||||
|
pub fn is_workspace_managed(&self) -> bool {
|
||||||
|
self.cleanup_target.is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Browser/Rust-client Workdir materialization request.
|
/// Browser/Rust-client Workdir materialization request.
|
||||||
///
|
///
|
||||||
/// `runtime_id = None` requests Workspace default Runtime resolution and
|
/// `runtime_id = None` requests Workspace default Runtime resolution and
|
||||||
|
|||||||
@@ -341,7 +341,7 @@ pub(crate) fn workspace_worker_summary(
|
|||||||
can_stop: summary.capabilities.can_stop,
|
can_stop: summary.capabilities.can_stop,
|
||||||
can_spawn_followup: summary.capabilities.can_spawn_followup,
|
can_spawn_followup: summary.capabilities.can_spawn_followup,
|
||||||
},
|
},
|
||||||
working_directory: summary.working_directory.map(crate::workdir_api::summary),
|
working_directory: summary.working_directory,
|
||||||
diagnostics: summary.diagnostics.into_iter().map(Into::into).collect(),
|
diagnostics: summary.diagnostics.into_iter().map(Into::into).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ pub mod runtime_subscription;
|
|||||||
pub mod server;
|
pub mod server;
|
||||||
pub mod skills;
|
pub mod skills;
|
||||||
pub mod store;
|
pub mod store;
|
||||||
mod workdir_api;
|
|
||||||
pub mod workdir_create_operations;
|
pub mod workdir_create_operations;
|
||||||
pub mod worker_source;
|
pub mod worker_source;
|
||||||
pub mod workspace_catalog;
|
pub mod workspace_catalog;
|
||||||
|
|||||||
@@ -8839,7 +8839,7 @@ async fn scoped_list_runtime_working_directories(
|
|||||||
let (items, diagnostics) = runtime_working_directory_summaries(&api, &path.runtime_id)?;
|
let (items, diagnostics) = runtime_working_directory_summaries(&api, &path.runtime_id)?;
|
||||||
Ok(Json(BrowserWorkingDirectoryListResponse {
|
Ok(Json(BrowserWorkingDirectoryListResponse {
|
||||||
workspace_id: api.config.workspace_id.clone(),
|
workspace_id: api.config.workspace_id.clone(),
|
||||||
items: items.into_iter().map(crate::workdir_api::summary).collect(),
|
items,
|
||||||
diagnostics: working_directory_diagnostics(diagnostics),
|
diagnostics: working_directory_diagnostics(diagnostics),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@@ -8882,7 +8882,7 @@ async fn scoped_list_working_directories(
|
|||||||
let items = working_directory_summaries(&api)?;
|
let items = working_directory_summaries(&api)?;
|
||||||
Ok(Json(BrowserWorkingDirectoryListResponse {
|
Ok(Json(BrowserWorkingDirectoryListResponse {
|
||||||
workspace_id: api.config.workspace_id.clone(),
|
workspace_id: api.config.workspace_id.clone(),
|
||||||
items: items.into_iter().map(crate::workdir_api::summary).collect(),
|
items,
|
||||||
diagnostics: Vec::new(),
|
diagnostics: Vec::new(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@@ -9339,7 +9339,7 @@ async fn create_workspace_working_directory(
|
|||||||
Json(BrowserWorkingDirectoryCreateResponse {
|
Json(BrowserWorkingDirectoryCreateResponse {
|
||||||
workspace_id: workspace_id.to_string(),
|
workspace_id: workspace_id.to_string(),
|
||||||
runtime_id: reserved.resolved_runtime_id,
|
runtime_id: reserved.resolved_runtime_id,
|
||||||
item: crate::workdir_api::summary(summary),
|
item: summary,
|
||||||
diagnostics: working_directory_diagnostics(result.diagnostics),
|
diagnostics: working_directory_diagnostics(result.diagnostics),
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
@@ -9362,7 +9362,7 @@ fn working_directory_detail_for_runtime(
|
|||||||
return Ok(Json(BrowserWorkingDirectoryDetailResponse {
|
return Ok(Json(BrowserWorkingDirectoryDetailResponse {
|
||||||
workspace_id: api.config.workspace_id.clone(),
|
workspace_id: api.config.workspace_id.clone(),
|
||||||
runtime_id: runtime_id.to_string(),
|
runtime_id: runtime_id.to_string(),
|
||||||
item: crate::workdir_api::summary(summary),
|
item: summary,
|
||||||
diagnostics: working_directory_diagnostics(result.diagnostics),
|
diagnostics: working_directory_diagnostics(result.diagnostics),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -9373,9 +9373,7 @@ fn working_directory_detail_for_runtime(
|
|||||||
return Ok(Json(BrowserWorkingDirectoryDetailResponse {
|
return Ok(Json(BrowserWorkingDirectoryDetailResponse {
|
||||||
workspace_id: api.config.workspace_id.clone(),
|
workspace_id: api.config.workspace_id.clone(),
|
||||||
runtime_id: runtime_id.to_string(),
|
runtime_id: runtime_id.to_string(),
|
||||||
item: crate::workdir_api::summary(projected_workdir_summary_from_record(
|
item: projected_workdir_summary_from_record(&api, &record)?,
|
||||||
&api, &record,
|
|
||||||
)?),
|
|
||||||
diagnostics: working_directory_diagnostics(result.diagnostics),
|
diagnostics: working_directory_diagnostics(result.diagnostics),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -9434,7 +9432,7 @@ fn cleanup_working_directory_for_runtime(
|
|||||||
Ok(Json(BrowserWorkingDirectoryDetailResponse {
|
Ok(Json(BrowserWorkingDirectoryDetailResponse {
|
||||||
workspace_id: api.config.workspace_id.clone(),
|
workspace_id: api.config.workspace_id.clone(),
|
||||||
runtime_id: runtime_id.to_string(),
|
runtime_id: runtime_id.to_string(),
|
||||||
item: crate::workdir_api::summary(summary),
|
item: summary,
|
||||||
diagnostics: working_directory_diagnostics(result.diagnostics),
|
diagnostics: working_directory_diagnostics(result.diagnostics),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@@ -14152,7 +14150,8 @@ fn merge_worker_registry_projection(
|
|||||||
.map(|workdir| {
|
.map(|workdir| {
|
||||||
let mut workdir_summary = workdir_summary_from_record(workdir);
|
let mut workdir_summary = workdir_summary_from_record(workdir);
|
||||||
workdir_summary.occupied_by = Some(WorkingDirectoryOccupancy {
|
workdir_summary.occupied_by = Some(WorkingDirectoryOccupancy {
|
||||||
worker: record.worker.clone(),
|
runtime_id: record.worker.runtime_id.clone(),
|
||||||
|
worker_id: record.worker.worker_id.clone(),
|
||||||
display_name: record.display_name.clone(),
|
display_name: record.display_name.clone(),
|
||||||
linked_at: link.linked_at.clone(),
|
linked_at: link.linked_at.clone(),
|
||||||
});
|
});
|
||||||
@@ -14501,7 +14500,8 @@ fn apply_workdir_occupancy_projection(
|
|||||||
})?;
|
})?;
|
||||||
summary.primary_worker_id = None;
|
summary.primary_worker_id = None;
|
||||||
summary.occupied_by = Some(WorkingDirectoryOccupancy {
|
summary.occupied_by = Some(WorkingDirectoryOccupancy {
|
||||||
worker: link.worker.clone(),
|
runtime_id: link.worker.runtime_id.clone(),
|
||||||
|
worker_id: link.worker.worker_id.clone(),
|
||||||
display_name: worker.display_name,
|
display_name: worker.display_name,
|
||||||
linked_at: link.linked_at.clone(),
|
linked_at: link.linked_at.clone(),
|
||||||
});
|
});
|
||||||
@@ -15955,7 +15955,8 @@ mod tests {
|
|||||||
assert_eq!(working_directory.current_selector, None);
|
assert_eq!(working_directory.current_selector, None);
|
||||||
assert_eq!(working_directory.current_ref.as_deref(), Some("fedcba"));
|
assert_eq!(working_directory.current_ref.as_deref(), Some("fedcba"));
|
||||||
let occupied_by = working_directory.occupied_by.as_ref().unwrap();
|
let occupied_by = working_directory.occupied_by.as_ref().unwrap();
|
||||||
assert_eq!(occupied_by.worker, RuntimeWorkerRef::new("embedded", "1"));
|
assert_eq!(occupied_by.runtime_id, "embedded");
|
||||||
|
assert_eq!(occupied_by.worker_id, "1");
|
||||||
assert!(working_directory.primary_worker_id.is_none());
|
assert!(working_directory.primary_worker_id.is_none());
|
||||||
let occupancy = serde_json::to_value(occupied_by).unwrap();
|
let occupancy = serde_json::to_value(occupied_by).unwrap();
|
||||||
assert_eq!(occupancy["runtime_id"], "embedded");
|
assert_eq!(occupancy["runtime_id"], "embedded");
|
||||||
@@ -17160,10 +17161,8 @@ mod tests {
|
|||||||
.find(|summary| summary.working_directory_id == "managed")
|
.find(|summary| summary.working_directory_id == "managed")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let occupied_by = managed.occupied_by.as_ref().unwrap();
|
let occupied_by = managed.occupied_by.as_ref().unwrap();
|
||||||
assert_eq!(
|
assert_eq!(occupied_by.runtime_id, EMBEDDED_WORKER_RUNTIME_ID);
|
||||||
occupied_by.worker,
|
assert_eq!(occupied_by.worker_id, "7");
|
||||||
RuntimeWorkerRef::new(EMBEDDED_WORKER_RUNTIME_ID, "7")
|
|
||||||
);
|
|
||||||
assert_eq!(occupied_by.display_name, "Worker Seven");
|
assert_eq!(occupied_by.display_name, "Worker Seven");
|
||||||
assert_eq!(occupied_by.linked_at, "3");
|
assert_eq!(occupied_by.linked_at, "3");
|
||||||
|
|
||||||
@@ -25499,7 +25498,7 @@ VALUES ('0192f0e8-4d84-7d6e-a000-000000000001', 'ticket', 3);
|
|||||||
fn workspace_workdir_response_serializes_shared_occupied_contract() {
|
fn workspace_workdir_response_serializes_shared_occupied_contract() {
|
||||||
let response = BrowserWorkingDirectoryListResponse {
|
let response = BrowserWorkingDirectoryListResponse {
|
||||||
workspace_id: TEST_WORKSPACE_ID.to_string(),
|
workspace_id: TEST_WORKSPACE_ID.to_string(),
|
||||||
items: vec![crate::workdir_api::summary(WorkingDirectorySummary {
|
items: vec![WorkingDirectorySummary {
|
||||||
working_directory_id: "wd-1".to_string(),
|
working_directory_id: "wd-1".to_string(),
|
||||||
repository_id: "main".to_string(),
|
repository_id: "main".to_string(),
|
||||||
creation_selector: None,
|
creation_selector: None,
|
||||||
@@ -25515,11 +25514,12 @@ VALUES ('0192f0e8-4d84-7d6e-a000-000000000001', 'ticket', 3);
|
|||||||
cleanliness: Some("clean".to_string()),
|
cleanliness: Some("clean".to_string()),
|
||||||
primary_worker_id: None,
|
primary_worker_id: None,
|
||||||
occupied_by: Some(WorkingDirectoryOccupancy {
|
occupied_by: Some(WorkingDirectoryOccupancy {
|
||||||
worker: RuntimeWorkerRef::new("arcadia", "worker-opaque-64"),
|
runtime_id: "arcadia".to_string(),
|
||||||
|
worker_id: "worker-opaque-64".to_string(),
|
||||||
display_name: "Coder".to_string(),
|
display_name: "Coder".to_string(),
|
||||||
linked_at: "2026-08-12T00:00:00Z".to_string(),
|
linked_at: "2026-08-12T00:00:00Z".to_string(),
|
||||||
}),
|
}),
|
||||||
})],
|
}],
|
||||||
diagnostics: vec![],
|
diagnostics: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
use workdir::workspace::{MaterializerKind, WorkingDirectoryStatusKind};
|
|
||||||
use workspace_api::{
|
|
||||||
WorkingDirectoryCleanupTarget, WorkingDirectoryMaterializerKind, WorkingDirectoryOccupancy,
|
|
||||||
WorkingDirectoryStatusKind as ApiWorkingDirectoryStatusKind, WorkingDirectorySummary,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub(crate) fn summary(
|
|
||||||
source: workdir::workspace::WorkingDirectorySummary,
|
|
||||||
) -> WorkingDirectorySummary {
|
|
||||||
WorkingDirectorySummary {
|
|
||||||
working_directory_id: source.working_directory_id,
|
|
||||||
repository_id: source.repository_id,
|
|
||||||
creation_selector: source.creation_selector,
|
|
||||||
creation_ref: source.creation_ref,
|
|
||||||
creation_tree: source.creation_tree,
|
|
||||||
current_selector: source.current_selector,
|
|
||||||
current_ref: source.current_ref,
|
|
||||||
current_tree: source.current_tree,
|
|
||||||
observed_at_epoch_seconds: source.observed_at_epoch_seconds,
|
|
||||||
materializer_kind: match source.materializer_kind {
|
|
||||||
MaterializerKind::RuntimeGitCache => WorkingDirectoryMaterializerKind::RuntimeGitCache,
|
|
||||||
MaterializerKind::LocalGitWorktree => {
|
|
||||||
WorkingDirectoryMaterializerKind::LocalGitWorktree
|
|
||||||
}
|
|
||||||
},
|
|
||||||
cleanup_target: source
|
|
||||||
.cleanup_target
|
|
||||||
.map(|target| WorkingDirectoryCleanupTarget {
|
|
||||||
kind: target.kind,
|
|
||||||
working_directory_id: target.working_directory_id,
|
|
||||||
repository_id: target.repository_id,
|
|
||||||
}),
|
|
||||||
status: match source.status {
|
|
||||||
WorkingDirectoryStatusKind::Active => ApiWorkingDirectoryStatusKind::Active,
|
|
||||||
WorkingDirectoryStatusKind::CleanupPending => {
|
|
||||||
ApiWorkingDirectoryStatusKind::CleanupPending
|
|
||||||
}
|
|
||||||
WorkingDirectoryStatusKind::Corrupted => ApiWorkingDirectoryStatusKind::Corrupted,
|
|
||||||
WorkingDirectoryStatusKind::NotFound => ApiWorkingDirectoryStatusKind::NotFound,
|
|
||||||
WorkingDirectoryStatusKind::Unknown => ApiWorkingDirectoryStatusKind::Unknown,
|
|
||||||
},
|
|
||||||
cleanliness: source.cleanliness,
|
|
||||||
primary_worker_id: source.primary_worker_id,
|
|
||||||
occupied_by: source
|
|
||||||
.occupied_by
|
|
||||||
.map(|occupancy| WorkingDirectoryOccupancy {
|
|
||||||
runtime_id: occupancy.worker.runtime_id,
|
|
||||||
worker_id: occupancy.worker.worker_id,
|
|
||||||
display_name: occupancy.display_name,
|
|
||||||
linked_at: occupancy.linked_at,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use workdir::workspace::{
|
|
||||||
RuntimeWorkerRef, WorkingDirectoryOccupancy as DomainOccupancy,
|
|
||||||
WorkingDirectorySummary as DomainSummary,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn conversion_preserves_public_occupancy_subject() {
|
|
||||||
let converted = summary(DomainSummary {
|
|
||||||
working_directory_id: "workdir-1".into(),
|
|
||||||
repository_id: "main".into(),
|
|
||||||
creation_selector: None,
|
|
||||||
creation_ref: None,
|
|
||||||
creation_tree: None,
|
|
||||||
current_selector: None,
|
|
||||||
current_ref: None,
|
|
||||||
current_tree: None,
|
|
||||||
observed_at_epoch_seconds: None,
|
|
||||||
materializer_kind: MaterializerKind::RuntimeGitCache,
|
|
||||||
cleanup_target: None,
|
|
||||||
status: WorkingDirectoryStatusKind::Active,
|
|
||||||
cleanliness: None,
|
|
||||||
primary_worker_id: None,
|
|
||||||
occupied_by: Some(DomainOccupancy {
|
|
||||||
worker: RuntimeWorkerRef::new("arcadia", "worker-1"),
|
|
||||||
display_name: "Coder".into(),
|
|
||||||
linked_at: "2026-01-01T00:00:00Z".into(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
let occupancy = converted.occupied_by.expect("occupancy");
|
|
||||||
assert_eq!(occupancy.runtime_id, "arcadia");
|
|
||||||
assert_eq!(occupancy.worker_id, "worker-1");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user