fix: share workspace creation wire contract
This commit is contained in:
@@ -1,32 +1,18 @@
|
|||||||
use crate::{BackendApiClient, BackendApiClientError};
|
use crate::{BackendApiClient, BackendApiClientError};
|
||||||
use reqwest::Method;
|
use reqwest::Method;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use workspace_api::{
|
use workspace_api::{
|
||||||
RepositoryListResponse, RepositorySummary, WorkspaceCatalogListResponse,
|
InitialRepositoryIntent, RepositoryListResponse, RepositorySummary,
|
||||||
WorkspaceCreateResponse, WorkspaceSummary,
|
WorkspaceCatalogListResponse, WorkspaceCreateRequest, WorkspaceCreateResponse,
|
||||||
|
WorkspaceSummary,
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_WORKSPACE_LIMIT: usize = 200;
|
const DEFAULT_WORKSPACE_LIMIT: usize = 200;
|
||||||
|
|
||||||
pub type BackendWorkspace = WorkspaceSummary;
|
pub type BackendWorkspace = WorkspaceSummary;
|
||||||
pub type CreateBackendWorkspaceResponse = WorkspaceCreateResponse;
|
pub type CreateBackendWorkspaceResponse = WorkspaceCreateResponse;
|
||||||
|
pub type CreateBackendWorkspaceRequest = WorkspaceCreateRequest;
|
||||||
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
|
pub type CreateBackendWorkspaceRepository = InitialRepositoryIntent;
|
||||||
#[serde(deny_unknown_fields)]
|
|
||||||
pub struct CreateBackendWorkspaceRequest {
|
|
||||||
pub operation_id: String,
|
|
||||||
pub display_name: String,
|
|
||||||
pub repository: CreateBackendWorkspaceRepository,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
||||||
#[serde(deny_unknown_fields)]
|
|
||||||
pub struct CreateBackendWorkspaceRepository {
|
|
||||||
pub repository_key: String,
|
|
||||||
pub source: String,
|
|
||||||
pub default_ref: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct BackendWorkspaceCatalogTarget {
|
pub struct BackendWorkspaceCatalogTarget {
|
||||||
@@ -185,19 +171,19 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_request_keeps_operation_id_for_exact_retry() {
|
fn create_request_keeps_operation_key_for_exact_retry() {
|
||||||
let request = CreateBackendWorkspaceRequest {
|
let request = CreateBackendWorkspaceRequest {
|
||||||
operation_id: "workspace-create-1".to_string(),
|
operation_key: "workspace-create-1".to_string(),
|
||||||
display_name: "Alpha".to_string(),
|
display_name: "Alpha".to_string(),
|
||||||
repository: CreateBackendWorkspaceRepository {
|
repository: CreateBackendWorkspaceRepository {
|
||||||
repository_key: "main".to_string(),
|
repository_key: "main".to_string(),
|
||||||
source: "/srv/repos/alpha".to_string(),
|
uri: "/srv/repos/alpha".to_string(),
|
||||||
default_ref: Some("develop".to_string()),
|
default_ref: Some("develop".to_string()),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let retry = request.clone();
|
let retry = request.clone();
|
||||||
assert_eq!(retry.operation_id, "workspace-create-1");
|
assert_eq!(retry.operation_key, "workspace-create-1");
|
||||||
assert_eq!(retry, request);
|
assert_eq!(retry, request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,26 +4,26 @@ use client::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn workspace_creation_request_preserves_operation_id_for_retry() {
|
fn workspace_creation_request_preserves_operation_key_for_retry() {
|
||||||
let request = CreateBackendWorkspaceRequest {
|
let request = CreateBackendWorkspaceRequest {
|
||||||
operation_id: "workspace-create-1".to_string(),
|
operation_key: "workspace-create-1".to_string(),
|
||||||
display_name: "Alpha".to_string(),
|
display_name: "Alpha".to_string(),
|
||||||
repository: CreateBackendWorkspaceRepository {
|
repository: CreateBackendWorkspaceRepository {
|
||||||
repository_key: "main".to_string(),
|
repository_key: "main".to_string(),
|
||||||
source: "/srv/repos/alpha".to_string(),
|
uri: "/srv/repos/alpha".to_string(),
|
||||||
default_ref: Some("develop".to_string()),
|
default_ref: Some("develop".to_string()),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(request.clone(), request);
|
assert_eq!(request.clone(), request);
|
||||||
assert_eq!(request.operation_id, "workspace-create-1");
|
assert_eq!(request.operation_key, "workspace-create-1");
|
||||||
let json = serde_json::to_value(&request).unwrap();
|
let json = serde_json::to_value(&request).unwrap();
|
||||||
assert_eq!(json["operation_id"], "workspace-create-1");
|
assert_eq!(json["operation_key"], "workspace-create-1");
|
||||||
assert_eq!(json["repository"]["repository_key"], "main");
|
assert_eq!(json["repository"]["repository_key"], "main");
|
||||||
assert_eq!(json["repository"]["source"], "/srv/repos/alpha");
|
assert_eq!(json["repository"]["uri"], "/srv/repos/alpha");
|
||||||
assert!(json.get("operation_key").is_none());
|
assert!(json.get("operation_id").is_none());
|
||||||
assert!(json["repository"].get("display_name").is_none());
|
assert!(json["repository"].get("display_name").is_none());
|
||||||
assert!(json["repository"].get("uri").is_none());
|
assert!(json["repository"].get("source").is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -200,10 +200,10 @@ fn prompt_create_request_inner() -> PickerResult<Option<CreateBackendWorkspaceRe
|
|||||||
.as_nanos()
|
.as_nanos()
|
||||||
);
|
);
|
||||||
Ok(Some(CreateBackendWorkspaceRequest {
|
Ok(Some(CreateBackendWorkspaceRequest {
|
||||||
operation_id: operation_key,
|
operation_key,
|
||||||
display_name,
|
display_name,
|
||||||
repository: CreateBackendWorkspaceRepository {
|
repository: CreateBackendWorkspaceRepository {
|
||||||
source: uri,
|
uri,
|
||||||
repository_key: if repository_key.is_empty() {
|
repository_key: if repository_key.is_empty() {
|
||||||
"main".to_string()
|
"main".to_string()
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -520,6 +520,25 @@ pub struct WorkspaceRepositoryRecord {
|
|||||||
pub updated_at: String,
|
pub updated_at: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initial Repository registration intent for Workspace creation.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct InitialRepositoryIntent {
|
||||||
|
pub repository_key: String,
|
||||||
|
pub uri: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub default_ref: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Request for atomically creating a Workspace and its initial Repository.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct WorkspaceCreateRequest {
|
||||||
|
pub operation_key: String,
|
||||||
|
pub display_name: String,
|
||||||
|
pub repository: InitialRepositoryIntent,
|
||||||
|
}
|
||||||
|
|
||||||
/// Response returned after atomically creating a Workspace and its first Repository.
|
/// Response returned after atomically creating a Workspace and its first Repository.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
@@ -3899,6 +3918,35 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn workspace_create_request_has_one_closed_shared_wire_shape() {
|
||||||
|
let request = WorkspaceCreateRequest {
|
||||||
|
operation_key: "workspace-create-1".to_string(),
|
||||||
|
display_name: "Workspace".to_string(),
|
||||||
|
repository: InitialRepositoryIntent {
|
||||||
|
repository_key: "main".to_string(),
|
||||||
|
uri: "/srv/repositories/main".to_string(),
|
||||||
|
default_ref: Some("develop".to_string()),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let json = serde_json::to_value(&request).unwrap();
|
||||||
|
assert_eq!(json["operation_key"], "workspace-create-1");
|
||||||
|
assert_eq!(json["repository"]["uri"], "/srv/repositories/main");
|
||||||
|
assert!(json.get("operation_id").is_none());
|
||||||
|
assert!(json["repository"].get("source").is_none());
|
||||||
|
assert!(
|
||||||
|
serde_json::from_value::<WorkspaceCreateRequest>(serde_json::json!({
|
||||||
|
"operation_id": "workspace-create-1",
|
||||||
|
"display_name": "Workspace",
|
||||||
|
"repository": {
|
||||||
|
"repository_key": "main",
|
||||||
|
"source": "/srv/repositories/main"
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.is_err()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn workspace_and_repository_response_shapes_round_trip() {
|
fn workspace_and_repository_response_shapes_round_trip() {
|
||||||
let workspace = serde_json::json!({
|
let workspace = serde_json::json!({
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use chrono::{SecondsFormat, Utc};
|
use chrono::{SecondsFormat, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
pub use workspace_api::{InitialRepositoryIntent, WorkspaceCreateRequest};
|
||||||
use workspace_api::{RepositoryObservedStatus, RepositorySource};
|
use workspace_api::{RepositoryObservedStatus, RepositorySource};
|
||||||
|
|
||||||
use crate::repository_source::{parse_repository_source, repository_source_fingerprint};
|
use crate::repository_source::{parse_repository_source, repository_source_fingerprint};
|
||||||
@@ -19,23 +19,6 @@ use crate::{Error, Result};
|
|||||||
const MAX_DISPLAY_NAME_BYTES: usize = 200;
|
const MAX_DISPLAY_NAME_BYTES: usize = 200;
|
||||||
const MAX_OPERATION_KEY_BYTES: usize = 200;
|
const MAX_OPERATION_KEY_BYTES: usize = 200;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
||||||
#[serde(deny_unknown_fields)]
|
|
||||||
pub struct InitialRepositoryIntent {
|
|
||||||
pub repository_key: String,
|
|
||||||
pub uri: String,
|
|
||||||
#[serde(default)]
|
|
||||||
pub default_ref: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
||||||
#[serde(deny_unknown_fields)]
|
|
||||||
pub struct WorkspaceCreateRequest {
|
|
||||||
pub operation_key: String,
|
|
||||||
pub display_name: String,
|
|
||||||
pub repository: InitialRepositoryIntent,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct WorkspaceCreateResult {
|
pub struct WorkspaceCreateResult {
|
||||||
pub workspace: WorkspaceRecord,
|
pub workspace: WorkspaceRecord,
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ pub(crate) async fn run_init(
|
|||||||
let response = create_backend_workspace(
|
let response = create_backend_workspace(
|
||||||
&target,
|
&target,
|
||||||
&CreateBackendWorkspaceRequest {
|
&CreateBackendWorkspaceRequest {
|
||||||
operation_id: uuid::Uuid::now_v7().to_string(),
|
operation_key: uuid::Uuid::now_v7().to_string(),
|
||||||
display_name: options.display_name,
|
display_name: options.display_name,
|
||||||
repository: CreateBackendWorkspaceRepository {
|
repository: CreateBackendWorkspaceRepository {
|
||||||
repository_key: options.repository_key,
|
repository_key: options.repository_key,
|
||||||
source: repository_uri.to_string(),
|
uri: repository_uri.to_string(),
|
||||||
default_ref: options.default_ref,
|
default_ref: options.default_ref,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user