@@ -1415,6 +1415,198 @@ def test_directory_to_existing_file_fails(self, linux_container, test_target_dir
14151415 linux_container .export_path (source = "/folder1" , destination = existing_file )
14161416
14171417
1418+ class TestRepositoryResolution :
1419+ """Tests for git-aware repository resolution logic."""
1420+
1421+ def test_git_worktree_detection (self , dda , helpers , mocker , temp_dir , host_user_args ):
1422+ """Test that repositories are detected in git worktrees with arbitrary directory names."""
1423+ # Create a git repository structure
1424+ repos_dir = temp_dir / "repos"
1425+ repos_dir .ensure_dir ()
1426+ main_repo_dir = repos_dir / "datadog-agent"
1427+ main_repo_dir .ensure_dir ()
1428+
1429+ # Create a worktree with a different name
1430+ worktrees_dir = main_repo_dir / ".worktrees"
1431+ worktrees_dir .ensure_dir ()
1432+ worktree_dir = worktrees_dir / "my_feature_branch"
1433+ worktree_dir .ensure_dir ()
1434+
1435+ # Create a .git file (worktree indicator)
1436+ git_file = worktree_dir / ".git"
1437+ git_file .write_text ("gitdir: /path/to/main/.git/worktrees/my_feature_branch" )
1438+
1439+ # Mock git remote detection to return the correct repository name
1440+ mock_remote = mocker .MagicMock ()
1441+ mock_remote .repo = "datadog-agent"
1442+ mocker .patch ("dda.tools.git.Git.get_remote" , return_value = mock_remote )
1443+
1444+ write_server_config = mocker .patch ("dda.utils.ssh.write_server_config" )
1445+ with (
1446+ worktree_dir .as_cwd (),
1447+ helpers .hybrid_patch (
1448+ "subprocess.run" ,
1449+ return_values = {
1450+ # Start command checks the status
1451+ 1 : CompletedProcess ([], returncode = 0 , stdout = "{}" ),
1452+ # Start method checks the status
1453+ 2 : CompletedProcess ([], returncode = 0 , stdout = "{}" ),
1454+ # Capture image pull
1455+ # Capture container run
1456+ # Readiness check
1457+ 5 : CompletedProcess ([], returncode = 0 , stdout = "Server listening on :: port 22" ),
1458+ },
1459+ ) as calls ,
1460+ ):
1461+ result = dda ("env" , "dev" , "start" )
1462+
1463+ result .check (
1464+ exit_code = 0 ,
1465+ output = helpers .dedent (
1466+ """
1467+ Pulling image: datadog/agent-dev-env-linux
1468+ Creating and starting container: dda-linux-container-default
1469+ Waiting for container: dda-linux-container-default
1470+ """
1471+ ),
1472+ )
1473+
1474+ assert_ssh_config_written (write_server_config , "localhost" )
1475+
1476+ # Verify that the worktree directory (not parent/datadog-agent) is mounted
1477+ shared_dir = temp_dir / "data" / "env" / "dev" / "linux-container" / "default" / ".shared"
1478+ global_shared_dir = shared_dir .parent .parent / ".shared"
1479+ starship_mount = get_starship_mount (global_shared_dir )
1480+ cache_volumes = get_cache_volumes ()
1481+
1482+ # Check that the docker run command includes the worktree directory
1483+ docker_run_call = calls [1 ]
1484+ assert "-v" in docker_run_call [0 ][0 ]
1485+ mount_arg_idx = docker_run_call [0 ][0 ].index ("-v" )
1486+ # Find the repo mount (should be the worktree directory)
1487+ repo_mounts = [
1488+ docker_run_call [0 ][0 ][i + 1 ]
1489+ for i , arg in enumerate (docker_run_call [0 ][0 ])
1490+ if arg == "-v" and ":/root/repos/datadog-agent" in docker_run_call [0 ][0 ][i + 1 ]
1491+ ]
1492+ assert len (repo_mounts ) == 1
1493+ assert str (worktree_dir ) in repo_mounts [0 ]
1494+
1495+ def test_current_directory_is_repo (self , dda , helpers , mocker , temp_dir , host_user_args ):
1496+ """Test that the current directory is used if it's a matching git repository."""
1497+ repos_dir = temp_dir / "repos"
1498+ repos_dir .ensure_dir ()
1499+ repo_dir = repos_dir / "datadog-agent"
1500+ repo_dir .ensure_dir ()
1501+
1502+ # Create a .git directory
1503+ git_dir = repo_dir / ".git"
1504+ git_dir .ensure_dir ()
1505+
1506+ # Mock git remote detection
1507+ mock_remote = mocker .MagicMock ()
1508+ mock_remote .repo = "datadog-agent"
1509+ mocker .patch ("dda.tools.git.Git.get_remote" , return_value = mock_remote )
1510+
1511+ write_server_config = mocker .patch ("dda.utils.ssh.write_server_config" )
1512+ with (
1513+ repo_dir .as_cwd (),
1514+ helpers .hybrid_patch (
1515+ "subprocess.run" ,
1516+ return_values = {
1517+ # Start command checks the status
1518+ 1 : CompletedProcess ([], returncode = 0 , stdout = "{}" ),
1519+ # Start method checks the status
1520+ 2 : CompletedProcess ([], returncode = 0 , stdout = "{}" ),
1521+ # Capture image pull
1522+ # Capture container run
1523+ # Readiness check
1524+ 5 : CompletedProcess ([], returncode = 0 , stdout = "Server listening on :: port 22" ),
1525+ },
1526+ ) as calls ,
1527+ ):
1528+ result = dda ("env" , "dev" , "start" )
1529+
1530+ result .check (exit_code = 0 )
1531+
1532+ # Verify the current directory is used
1533+ docker_run_call = calls [1 ]
1534+ repo_mounts = [
1535+ docker_run_call [0 ][0 ][i + 1 ]
1536+ for i , arg in enumerate (docker_run_call [0 ][0 ])
1537+ if arg == "-v" and ":/root/repos/datadog-agent" in docker_run_call [0 ][0 ][i + 1 ]
1538+ ]
1539+ assert len (repo_mounts ) == 1
1540+ assert str (repo_dir ) in repo_mounts [0 ]
1541+
1542+ def test_backward_compatibility_non_git_directory (self , dda , helpers , mocker , temp_dir , host_user_args ):
1543+ """Test backward compatibility: non-git directories are still found via parent directory."""
1544+ repos_dir = temp_dir / "repos"
1545+ repos_dir .ensure_dir ()
1546+ repo_dir = repos_dir / "datadog-agent"
1547+ repo_dir .ensure_dir ()
1548+
1549+ # Don't create .git directory - this is a non-git directory
1550+ # Mock git to fail (no remote available)
1551+ mocker .patch ("dda.tools.git.Git.get_remote" , side_effect = Exception ("Not a git repository" ))
1552+
1553+ write_server_config = mocker .patch ("dda.utils.ssh.write_server_config" )
1554+ with (
1555+ repo_dir .as_cwd (),
1556+ helpers .hybrid_patch (
1557+ "subprocess.run" ,
1558+ return_values = {
1559+ # Start command checks the status
1560+ 1 : CompletedProcess ([], returncode = 0 , stdout = "{}" ),
1561+ # Start method checks the status
1562+ 2 : CompletedProcess ([], returncode = 0 , stdout = "{}" ),
1563+ # Capture image pull
1564+ # Capture container run
1565+ # Readiness check
1566+ 5 : CompletedProcess ([], returncode = 0 , stdout = "Server listening on :: port 22" ),
1567+ },
1568+ ) as calls ,
1569+ ):
1570+ result = dda ("env" , "dev" , "start" )
1571+
1572+ result .check (exit_code = 0 )
1573+
1574+ # Verify that the parent directory lookup worked
1575+ docker_run_call = calls [1 ]
1576+ repo_mounts = [
1577+ docker_run_call [0 ][0 ][i + 1 ]
1578+ for i , arg in enumerate (docker_run_call [0 ][0 ])
1579+ if arg == "-v" and ":/root/repos/datadog-agent" in docker_run_call [0 ][0 ][i + 1 ]
1580+ ]
1581+ assert len (repo_mounts ) == 1
1582+ assert str (repo_dir ) in repo_mounts [0 ]
1583+
1584+ def test_repo_not_found_error (self , dda , helpers , mocker , temp_dir ):
1585+ """Test that appropriate error is shown when repository cannot be found."""
1586+ # Don't create any repository directory
1587+ mocker .patch ("dda.tools.git.Git.get_remote" , side_effect = Exception ("Not a git repository" ))
1588+
1589+ with (
1590+ temp_dir .as_cwd (),
1591+ helpers .hybrid_patch (
1592+ "subprocess.run" ,
1593+ return_values = {
1594+ # Start command checks the status
1595+ 1 : CompletedProcess ([], returncode = 0 , stdout = "{}" ),
1596+ # Start method checks the status
1597+ 2 : CompletedProcess ([], returncode = 0 , stdout = "{}" ),
1598+ },
1599+ ),
1600+ ):
1601+ result = dda ("env" , "dev" , "start" )
1602+
1603+ result .check (
1604+ exit_code = 1 ,
1605+ output = mocker .ANY , # Just check it errors, message may vary
1606+ )
1607+ assert "Local repository not found: datadog-agent" in result .output
1608+
1609+
14181610class TestImportFiles :
14191611 """Basic import operations."""
14201612
0 commit comments