refactor: store workspaces as {workspace_id}/{repo_name} for natural git clone layout
Working copies were stored as /data/working-copies/{repo_id}/{workspace_name}/,
so git clone was forced into a user-named directory. That meant the container
mount basename was the workspace name (e.g. main) instead of the repo name.
- Generate the workspace UUID before cloning and clone into
/data/working-copies/{workspace_id}/ so git creates {repo_name}/ naturally
- Set workspace.path to /data/working-copies/{workspace_id}/{repo_name}/
- Update _migrate_clone_into_workspace() to use the same layout
- _get_repository_mount_name() now prefers workspace.path basename and only
falls back to remote URL / repo.name for legacy repo-only instances
- Update unit tests to assert workspace path basename is used for mounts
Quality gates:
- pytest tests/unit: 219 passed
- ruff: clean on changed files
- mypy: clean on changed files
This commit is contained in:
@@ -64,6 +64,14 @@ class TestGetRepositoryMountName:
|
||||
repo.remote_url = "https://github.com/acme/headquarter/tree/main"
|
||||
assert _get_repository_mount_name(repo) == "headquarter"
|
||||
|
||||
def test_uses_workspace_path_basename_when_workspace_provided(self):
|
||||
repo = MagicMock()
|
||||
repo.name = "src"
|
||||
repo.remote_url = "git@git.example.com:acme/headquarter.git"
|
||||
workspace = MagicMock()
|
||||
workspace.path = "/data/working-copies/uuid/headquarter"
|
||||
assert _get_repository_mount_name(repo, workspace) == "headquarter"
|
||||
|
||||
def test_falls_back_to_repo_name_when_remote_url_missing(self):
|
||||
repo = MagicMock()
|
||||
repo.name = "my-cool-repo"
|
||||
@@ -78,13 +86,19 @@ class TestGetRepositoryMountName:
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
async def test_prepare_manifest_instance_uses_repo_name_not_workspace_dir():
|
||||
"""WORKSPACE_NAME must be the repository name, not the workspace path basename."""
|
||||
async def test_prepare_manifest_instance_uses_workspace_path_basename():
|
||||
"""WORKSPACE_NAME must be the repo-named workspace directory, not workspace.name."""
|
||||
repo = MagicMock()
|
||||
repo.name = "src"
|
||||
repo.remote_url = "git@git.example.com:acme/headquarter.git"
|
||||
repo.path = "/data/repos/main"
|
||||
|
||||
workspace = MagicMock()
|
||||
workspace.id = "workspace-uuid"
|
||||
workspace.repo_id = "repo-uuid"
|
||||
workspace.name = "main"
|
||||
workspace.path = "/data/working-copies/workspace-uuid/headquarter"
|
||||
|
||||
tool_type = MagicMock()
|
||||
tool_type.name = "pi-agent"
|
||||
tool_type.manifest_id = "manifest-uuid"
|
||||
@@ -105,7 +119,7 @@ async def test_prepare_manifest_instance_uses_repo_name_not_workspace_dir():
|
||||
instance.tool_type_id = "tooltype-uuid"
|
||||
instance.port = 0
|
||||
instance.selected_config_profile_id = None
|
||||
instance.workspace_id = None
|
||||
instance.workspace_id = "workspace-uuid"
|
||||
|
||||
session = AsyncMock()
|
||||
|
||||
@@ -116,6 +130,8 @@ async def test_prepare_manifest_instance_uses_repo_name_not_workspace_dir():
|
||||
return manifest_def
|
||||
if model.__name__ == "GitRepository":
|
||||
return repo
|
||||
if model.__name__ == "Workspace":
|
||||
return workspace
|
||||
return None
|
||||
|
||||
session.get.side_effect = session_get
|
||||
@@ -146,7 +162,7 @@ async def test_prepare_manifest_instance_uses_repo_name_not_workspace_dir():
|
||||
session=session,
|
||||
instance=instance,
|
||||
instance_dir="/tmp/instance",
|
||||
repo_path="/data/repos/main",
|
||||
repo_path="/data/working-copies/workspace-uuid/headquarter",
|
||||
env_vars={},
|
||||
extra_volumes=[],
|
||||
working_directory=None,
|
||||
@@ -155,4 +171,4 @@ async def test_prepare_manifest_instance_uses_repo_name_not_workspace_dir():
|
||||
instance_service.subprocess.run = original_run
|
||||
|
||||
assert "WORKSPACE_NAME: headquarter" in compose_content
|
||||
assert "/data/repos/main:/home/user/headquarter" in compose_content
|
||||
assert "/data/working-copies/workspace-uuid/headquarter:/home/user/headquarter" in compose_content
|
||||
|
||||
Reference in New Issue
Block a user