diff --git a/.gitignore b/.gitignore index b75a945..6679fc3 100644 --- a/.gitignore +++ b/.gitignore @@ -219,3 +219,7 @@ __marimo__/ plans/**/* !plans/templates/* repomix-output.xml +AGENTS.md +.claude/ +.opencode/ +release-manifest.json diff --git a/.repomixignore b/.repomixignore new file mode 100644 index 0000000..c9bb5df --- /dev/null +++ b/.repomixignore @@ -0,0 +1,22 @@ +docs/* +plans/* +assets/* +dist/* +coverage/* +build/* +ios/* +android/* +tests/* +__tests__/* +__pycache__/* +node_modules/* + +.opencode/* +.claude/* +.serena/* +.pnpm-store/* +.github/* +.dart_tool/* +.idea/* +.husky/* +.venv/* diff --git a/docs/code-standards.md b/docs/code-standards.md index 39bcb00..517bc38 100644 --- a/docs/code-standards.md +++ b/docs/code-standards.md @@ -74,7 +74,7 @@ Config validated at startup. Early detection prevents side effects on invalid in ### Input Validation - **Regex patterns** - All config fields validated with specific patterns: - - Versions: `^\d+\.\d+$` + - Versions: `^(?:\d+\.\d+|master)$` (supports semver and "master" branch) - UV tools: `^[a-zA-Z0-9][a-zA-Z0-9._\-\[\]@=<>!,]*$` - Repo names: `^[a-zA-Z0-9._-]+$` - **Pydantic models** - No ad-hoc parsing of config @@ -169,12 +169,12 @@ Follow [Conventional Commits](https://www.conventionalcommits.org/): ## File Structure **Max file size**: 500 LOC (split if larger) -- `main.py`: CLI commands and orchestration (452 LOC) -- `installers.py`: Installation strategies (282 LOC) -- `utils.py`: Config, platform detection, helpers (264 LOC) -- `concurrency.py`: Task runner with progress (60 LOC) -- `exceptions.py`: Custom exception classes (38 LOC) -- `tests/`: pytest unit tests for all modules +- `main.py`: CLI commands and orchestration (455 LOC) +- `installers.py`: Installation strategies (283 LOC) +- `utils.py`: Config, platform detection, helpers (275 LOC) +- `concurrency.py`: Task runner with progress (61 LOC) +- `exceptions.py`: Custom exception classes (39 LOC) +- `tests/`: pytest unit tests (613 LOC total, 69% coverage) **Imports in each module**: - No circular imports diff --git a/docs/codebase-summary.md b/docs/codebase-summary.md index 29b7e9a..80a61aa 100644 --- a/docs/codebase-summary.md +++ b/docs/codebase-summary.md @@ -6,17 +6,18 @@ Technical overview of the `trobz_local` codebase structure, implementation patte | Metric | Value | |---|---| -| **Language** | Python 3.12+ | -| **Total LOC** | ~1,096 lines (core logic) + tests | -| **Core Modules** | 6 files (main, installers, utils, concurrency, exceptions, \__init\_\_) | -| **Test Modules** | tests/ directory with pytest unit tests | +| **Language** | Python 3.10+ | +| **Core LOC** | 1,109 lines (production code across 6 files) | +| **Test LOC** | 613 lines (4 test files, 69% coverage, 20 passing tests) | +| **Core Modules** | 6 files: main (455), installers (282), utils (274), concurrency (60), exceptions (38), __init__ (0) | +| **Test Modules** | test_pull_repos (211), test_install_tools (253), test_create_venvs (123), test_utils (26) | | **Primary Frameworks** | Typer (CLI), Pydantic (validation), Rich (UI), GitPython (git) | | **Concurrency Model** | ThreadPoolExecutor, max 4 workers, I/O-bound tasks | | **License** | AGPL-3.0 | ## Module Breakdown -### `main.py` (452 LOC) +### `main.py` (455 LOC) **Purpose**: CLI entry point and command orchestration **Responsibilities**: @@ -41,7 +42,7 @@ Technical overview of the `trobz_local` codebase structure, implementation patte --- -### `installers.py` (282 LOC) +### `installers.py` (283 LOC) **Purpose**: Multi-source tool installation strategies **Strategies**: @@ -64,7 +65,7 @@ Technical overview of the `trobz_local` codebase structure, implementation patte --- -### `utils.py` (264 LOC) +### `utils.py` (275 LOC) **Purpose**: Configuration validation, platform detection, utilities **Pydantic Models**: @@ -74,13 +75,14 @@ Technical overview of the `trobz_local` codebase structure, implementation patte - `RepoConfig` - Repository definitions (odoo, oca) **Validation**: -- Versions: Pattern `^\d+\.\d+$` +- Versions: Pattern `^(?:\d+\.\d+|master)$` (supports semver and "master" branch) - UV tools: Pattern `^[a-zA-Z0-9][a-zA-Z0-9._\-\[\]@=<>!,]*$` - NPM packages: Scoped and unscoped validation - Scripts: HTTPS-only enforcement - Repo names: Pattern `^[a-zA-Z0-9._-]+$` **Key Functions**: +- `get_code_root()` - Resolve code root directory from TLC_CODE_DIR env var or default to ~/code - `get_config()` - Load and validate config.toml with error handling - `get_uv_path()` - Locate uv executable - `get_os_info()` - Return {system, distro} for platform detection @@ -91,7 +93,7 @@ Technical overview of the `trobz_local` codebase structure, implementation patte --- -### `concurrency.py` (60 LOC) +### `concurrency.py` (61 LOC) **Purpose**: Generic parallel task execution with progress tracking **TaskResult Dataclass**: @@ -113,7 +115,7 @@ class TaskResult: --- -### `exceptions.py` (38 LOC) +### `exceptions.py` (39 LOC) **Purpose**: Custom exception hierarchy for granular error handling **Exception Classes**: @@ -162,6 +164,8 @@ The `get_code_root()` function (utils.py) resolves the code root directory by: 1. First checking for `TLC_CODE_DIR` environment variable 2. Falling back to `~/code` if not set +This enables flexible deployment: developers can customize the base directory via environment variable while maintaining consistent configuration file location at `{CODE_ROOT}/config.toml`. + --- ## External Dependencies diff --git a/docs/project-overview-pdr.md b/docs/project-overview-pdr.md index b95fca9..e42a00c 100644 --- a/docs/project-overview-pdr.md +++ b/docs/project-overview-pdr.md @@ -122,10 +122,11 @@ oca = ["server-tools", "server-ux", "web"] ### Field Reference & Validation #### `versions` (Required) -Odoo versions to set up. Format: Major.Minor (e.g., "16.0", "17.0") +Odoo versions to set up. Supports semantic versioning (Major.Minor) or "master" branch. - **Type**: List of strings -- **Pattern**: `^\d+\.\d+$` -- **Example**: `["16.0", "17.0", "18.0"]` +- **Pattern**: `^(?:\d+\.\d+|master)$` +- **Examples**: `["16.0", "17.0", "18.0"]` or `["master", "17.0"]` +- **Note**: "master" branch for development, semver (16.0, 17.0) for stable releases #### `tools.uv` (Optional) UV tools to install globally via `uv tool install` @@ -188,7 +189,7 @@ System packages are automatically merged with defaults for your OS: **Valid configurations:** ```toml -versions = ["16.0", "17.0"] # ✓ Correct format +versions = ["16.0", "17.0", "master"] # ✓ Correct format with master branch tools.uv = ["package[extra]@1.0", "tool"] # ✓ Supports extras syntax tools.npm = ["@babel/core", "prettier"] # ✓ Scoped and unscoped repos.odoo = ["odoo", "enterprise"] # ✓ Both sources @@ -197,7 +198,8 @@ repos.oca = ["server-tools", "web"] # ✓ Valid names **Invalid configurations:** ```toml -versions = ["16", "17.0"] # ✗ First version invalid format +versions = ["16", "17.0"] # ✗ First version invalid (missing minor) +versions = ["main", "17.0"] # ✗ "main" not supported (use "master") tools.uv = [" invalid"] # ✗ Leading space tools.npm = ["__invalid"] # ✗ Double underscore tools.script = [{url = "http://..."}] # ✗ HTTP not allowed (HTTPS only) diff --git a/docs/system-architecture.md b/docs/system-architecture.md index 3536a18..df11561 100644 --- a/docs/system-architecture.md +++ b/docs/system-architecture.md @@ -497,6 +497,12 @@ Script Execution - Can be customized per operation type if needed - Example: `run_tasks(tasks, max_workers=8)` for more parallelization +### Version Support +- **Semantic Versioning**: "16.0", "17.0", "18.0" (standard Odoo releases) +- **Master Branch**: "master" for development/cutting-edge versions +- **Pattern**: `^(?:\d+\.\d+|master)$` enforced via Pydantic validation +- **Branch Mapping**: Version strings map to git branch names during pull-repos + --- ## Performance Characteristics diff --git a/trobz_local/utils.py b/trobz_local/utils.py index 9d740f5..3a64543 100644 --- a/trobz_local/utils.py +++ b/trobz_local/utils.py @@ -15,7 +15,7 @@ ) TOOL_NAME_REGEX = re.compile(r"^[a-zA-Z0-9][a-zA-Z0-9._\-\[\]@=<>!,]*$") -VERSION_REGEX = re.compile(r"^\d+\.\d+$") +VERSION_REGEX = re.compile(r"^(?:\d+\.\d+|master)$") ARCH_PACKAGES = [ "gcc",