feat: workspace backend integration (PR-2)
- Add workspace_id to CreateInstanceRequest (optional, replaces clone_mode) - create_instance: resolve workspace, validate repo ownership, use workspace.path - create_instance: store workspace_id on ToolInstance record - start_instance: use workspace.path when workspace_id is set (manifest + legacy flows) - Skip SSH key mount for clone mode when workspace is used - Backward compatible: clone_mode still works when workspace_id is absent
This commit is contained in:
@@ -427,6 +427,9 @@ class CreateInstanceRequest(BaseModel):
|
||||
display_name: str | None = Field(
|
||||
default=None, description="Optional display name for the instance"
|
||||
)
|
||||
workspace_id: str | None = Field(
|
||||
default=None, description="UUID of workspace to mount (replaces clone_mode)"
|
||||
)
|
||||
clone_mode: str = Field(
|
||||
default="mount", description="Repository access mode: 'mount' or 'clone'"
|
||||
)
|
||||
@@ -849,9 +852,34 @@ async def create_instance(
|
||||
session, data.config_profile_id, user_id, project_id, tool_type_id
|
||||
)
|
||||
|
||||
# Resolve workspace if provided
|
||||
workspace = None
|
||||
workspace_id = None
|
||||
if data.workspace_id:
|
||||
from src.models.workspace import Workspace as WorkspaceModel
|
||||
|
||||
try:
|
||||
workspace_id = uuid.UUID(data.workspace_id)
|
||||
except ValueError:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Invalid workspace_id format",
|
||||
)
|
||||
workspace = await session.get(WorkspaceModel, workspace_id)
|
||||
if workspace is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="workspace not found",
|
||||
)
|
||||
if workspace.repo_id != repo_id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="workspace does not belong to this repository",
|
||||
)
|
||||
|
||||
try:
|
||||
# Validate clone mode requirements
|
||||
if data.clone_mode == "clone":
|
||||
# Validate clone mode requirements (legacy path)
|
||||
if data.clone_mode == "clone" and not workspace:
|
||||
if not repo.remote_url:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
@@ -876,8 +904,10 @@ async def create_instance(
|
||||
# Find free port
|
||||
tool_port = find_free_port()
|
||||
|
||||
# Determine repo path based on clone mode
|
||||
if data.clone_mode == "clone":
|
||||
# Determine repo path based on workspace or clone mode
|
||||
if workspace:
|
||||
repo_path = workspace.path
|
||||
elif data.clone_mode == "clone":
|
||||
# Get SSH key for cloning
|
||||
ssh_key = await session.get(SSHKey, repo.ssh_key_id)
|
||||
if ssh_key is None:
|
||||
@@ -1143,6 +1173,7 @@ services:
|
||||
status="pending",
|
||||
compose_path=compose_path,
|
||||
port=tool_port,
|
||||
workspace_id=workspace_id,
|
||||
clone_mode=data.clone_mode,
|
||||
branch=data.new_branch
|
||||
if data.new_branch
|
||||
@@ -1649,11 +1680,18 @@ async def start_instance(
|
||||
if tool_type and tool_type.definition_type == "manifest" and tool_type.manifest_id:
|
||||
logger.info("Using manifest-based startup for instance %s", instance.id)
|
||||
|
||||
# Determine repo path
|
||||
repo = await session.get(GitRepository, instance.repository_id)
|
||||
repo_path = repo.path if repo else ""
|
||||
if instance.clone_mode == "clone":
|
||||
repo_path = os.path.join(instance_dir, "repo-clone")
|
||||
# Determine repo path (workspace takes precedence)
|
||||
repo_path = ""
|
||||
if instance.workspace_id:
|
||||
from src.models.workspace import Workspace as WorkspaceModel
|
||||
workspace = await session.get(WorkspaceModel, instance.workspace_id)
|
||||
if workspace:
|
||||
repo_path = workspace.path
|
||||
else:
|
||||
repo = await session.get(GitRepository, instance.repository_id)
|
||||
repo_path = repo.path if repo else ""
|
||||
if instance.clone_mode == "clone":
|
||||
repo_path = os.path.join(instance_dir, "repo-clone")
|
||||
|
||||
try:
|
||||
(
|
||||
@@ -1686,8 +1724,8 @@ async def start_instance(
|
||||
)
|
||||
else:
|
||||
# ── LEGACY FLOW ──────────────────────────────────────────
|
||||
# Mount SSH key for clone-mode instances
|
||||
if instance.clone_mode == "clone":
|
||||
# Mount SSH key for clone-mode instances (skip for workspace-based)
|
||||
if instance.clone_mode == "clone" and not instance.workspace_id:
|
||||
repo = await session.get(GitRepository, instance.repository_id)
|
||||
if repo and repo.ssh_key_id:
|
||||
ssh_key = await session.get(SSHKey, repo.ssh_key_id)
|
||||
|
||||
Reference in New Issue
Block a user