|
| 1 | +# Copilot Instructions |
| 2 | + |
| 3 | +## Commands |
| 4 | + |
| 5 | +```bash |
| 6 | +# Install |
| 7 | +uv pip install -e ".[dev]" # dev extras |
| 8 | +uv pip install -e ".[test]" # test extras |
| 9 | + |
| 10 | +# Test |
| 11 | +python -m pytest # full suite |
| 12 | +python -m pytest tests/test_install_command.py -v # single file |
| 13 | +python -m pytest tests/test_install_command.py::test_install_basic_success -v # single test |
| 14 | +python -m pytest --cov=dbx --cov-report=term-missing # with coverage |
| 15 | + |
| 16 | +# Build |
| 17 | +python -m build |
| 18 | +``` |
| 19 | + |
| 20 | +Pre-commit hooks (ruff lint + format, toml/yaml checks) run on `git commit`. To apply ruff formatting manually: `ruff format src/`. |
| 21 | + |
| 22 | +## Architecture |
| 23 | + |
| 24 | +`dbx` is a Typer CLI tool for managing a local workspace of multiple git repositories, grouped by project area. The entry point is `src/dbx_python_cli/cli.py`, which mounts each command module as a sub-`typer.Typer` app. |
| 25 | + |
| 26 | +### Config system |
| 27 | + |
| 28 | +Config is loaded from `~/.config/dbx-python-cli/config.toml` (user) with fallback to the bundled `src/dbx_python_cli/config.toml`. The config drives almost all behavior — commands rarely have hardcoded paths or group names. |
| 29 | + |
| 30 | +Key config sections: |
| 31 | +- `[repo]` — `base_dir`, `flat`, `global_groups`, `group_priority`, `fork_user`, `python_version`, `editor` |
| 32 | +- `[repo.groups.<name>]` — per-group settings: `repos`, `python_version`, `test_env`, `install_extras`, `install_dirs`, `build_commands`, `install_groups`, `test_runner`, `test_runner_args`, `preferred_branch`, `sys_path`, `skip_install` |
| 33 | +- `[project.*]` — Django project defaults (MongoDB backend, edition, runner config) |
| 34 | +- `[evergreen.<repo>]` — Evergreen CI project name mappings |
| 35 | + |
| 36 | +### Flat mode vs grouped mode |
| 37 | + |
| 38 | +`flat = true` in `[repo]` means repos live directly under `base_dir`. Grouped mode (default) uses `base_dir/<group>/<repo>`. All path helpers in `utils/repo.py` (`get_group_dir`, `get_repo_dir`, `get_projects_dir`) accept a `flat` flag — always derive it from `is_flat_mode(config)`. |
| 39 | + |
| 40 | +### Global groups |
| 41 | + |
| 42 | +Groups listed in `repo.global_groups` are not cloned into their own subdirectory. Their repos are installed into every other group's venv. Functions like `get_test_env_vars()` and install helpers fall back to global groups when a repo's own group has no config for it. |
| 43 | + |
| 44 | +### Command pattern |
| 45 | + |
| 46 | +Every command module follows this shape: |
| 47 | + |
| 48 | +```python |
| 49 | +app = typer.Typer( |
| 50 | + help="...", |
| 51 | + invoke_without_command=True, |
| 52 | + context_settings={"help_option_names": ["-h", "--help"]}, |
| 53 | +) |
| 54 | + |
| 55 | +@app.callback() |
| 56 | +def my_command(ctx: typer.Context, ...): |
| 57 | + verbose = ctx.obj.get("verbose", False) if ctx.obj else False |
| 58 | + config = get_config() |
| 59 | + base_dir = get_base_dir(config) |
| 60 | + ... |
| 61 | +``` |
| 62 | + |
| 63 | +`ctx.obj` carries top-level flags: `verbose`, `pager`, `mongodb_backend`, `mongodb_edition`. Commands are registered in `cli.py` with `app.add_typer(module.app, name="command-name")`. |
| 64 | + |
| 65 | +### Key utilities (`utils/repo.py`) |
| 66 | + |
| 67 | +All config lookups go through helpers — never access `config["repo"]["groups"]` directly: |
| 68 | +- `get_repo_groups(config)` — all groups dict |
| 69 | +- `get_global_groups(config)` — list of global group names |
| 70 | +- `get_group_priority(config)` — ordered list for conflict resolution |
| 71 | +- `is_flat_mode(config)` — bool |
| 72 | +- `find_all_repos(base_dir, config)` — discovers cloned repos respecting flat/grouped layout |
| 73 | +- `find_repo_by_name(name, base_dir, config)` — finds a repo with group priority applied |
| 74 | +- `get_test_env_vars(config, group_name, repo_name)` — resolves env vars with global group fallback |
| 75 | + |
| 76 | +## Testing conventions |
| 77 | + |
| 78 | +- Tests use `pytest` with `typer.testing.CliRunner` to invoke commands end-to-end. |
| 79 | +- Common patches: `dbx_python_cli.commands.<module>.get_config`, `subprocess.run`, `subprocess.check_call`. |
| 80 | +- `tests/conftest.py` provides shared fixtures (`cli_runner`, temp directory helpers). |
| 81 | +- Integration tests live in `tests/integration/` and may require real filesystem state. |
| 82 | +- Mock the config dict directly rather than the TOML file: |
| 83 | + ```python |
| 84 | + with patch("dbx_python_cli.commands.list.get_config", return_value={ |
| 85 | + "repo": {"base_dir": str(tmp_path), "flat": True, "groups": {...}} |
| 86 | + }): |
| 87 | + ``` |
0 commit comments