Skip to content

Commit db102dc

Browse files
committed
feat: allow dbx test and dbx just to accept '.' or any path as repo argument
- Import find_repo_by_path in test.py and just.py - Add path detection (., .., absolute/relative paths) in the no-group lookup branch of both commands - Update repo_name to the real name after path resolution so test-runner config lookups, env-var lookups, and output messages are correct - Add tests for path lookup from repo root and from an unmanaged directory in both test_test_command.py and test_just_command.py
1 parent 2bef523 commit db102dc

4 files changed

Lines changed: 155 additions & 36 deletions

File tree

src/dbx_python_cli/commands/just.py

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
find_all_repos,
1313
find_all_repos_by_name,
1414
find_repo_by_name,
15+
find_repo_by_path,
1516
get_base_dir,
1617
get_config,
1718
get_global_groups,
@@ -129,25 +130,46 @@ def _run_just_in_repo(
129130
"group": group,
130131
}
131132
else:
132-
# Find repo by name across all groups
133-
repo = find_repo_by_name(repo_name, base_dir, config)
134-
if not repo:
135-
typer.echo(f"❌ Error: Repository '{repo_name}' not found", err=True)
136-
typer.echo("\nRun 'dbx list' to see available repositories")
137-
raise typer.Exit(1)
133+
# Detect path-like inputs: ".", "..", absolute paths, relative paths with /
134+
_is_path_like = (
135+
repo_name in (".", "..")
136+
or repo_name.startswith(("./", "../", "/", "~/"))
137+
or "/" in repo_name
138+
or Path(repo_name).is_dir()
139+
)
138140

139-
# Check if repo exists in multiple groups
140-
all_matches = find_all_repos_by_name(repo_name, base_dir, config)
141-
if len(all_matches) > 1:
142-
groups = [r["group"] for r in all_matches]
143-
typer.echo(
144-
f"⚠️ Warning: '{repo_name}' exists in multiple groups: {', '.join(groups)}",
145-
err=True,
146-
)
147-
typer.echo(
148-
f"⚠️ Using '{repo['group']}' group. Specify -g <group> to use a different one.\n",
149-
err=True,
150-
)
141+
if _is_path_like:
142+
repo = find_repo_by_path(repo_name, base_dir, config)
143+
if not repo:
144+
typer.echo(
145+
f"❌ Error: No managed repository found at '{Path(repo_name).resolve()}'",
146+
err=True,
147+
)
148+
typer.echo("\nRun 'dbx list' to see available repositories")
149+
raise typer.Exit(1)
150+
# Update repo_name so env-var lookups and messages use the real name
151+
repo_name = repo["name"]
152+
else:
153+
# Find repo by name across all groups
154+
repo = find_repo_by_name(repo_name, base_dir, config)
155+
if not repo:
156+
typer.echo(f"❌ Error: Repository '{repo_name}' not found", err=True)
157+
typer.echo("\nRun 'dbx list' to see available repositories")
158+
raise typer.Exit(1)
159+
160+
# Check if repo exists in multiple groups (name-based lookup only)
161+
if not _is_path_like:
162+
all_matches = find_all_repos_by_name(repo_name, base_dir, config)
163+
if len(all_matches) > 1:
164+
groups = [r["group"] for r in all_matches]
165+
typer.echo(
166+
f"⚠️ Warning: '{repo_name}' exists in multiple groups: {', '.join(groups)}",
167+
err=True,
168+
)
169+
typer.echo(
170+
f"⚠️ Using '{repo['group']}' group. Specify -g <group> to use a different one.\n",
171+
err=True,
172+
)
151173

152174
repo_path = Path(repo["path"])
153175

src/dbx_python_cli/commands/test.py

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from dbx_python_cli.utils.repo import (
1212
find_repo_by_name,
13+
find_repo_by_path,
1314
find_all_repos_by_name,
1415
get_base_dir,
1516
get_config,
@@ -159,25 +160,46 @@ def test_callback(
159160
"group": group,
160161
}
161162
else:
162-
# Default behavior: find repo by name across all groups
163-
repo = find_repo_by_name(repo_name, base_dir, config)
164-
if not repo:
165-
typer.echo(f"Error: Repository '{repo_name}' not found.", err=True)
166-
typer.echo("Run 'dbx list' to see available repositories.", err=True)
167-
raise typer.Exit(1)
163+
# Detect path-like inputs: ".", "..", absolute paths, relative paths with /
164+
_is_path_like = (
165+
repo_name in (".", "..")
166+
or repo_name.startswith(("./", "../", "/", "~/"))
167+
or "/" in repo_name
168+
or Path(repo_name).is_dir()
169+
)
168170

169-
# Check if repo exists in multiple groups
170-
all_matches = find_all_repos_by_name(repo_name, base_dir, config)
171-
if len(all_matches) > 1:
172-
groups = [r["group"] for r in all_matches]
173-
typer.echo(
174-
f"⚠️ Warning: '{repo_name}' exists in multiple groups: {', '.join(groups)}",
175-
err=True,
176-
)
177-
typer.echo(
178-
f"⚠️ Using '{repo['group']}' group. Specify -g <group> to use a different one.\n",
179-
err=True,
180-
)
171+
if _is_path_like:
172+
repo = find_repo_by_path(repo_name, base_dir, config)
173+
if not repo:
174+
typer.echo(
175+
f"Error: No managed repository found at '{Path(repo_name).resolve()}'.",
176+
err=True,
177+
)
178+
typer.echo("Run 'dbx list' to see available repositories.", err=True)
179+
raise typer.Exit(1)
180+
# Update repo_name so test-runner config lookups and messages use real name
181+
repo_name = repo["name"]
182+
else:
183+
# Default behavior: find repo by name across all groups
184+
repo = find_repo_by_name(repo_name, base_dir, config)
185+
if not repo:
186+
typer.echo(f"Error: Repository '{repo_name}' not found.", err=True)
187+
typer.echo("Run 'dbx list' to see available repositories.", err=True)
188+
raise typer.Exit(1)
189+
190+
# Check if repo exists in multiple groups (name-based lookup only)
191+
if not _is_path_like:
192+
all_matches = find_all_repos_by_name(repo_name, base_dir, config)
193+
if len(all_matches) > 1:
194+
groups = [r["group"] for r in all_matches]
195+
typer.echo(
196+
f"⚠️ Warning: '{repo_name}' exists in multiple groups: {', '.join(groups)}",
197+
err=True,
198+
)
199+
typer.echo(
200+
f"⚠️ Using '{repo['group']}' group. Specify -g <group> to use a different one.\n",
201+
err=True,
202+
)
181203

182204
repo_path = repo["path"]
183205
# Use repo's own group

tests/test_just_command.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,43 @@ def test_just_repo_not_found(tmp_path, temp_repos_dir, mock_config):
9999
assert "not found" in output or "available repositories" in output
100100

101101

102+
def test_just_dot_from_repo_root(tmp_path, temp_repos_dir, mock_config, monkeypatch):
103+
"""Test that '.' resolves to the repo at the current directory."""
104+
repo_dir = temp_repos_dir / "pymongo" / "mongo-python-driver"
105+
106+
monkeypatch.chdir(repo_dir)
107+
108+
with patch("dbx_python_cli.utils.repo.get_config_path") as mock_get_path:
109+
with patch(
110+
"dbx_python_cli.commands.just.ensure_mongodb",
111+
side_effect=lambda e, *a, **k: e,
112+
):
113+
with patch("subprocess.run") as mock_run:
114+
mock_get_path.return_value = mock_config
115+
mock_run.return_value = MagicMock(returncode=0)
116+
117+
result = runner.invoke(app, ["just", ".", "test"])
118+
assert result.exit_code == 0
119+
assert "Running 'just test' in" in result.stdout
120+
args = mock_run.call_args[0][0]
121+
assert args == ["just", "test"]
122+
123+
124+
def test_just_dot_not_in_managed_repo(tmp_path, temp_repos_dir, mock_config, monkeypatch):
125+
"""Test that '.' in an unmanaged directory gives a clear error."""
126+
unrelated = tmp_path / "unrelated"
127+
unrelated.mkdir()
128+
monkeypatch.chdir(unrelated)
129+
130+
with patch("dbx_python_cli.utils.repo.get_config_path") as mock_get_path:
131+
mock_get_path.return_value = mock_config
132+
133+
result = runner.invoke(app, ["just", "."])
134+
assert result.exit_code == 1
135+
output = result.stdout + result.stderr
136+
assert "No managed repository found" in output
137+
138+
102139
def test_just_no_justfile(tmp_path, temp_repos_dir, mock_config):
103140
"""Test that just with repo without justfile shows warning."""
104141
with patch(

tests/test_test_command.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,44 @@ def test_test_nonexistent_repo(mock_config, temp_repos_dir):
9696
assert "Repository 'nonexistent-repo' not found" in output
9797

9898

99+
def test_test_dot_from_repo_root(mock_config, temp_repos_dir, monkeypatch):
100+
"""Test that '.' resolves to the repo at the current directory."""
101+
repo_dir = temp_repos_dir / "pymongo" / "mongo-python-driver"
102+
103+
monkeypatch.chdir(repo_dir)
104+
105+
with patch("dbx_python_cli.utils.repo.get_config_path") as mock_get_path:
106+
with patch("dbx_python_cli.commands.test.get_venv_info") as mock_venv:
107+
with patch("subprocess.run") as mock_run:
108+
with patch.dict("os.environ", {"MONGODB_URI": "mongodb://localhost:27017"}):
109+
mock_get_path.return_value = mock_config
110+
mock_venv.return_value = ("python", "venv")
111+
112+
mock_result = MagicMock()
113+
mock_result.returncode = 0
114+
mock_run.return_value = mock_result
115+
116+
result = runner.invoke(app, ["test", "."])
117+
assert result.exit_code == 0
118+
assert "Running pytest" in result.stdout
119+
assert "Tests passed in mongo-python-driver" in result.stdout
120+
121+
122+
def test_test_dot_not_in_managed_repo(mock_config, temp_repos_dir, monkeypatch):
123+
"""Test that '.' in an unmanaged directory gives a clear error."""
124+
unrelated = temp_repos_dir / "unrelated"
125+
unrelated.mkdir()
126+
monkeypatch.chdir(unrelated)
127+
128+
with patch("dbx_python_cli.utils.repo.get_config_path") as mock_get_path:
129+
mock_get_path.return_value = mock_config
130+
131+
result = runner.invoke(app, ["test", "."])
132+
assert result.exit_code == 1
133+
output = result.stdout + result.stderr
134+
assert "No managed repository found" in output
135+
136+
99137
def test_test_runs_pytest_success(mock_config, temp_repos_dir):
100138
"""Test that test runs pytest successfully."""
101139
with patch("dbx_python_cli.utils.repo.get_config_path") as mock_get_path:

0 commit comments

Comments
 (0)