Skip to content

Commit a10ab01

Browse files
committed
Clean up markdown files
1 parent 84a23d1 commit a10ab01

File tree

10 files changed

+183
-1132
lines changed

10 files changed

+183
-1132
lines changed

docs/technical/adding-new-detectors.md

Lines changed: 63 additions & 190 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ The dependency resolver uses a modular detector architecture where each package
1010

1111
Before adding a new detector, ensure you understand:
1212

13-
1. **Architecture Decision Records (ADRs)**: Review `/docs/adr/` for design principles
13+
1. **Architecture Decision Records (ADRs)**: Review `/docs/technical/architecture/adr/` for design principles
1414
2. **Existing Detectors**: Study `/dependency_resolver/detectors/` implementations
1515
3. **Interface Contracts**: Understand `PackageManagerDetector` in `/dependency_resolver/core/interfaces.py`
1616
4. **Testing Patterns**: Review `/tests/detectors/` structure
@@ -19,40 +19,13 @@ Before adding a new detector, ensure you understand:
1919

2020
### 1.1 Create the Detector File
2121

22-
Create `/dependency_resolver/detectors/{package_manager}_detector.py`:
22+
Create `/dependency_resolver/detectors/{package_manager}_detector.py` implementing the `PackageManagerDetector` interface with these required methods:
2323

24-
```python
25-
from typing import Optional, Any
26-
from ..core.interfaces import EnvironmentExecutor, PackageManagerDetector
27-
28-
29-
class {PackageManager}Detector(PackageManagerDetector):
30-
"""Detector for {Package Manager Description}."""
31-
32-
NAME = "{package_manager}"
33-
34-
def __init__(self, debug: bool = False):
35-
self.debug = debug
36-
37-
def is_usable(self, executor: EnvironmentExecutor, working_dir: Optional[str] = None) -> bool:
38-
"""Check if {package_manager} is usable in the environment."""
39-
# Implement OS compatibility check if needed
40-
# Check if package manager tool is available
41-
_, _, exit_code = executor.execute_command("{package_manager} --version", working_dir)
42-
return exit_code == 0
43-
44-
def get_dependencies(self, executor: EnvironmentExecutor, working_dir: Optional[str] = None) -> dict[str, Any]:
45-
"""Extract {package_manager} dependencies with versions."""
46-
# Implement dependency extraction logic
47-
# Return format: {"scope": "system|project", "location": "path", "dependencies": {}, "hash": "sha256"}
48-
pass
49-
50-
def has_system_scope(self, executor: EnvironmentExecutor, working_dir: Optional[str] = None) -> bool:
51-
"""Check if this detector operates at system scope."""
52-
# Return True for system-wide package managers (dpkg, apk)
53-
# Return False or implement logic for project-scoped managers (pip, npm)
54-
pass
55-
```
24+
- `__init__(self, debug: bool = False)`: Initialize detector with debug flag
25+
- `is_usable()`: Check if package manager is available in the environment
26+
- `get_dependencies()`: Extract package dependencies with versions and metadata
27+
- `has_system_scope()`: Determine if detector operates at system or project scope
28+
- `get_name()`: Return the detector name (inherited from base class)
5629

5730
### 1.2 Key Implementation Considerations
5831

@@ -89,30 +62,16 @@ class {PackageManager}Detector(PackageManagerDetector):
8962

9063
### 2.1 Update the Orchestrator
9164

92-
Add your detector to `/dependency_resolver/core/orchestrator.py`:
93-
94-
```python
95-
from ..detectors.{package_manager}_detector import {PackageManager}Detector
96-
97-
class Orchestrator:
98-
def __init__(self, ...):
99-
# Add to detectors list in priority order
100-
self.detectors: list[PackageManagerDetector] = [
101-
DockerInfoDetector(),
102-
DpkgDetector(),
103-
ApkDetector(),
104-
{PackageManager}Detector(debug=debug), # Add here
105-
PipDetector(venv_path=venv_path, debug=debug),
106-
NpmDetector(debug=debug),
107-
]
108-
```
65+
Add your detector to the detectors list in `/dependency_resolver/core/orchestrator.py` following the priority order:
10966

11067
**Priority Ordering**:
11168

11269
1. Container information (docker-info)
11370
2. System packages (dpkg, apk, yum, etc.)
11471
3. Language-specific packages (pip, npm, etc.)
11572

73+
Reference existing detectors like `DpkgDetector`, `ApkDetector`, `PipDetector`, and `NpmDetector` for import and initialization patterns.
74+
11675
### 2.2 Update Package Imports
11776

11877
Add to `/dependency_resolver/detectors/__init__.py` if needed.
@@ -132,144 +91,61 @@ Create `/docs/technical/detectors/{package_manager}_detector.md` with the follow
13291
- **Limitations**: Known limitations or edge cases
13392
- **Example Output**: JSON sample showing expected output format
13493

135-
**Example JSON Output Format:**
94+
**Expected JSON Output Format:**
13695

137-
```json
138-
{
139-
"scope": "system",
140-
"dependencies": {
141-
"package1": {"version": "1.0.0", "hash": "sha256..."},
142-
"package2": {"version": "2.0.0", "hash": "sha256..."}
143-
},
144-
"hash": "sha256..."
145-
}
146-
```
96+
Standard output includes `scope`, `dependencies` dict with package names and versions, and optional `hash` and `location` fields. Reference existing detector documentation for specific examples.
14797

14898
## Step 4: Implement Tests
14999

150100
### 4.1 Test Directory Structure
151101

152-
Create `/tests/detectors/{package_manager}/`:
102+
Create `/tests/detectors/{package_manager}/` with:
153103

154-
```plain
155-
tests/detectors/{package_manager}/
156-
├── __init__.py
157-
├── README.md
158-
└── test_{package_manager}_docker_detection.py
159-
```
104+
- `__init__.py`
105+
- `README.md`
106+
- `test_{package_manager}_docker_detection.py`
160107

161108
### 4.2 Docker Test Implementation
162109

163-
Create `/tests/detectors/{package_manager}/test_{package_manager}_docker_detection.py`:
164-
165-
```python
166-
"""Test {package_manager} Docker container dependency detection."""
167-
168-
import os
169-
import sys
170-
from typing import Dict, Any
171-
172-
# Add parent directory to path for imports
173-
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
174-
175-
import pytest
176-
from dependency_resolver.executors import DockerExecutor
177-
from dependency_resolver.core.orchestrator import Orchestrator
178-
from tests.common.docker_test_base import DockerTestBase
179-
180-
try:
181-
import docker
182-
except ImportError:
183-
docker = None # type: ignore
184-
185-
186-
class Test{PackageManager}DockerDetection(DockerTestBase):
187-
"""Test {package_manager} dependency detection using Docker container environment."""
188-
189-
# Choose appropriate Docker image that has your package manager
190-
TEST_IMAGE = "appropriate/docker-image"
191-
192-
@pytest.mark.skipif(docker is None, reason="Docker not available")
193-
def test_{package_manager}_docker_container_detection(self, request: pytest.FixtureRequest) -> None:
194-
"""Test {package_manager} dependency detection inside a Docker container."""
110+
Create a test class inheriting from `DockerTestBase` in `/tests/common/docker_test_base.py`. Key components:
195111

196-
verbose_output = self.setup_verbose_output(request)
197-
container_id = None
112+
- Choose appropriate Docker image containing your package manager
113+
- Use `DockerExecutor` to run tests in containerized environment
114+
- Test via `Orchestrator` to ensure integration works correctly
115+
- Validate expected output format and required fields
116+
- Include proper cleanup and error handling
198117

199-
try:
200-
container_id = self.start_container(self.TEST_IMAGE, additional_args=[])
201-
self.wait_for_container_ready(container_id, "{package_manager} --version", max_wait=60)
202-
203-
executor = DockerExecutor(container_id)
204-
orchestrator = Orchestrator(debug=False, skip_system_scope=False)
205-
206-
result = orchestrator.resolve_dependencies(executor)
207-
208-
if verbose_output:
209-
self.print_verbose_results("DEPENDENCY RESOLVER OUTPUT:", result)
210-
211-
self._validate_{package_manager}_dependencies(result)
212-
213-
finally:
214-
if container_id:
215-
self.cleanup_container(container_id)
216-
217-
def _validate_{package_manager}_dependencies(self, result: Dict[str, Any]) -> None:
218-
"""Validate {package_manager} dependencies in the result."""
219-
assert "{package_manager}" in result
220-
221-
{package_manager}_result = result["{package_manager}"]
222-
assert "scope" in {package_manager}_result
223-
assert "dependencies" in {package_manager}_result
224-
225-
# Add specific validations for your package manager
226-
dependencies = {package_manager}_result["dependencies"]
227-
assert isinstance(dependencies, dict)
228-
229-
# Validate expected packages if known
230-
# assert "expected-package" in dependencies
231-
```
118+
Reference existing detector tests in `/tests/detectors/` for implementation patterns.
232119

233120
### 4.3 Test README
234121

235-
Create `/tests/detectors/{package_manager}/README.md` with:
122+
Create `/tests/detectors/{package_manager}/README.md` documenting:
236123

237124
**Content Structure:**
238125

239126
- **Docker Test**: Description of Docker-based testing approach
240127
- **Image Used**: Document the Docker image used for testing
241-
- **Test Commands**: List the commands tested (e.g., `{package_manager} --version`)
128+
- **Test Commands**: List the commands tested
242129
- **Running Tests**: Instructions for executing the tests
243130

244-
**Test Execution Commands:**
131+
**Test Execution Patterns:**
245132

246-
- Run all tests: `pytest tests/detectors/{package_manager}/`
247-
- Verbose output: `pytest tests/detectors/{package_manager}/ --verbose-resolver`
248-
- Specific test: `pytest tests/detectors/{package_manager}/test_{package_manager}_docker_detection.py::Test{PackageManager}DockerDetection::test_{package_manager}_docker_container_detection`
133+
Reference pytest command patterns from existing detector test READMEs for running individual tests, verbose output, and full test suites.
249134

250135
## Step 5: Integration and Testing
251136

252137
### 5.1 Manual Testing
253138

254139
**Basic Testing Steps:**
255140

256-
1. **Activate environment**: `source venv/bin/activate`
141+
1. **Activate environment**: Use virtual environment activation
257142
2. **Test detector directly**: Import and run your detector with `debug=True`
258-
3. **Test via CLI**: `python3 -m dependency_resolver --debug`
143+
3. **Test via CLI**: Use debug mode to see detailed output
259144
4. **Test in target environment**: Use appropriate executor (host/docker) for your use case
260145

261146
### 5.2 Run Test Suite
262147

263-
```bash
264-
# Run your detector tests
265-
pytest tests/detectors/{package_manager}/
266-
267-
# Run all tests
268-
pytest
269-
270-
# Run linting
271-
pre-commit run --files $(git diff --name-only --diff-filter=ACMR HEAD)
272-
```
148+
Run detector-specific tests, full test suite, and linting checks. Reference CLAUDE.md for specific commands and patterns.
273149

274150
## Step 6: Documentation and Performance
275151

@@ -283,36 +159,23 @@ If a `performance-analysis/` directory exists, add a benchmark script following
283159

284160
## Common Implementation Patterns
285161

286-
### System-Wide Detectors (dpkg, apk style)
287-
288-
```python
289-
def has_system_scope(self, executor: EnvironmentExecutor, working_dir: Optional[str] = None) -> bool:
290-
return True # Always system scope
291-
292-
def get_dependencies(self, executor: EnvironmentExecutor, working_dir: Optional[str] = None) -> dict[str, Any]:
293-
# Extract from system package database
294-
# Usually ignore working_dir for system packages
295-
result = {"scope": "system", "dependencies": {}}
296-
```
297-
298-
### Project-Scoped Detectors (pip, npm style)
299-
300-
```python
301-
def has_system_scope(self, executor: EnvironmentExecutor, working_dir: Optional[str] = None) -> bool:
302-
if working_dir:
303-
# Check for project files in working_dir
304-
return not self._has_project_files(executor, working_dir)
305-
return True # Default to system if no working_dir
306-
307-
def get_dependencies(self, executor: EnvironmentExecutor, working_dir: Optional[str] = None) -> dict[str, Any]:
308-
if working_dir and self._has_project_files(executor, working_dir):
309-
# Extract project dependencies
310-
location = self._resolve_absolute_path(executor, working_dir)
311-
return {"scope": "project", "location": location, "dependencies": {}}
312-
else:
313-
# Extract system dependencies
314-
return {"scope": "system", "dependencies": {}}
315-
```
162+
### System-Wide Detectors
163+
164+
Reference `DpkgDetector` and `ApkDetector` implementations:
165+
166+
- Always return `True` for `has_system_scope()`
167+
- Extract from system package database
168+
- Usually ignore `working_dir` for system packages
169+
- Return `{"scope": "system", "dependencies": {}}`
170+
171+
### Project-Scoped Detectors
172+
173+
Reference `PipDetector` and `NpmDetector` implementations:
174+
175+
- Check for project files in `working_dir` to determine scope
176+
- Extract project dependencies when project files found
177+
- Fall back to system scope when no project context
178+
- Return appropriate scope with location for project dependencies
316179

317180
## Debugging Tips
318181

@@ -322,6 +185,8 @@ def get_dependencies(self, executor: EnvironmentExecutor, working_dir: Optional[
322185
4. **Validate JSON Output**: Ensure output follows expected schema
323186
5. **Test Both Scopes**: If supporting both project and system scope
324187

188+
Use `python3 -m dependency_resolver --debug` to see detailed execution flow.
189+
325190
## Quality Checklist
326191

327192
Before submitting your detector:
@@ -338,11 +203,19 @@ Before submitting your detector:
338203
- [ ] Manual testing in target environments
339204
- [ ] Performance considerations documented
340205

341-
## Support
206+
## Support and References
207+
208+
**Key Reference Files:**
209+
210+
- `/dependency_resolver/detectors/` - Existing detector implementations
211+
- `/dependency_resolver/core/interfaces.py` - PackageManagerDetector interface
212+
- `/dependency_resolver/core/orchestrator.py` - Detector registration
213+
- `/docs/technical/architecture/adr/` - Architecture decision records
214+
- `/tests/detectors/` - Test patterns and examples
215+
- `/tests/common/docker_test_base.py` - Docker testing base class
342216

343-
For questions or assistance:
217+
**Debug Commands:**
344218

345-
1. Review existing detector implementations in `/dependency_resolver/detectors/`
346-
2. Check ADRs in `/docs/adr/` for architectural decisions
347-
3. Examine test patterns in `/tests/detectors/`
348-
4. Follow the debug output with `python3 -m dependency_resolver --debug`
219+
- `python3 -m dependency_resolver --debug` - Full debug output
220+
- `source venv/bin/activate` - Activate development environment
221+
- `pre-commit run --files $(git diff --name-only --diff-filter=ACMR HEAD)` - Run linting

docs/technical/detectors/docker_info_detector.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,13 @@ Works exclusively with `DockerExecutor` to:
116116

117117
```json
118118
{
119+
"source": {
119120
"type": "container",
120121
"name": "my-container",
121122
"image": "unknown",
122123
"hash": "unknown",
123124
"error": "AttributeError: 'NoneType' object has no attribute 'tags'"
125+
}
124126
}
125127
```
126128

0 commit comments

Comments
 (0)