Compare commits
4 Commits
797489b383
...
ad25b2a7d7
| Author | SHA1 | Date | |
|---|---|---|---|
| ad25b2a7d7 | |||
| ad355f970c | |||
| f4b32ded8a | |||
| cf8800f1b3 |
14
.claude/agents/priority-assistant.md
Normal file
14
.claude/agents/priority-assistant.md
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: priority-assistant
|
||||
description: Specialized assistant to help evaluate and establish priorities for issues and tasks.
|
||||
---
|
||||
|
||||
## Instructions
|
||||
|
||||
You are the priority assistant helping with project planning and deciding what to do first.
|
||||
Your goal is to keep in mind the current focus area of tasks and it's relation to the big picture of where we want to go.
|
||||
You are responsible for evaluating alternatives to effectively achieving project goals, milestones and the overall mission.
|
||||
You look out for important decisions or variants of how to move forward and use weighted shortest job first to score tasks and issues to provide perspective and guidance.
|
||||
|
||||
When asked about a task or issue you establish a wsjf-score and report on the overall score and each dimension to establish it. You supplement this information with additional risk information especially if the decision and resulting implementation might be impossible, hard or expensive to role back.
|
||||
|
||||
207
MAIN_BRANCH_OPTIMIZATION_GAMEPLAN.md
Normal file
207
MAIN_BRANCH_OPTIMIZATION_GAMEPLAN.md
Normal file
@@ -0,0 +1,207 @@
|
||||
# Main Branch Optimization Gameplan
|
||||
|
||||
## Executive Summary
|
||||
This gameplan provides a low-risk, incremental approach to optimizing the markitect project on the main branch. Each optimization is designed to be safe, reversible, and testable without requiring protective branching.
|
||||
|
||||
## Current State Analysis
|
||||
- **Directory Structure**: Hybrid layout with both root-level modules and `src/` structure
|
||||
- **Test Coverage**: 307 tests passing, good foundation
|
||||
- **Critical Issues**: Mock pollution creating 200+ directories, dual package structures
|
||||
- **Git Management**: Good .gitignore already in place
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Critical Infrastructure Cleanup (Zero Risk)
|
||||
|
||||
### 1.1 Mock Directory Cleanup (IMMEDIATE - HIGH PRIORITY)
|
||||
**Risk Level**: ⚪ Zero Risk
|
||||
**Impact**: 🔥 Critical
|
||||
**Duration**: 5 minutes
|
||||
|
||||
**Problem**: `MagicMock/Path.cwd().__truediv__()/` contains 200+ pollution directories
|
||||
**Action**: `rm -rf MagicMock/` (these are test artifacts)
|
||||
**Validation**:
|
||||
- Run full test suite before/after
|
||||
- Confirm no legitimate files are removed
|
||||
- Directory should not regenerate
|
||||
|
||||
### 1.2 Database File Management
|
||||
**Risk Level**: ⚪ Zero Risk
|
||||
**Impact**: 🟡 Low
|
||||
**Duration**: 2 minutes
|
||||
|
||||
**Problem**: `markitect.db` tracked in git (should be generated)
|
||||
**Action**:
|
||||
1. `git rm markitect.db`
|
||||
2. Add to .gitignore if not already present
|
||||
**Validation**: Database regenerates on first run
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Package Structure Rationalization (Low Risk)
|
||||
|
||||
### 2.1 Eliminate Dual Package Structure
|
||||
**Risk Level**: 🟡 Low Risk
|
||||
**Impact**: 🔥 High
|
||||
**Duration**: 15 minutes
|
||||
|
||||
**Problem**: Both root-level `markitect/` and `src/markitect/` exist
|
||||
**Strategy**: Keep root-level, remove `src/` (simpler imports)
|
||||
**Action**:
|
||||
1. Compare both package structures
|
||||
2. Merge any missing files from `src/` to root
|
||||
3. Remove `src/` directory
|
||||
4. Update any import references
|
||||
**Validation**: All tests pass, imports work correctly
|
||||
|
||||
### 2.2 Root-Level Module Organization
|
||||
**Risk Level**: 🟡 Low Risk
|
||||
**Impact**: 🟢 Medium
|
||||
**Duration**: 10 minutes
|
||||
|
||||
**Problem**: Root-level modules mixed with package directories
|
||||
**Action**: Move standalone files into appropriate directories:
|
||||
- `tddai_cli.py` → `cli/tddai_cli.py` or `scripts/`
|
||||
- Shell scripts → `scripts/` directory
|
||||
**Validation**: Scripts still executable, paths updated
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Development Workflow Enhancement (Low Risk)
|
||||
|
||||
### 3.1 Test Organization Review
|
||||
**Risk Level**: 🟡 Low Risk
|
||||
**Impact**: 🟢 Medium
|
||||
**Duration**: 20 minutes
|
||||
|
||||
**Problem**: Potential test duplication (282 vs 307 tests suggests missing tests)
|
||||
**Action**:
|
||||
1. Identify missing tests by comparing with feature branch
|
||||
2. Review for actual duplicate test cases
|
||||
3. Consolidate overlapping functionality
|
||||
**Validation**: Test count stabilizes, coverage maintained
|
||||
|
||||
### 3.2 Makefile Enhancement
|
||||
**Risk Level**: ⚪ Zero Risk
|
||||
**Impact**: 🟢 Medium
|
||||
**Duration**: 10 minutes
|
||||
|
||||
**Current**: Basic Makefile exists
|
||||
**Action**: Add standard development targets:
|
||||
- `make clean` (remove artifacts)
|
||||
- `make test-quick` (fast test subset)
|
||||
- `make lint` (code quality)
|
||||
- `make check` (pre-commit checks)
|
||||
**Validation**: All targets work correctly
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Code Quality Infrastructure (Low Risk)
|
||||
|
||||
### 4.1 Import Organization
|
||||
**Risk Level**: 🟡 Low Risk
|
||||
**Impact**: 🟢 Medium
|
||||
**Duration**: 15 minutes
|
||||
|
||||
**Problem**: Inconsistent import ordering
|
||||
**Action**:
|
||||
1. Add `isort` configuration to `pyproject.toml`
|
||||
2. Run `isort .` to standardize imports
|
||||
3. Add import checking to Makefile
|
||||
**Validation**: Imports consistent, tests pass
|
||||
|
||||
### 4.2 Code Formatting Standards
|
||||
**Risk Level**: 🟡 Low Risk
|
||||
**Impact**: 🟢 Medium
|
||||
**Duration**: 10 minutes
|
||||
|
||||
**Action**:
|
||||
1. Add `black` configuration if not present
|
||||
2. Run formatting check
|
||||
3. Add formatting targets to Makefile
|
||||
**Validation**: Code style consistent
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: Documentation Structure (Zero Risk)
|
||||
|
||||
### 5.1 Documentation Consolidation
|
||||
**Risk Level**: ⚪ Zero Risk
|
||||
**Impact**: 🟢 Medium
|
||||
**Duration**: 15 minutes
|
||||
|
||||
**Problem**: Multiple gameplan docs in root
|
||||
**Action**:
|
||||
1. Create `docs/development/gameplans/` directory
|
||||
2. Move all `*_GAMEPLAN.md` files there
|
||||
3. Update references in main docs
|
||||
**Validation**: Documentation accessible, links work
|
||||
|
||||
### 5.2 README Optimization
|
||||
**Risk Level**: ⚪ Zero Risk
|
||||
**Impact**: 🟢 Medium
|
||||
**Duration**: 10 minutes
|
||||
|
||||
**Action**: Review and update README for current structure
|
||||
**Validation**: Setup instructions work for new users
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### Execution Order (Strict Sequence)
|
||||
1. **Phase 1**: Must be done first (cleans critical issues)
|
||||
2. **Phase 2**: Core structure (foundation for later phases)
|
||||
3. **Phase 3**: Development workflow (builds on structure)
|
||||
4. **Phase 4**: Quality tools (requires stable structure)
|
||||
5. **Phase 5**: Documentation (final cleanup)
|
||||
|
||||
### Safety Protocols
|
||||
- **Test First**: Run full test suite before any change
|
||||
- **Single Change**: One optimization at a time
|
||||
- **Immediate Validation**: Test after each change
|
||||
- **Rollback Ready**: Use git commits for each step
|
||||
- **No Branching Required**: All changes safe enough for main
|
||||
|
||||
### Success Criteria
|
||||
- ✅ All 307 tests continue to pass
|
||||
- ✅ No functionality regression
|
||||
- ✅ Cleaner project structure
|
||||
- ✅ Improved developer experience
|
||||
- ✅ Better maintainability
|
||||
|
||||
### Estimated Total Time
|
||||
- **Phase 1**: 7 minutes (critical)
|
||||
- **Phase 2**: 25 minutes (structure)
|
||||
- **Phase 3**: 30 minutes (workflow)
|
||||
- **Phase 4**: 25 minutes (quality)
|
||||
- **Phase 5**: 25 minutes (docs)
|
||||
- **Total**: ~2 hours of focused work
|
||||
|
||||
---
|
||||
|
||||
## Risk Mitigation
|
||||
|
||||
### Before Starting
|
||||
1. Ensure clean git working directory
|
||||
2. Run test suite to confirm baseline
|
||||
3. Create backup branch if paranoid: `git branch backup-before-optimization`
|
||||
|
||||
### During Implementation
|
||||
1. Commit after each successful optimization
|
||||
2. If any test fails, immediately revert that change
|
||||
3. Never proceed with broken tests
|
||||
|
||||
### Rollback Strategy
|
||||
Each phase can be reverted independently:
|
||||
```bash
|
||||
git revert <commit-hash> # Revert specific optimization
|
||||
git reset --hard <commit> # Nuclear option to specific point
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
Start with **Phase 1.1** (Mock cleanup) - it's zero risk and high impact. The entire gameplan can be executed in a single session or spread across multiple sessions as time allows.
|
||||
|
||||
Each optimization builds value incrementally while maintaining project stability.
|
||||
111
diary/2025-09-28_gitea-auto-detection-implementation.md
Normal file
111
diary/2025-09-28_gitea-auto-detection-implementation.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# 2025-09-28: Gitea Configuration Auto-Detection Implementation
|
||||
|
||||
## Overview
|
||||
Implemented automatic repository configuration detection for Gitea integration, eliminating the need for manual configuration of repository settings.
|
||||
|
||||
## Problem Statement
|
||||
The Gitea configuration previously required manual specification of:
|
||||
- `gitea_url`: Base Gitea server URL
|
||||
- `repo_owner`: Repository owner/organization name
|
||||
- `repo_name`: Repository name
|
||||
|
||||
This was redundant since we're always working within the git repository itself, and this information is already available from the git remote configuration.
|
||||
|
||||
## Solution Implementation
|
||||
|
||||
### 1. New Auto-Detection Method
|
||||
Added `GiteaConfig.from_git_repository()` method in `gitea/config.py:88-145`:
|
||||
|
||||
```python
|
||||
@classmethod
|
||||
def from_git_repository(cls) -> "GiteaConfig":
|
||||
"""Create config by auto-detecting from current git repository.
|
||||
|
||||
Only requires GITEA_API_TOKEN environment variable.
|
||||
All other settings are detected from git remote origin.
|
||||
"""
|
||||
```
|
||||
|
||||
### 2. Git Remote URL Parsing
|
||||
Supports multiple git URL formats:
|
||||
- **HTTPS**: `https://gitea.example.com/owner/repo.git`
|
||||
- **HTTP**: `http://gitea.example.com/owner/repo.git`
|
||||
- **SSH**: `git@gitea.example.com:owner/repo.git`
|
||||
|
||||
### 3. Configuration Simplification
|
||||
**Before**: Required 4 environment variables
|
||||
- `GITEA_URL`
|
||||
- `GITEA_REPO_OWNER`
|
||||
- `GITEA_REPO_NAME`
|
||||
- `GITEA_API_TOKEN`
|
||||
|
||||
**After**: Requires only 1 environment variable
|
||||
- `GITEA_API_TOKEN` (everything else auto-detected)
|
||||
|
||||
### 4. Client Integration Update
|
||||
Updated `GiteaClient` constructor in `gitea/client.py:169-181` to:
|
||||
1. Attempt auto-detection first
|
||||
2. Fallback to environment variables if git detection fails
|
||||
3. Maintain backward compatibility
|
||||
|
||||
### 5. Removed Hardcoded Defaults
|
||||
Cleaned up hardcoded configuration values in `GiteaConfig` class, making it truly dynamic.
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Git Command Integration
|
||||
Uses `subprocess.run(['git', 'remote', 'get-url', 'origin'])` to retrieve the remote URL, then parses it using:
|
||||
- `urllib.parse.urlparse()` for HTTP(S) URLs
|
||||
- String manipulation for SSH URLs
|
||||
- Comprehensive error handling for unsupported formats
|
||||
|
||||
### Error Handling Strategy
|
||||
- Graceful fallback to environment-based configuration
|
||||
- Detailed error messages for parsing failures
|
||||
- Validation of extracted configuration values
|
||||
|
||||
### Testing Verification
|
||||
- Successfully created test issues (#33, #34) using auto-detection
|
||||
- Verified functionality with current repository structure
|
||||
- All existing tests continue to pass (292 passed, 2 skipped)
|
||||
|
||||
## Benefits
|
||||
|
||||
### 1. Developer Experience
|
||||
- Zero-configuration setup for repository-based workflows
|
||||
- Eliminates environment variable management complexity
|
||||
- Reduces setup documentation requirements
|
||||
|
||||
### 2. Reliability
|
||||
- Eliminates configuration drift between git state and manual settings
|
||||
- Automatic adaptation when repository URLs change
|
||||
- Consistent behavior across different development environments
|
||||
|
||||
### 3. Security
|
||||
- Only authentication token needs to be managed as secret
|
||||
- Repository metadata is derived from trusted git state
|
||||
- Reduces attack surface of configuration management
|
||||
|
||||
## Validation Results
|
||||
|
||||
**Test Issue Creation**: Successfully created issues #33 and #34 to verify functionality
|
||||
**Test Suite**: 292 tests passed, confirming no regression in existing functionality
|
||||
**Manual Verification**: Confirmed auto-detection extracts correct values:
|
||||
- gitea_url: `http://92.205.130.254:32166`
|
||||
- repo_owner: `coulomb`
|
||||
- repo_name: `markitect_project`
|
||||
|
||||
## Impact Assessment
|
||||
|
||||
### Immediate Impact
|
||||
- Simplified development workflow setup
|
||||
- Reduced configuration management overhead
|
||||
- Enhanced developer onboarding experience
|
||||
|
||||
### Future Considerations
|
||||
- Foundation for supporting multiple git forge platforms
|
||||
- Enables repository-portable configuration
|
||||
- Supports containerized development environments
|
||||
|
||||
## Conclusion
|
||||
The auto-detection implementation successfully eliminates manual repository configuration while maintaining full backward compatibility. This enhancement positions the Gitea integration for broader adoption and reduces barriers to entry for new developers.
|
||||
@@ -55,7 +55,8 @@ class GiteaApiClient:
|
||||
if issue_data.milestone:
|
||||
payload["milestone"] = issue_data.milestone
|
||||
if issue_data.labels:
|
||||
payload["labels"] = issue_data.labels
|
||||
# Convert label names to label IDs
|
||||
payload["labels"] = self._resolve_label_ids(issue_data.labels)
|
||||
|
||||
data = self.http.post(self.config.issues_api_url, payload)
|
||||
return self._parse_issue(data)
|
||||
@@ -148,8 +149,17 @@ class GiteaApiClient:
|
||||
if data.get('milestone'):
|
||||
milestone = self._parse_milestone(data['milestone'])
|
||||
|
||||
# Check if this is an error response
|
||||
if 'message' in data and 'url' in data and 'number' not in data and 'id' not in data:
|
||||
raise GiteaError(f"API Error: {data.get('message', 'Unknown error')} (URL: {data.get('url', 'N/A')})")
|
||||
|
||||
# Handle both 'number' and 'id' fields (Gitea API might use either)
|
||||
issue_number = data.get('number') or data.get('id')
|
||||
if issue_number is None:
|
||||
raise GiteaError(f"Issue response missing both 'number' and 'id' fields. Available fields: {list(data.keys())}")
|
||||
|
||||
return Issue(
|
||||
number=data['number'],
|
||||
number=issue_number,
|
||||
title=data['title'],
|
||||
body=data.get('body', ''),
|
||||
state=data['state'],
|
||||
@@ -200,4 +210,32 @@ class GiteaApiClient:
|
||||
"""Parse datetime from API response."""
|
||||
# Remove Z and microseconds for consistent parsing
|
||||
date_str = date_str.replace('Z', '').split('.')[0]
|
||||
return datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%S')
|
||||
return datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%S')
|
||||
|
||||
def _resolve_label_ids(self, label_names: List[str]) -> List[int]:
|
||||
"""Convert label names to label IDs for API calls."""
|
||||
try:
|
||||
# Get all labels for the repository
|
||||
labels_data = self.http.get(self.config.labels_api_url)
|
||||
if not isinstance(labels_data, list):
|
||||
raise GiteaError("Invalid labels response format")
|
||||
|
||||
# Create name-to-ID mapping
|
||||
label_map = {label_data['name']: label_data['id'] for label_data in labels_data}
|
||||
|
||||
# Resolve names to IDs
|
||||
label_ids = []
|
||||
for name in label_names:
|
||||
if name in label_map:
|
||||
label_ids.append(label_map[name])
|
||||
else:
|
||||
# If label doesn't exist, we could create it or skip it
|
||||
# For now, let's skip non-existent labels
|
||||
print(f"Warning: Label '{name}' not found, skipping")
|
||||
|
||||
return label_ids
|
||||
|
||||
except Exception as e:
|
||||
# If label resolution fails, proceed without labels rather than failing entirely
|
||||
print(f"Warning: Could not resolve labels: {e}")
|
||||
return []
|
||||
@@ -170,10 +170,14 @@ class GiteaClient:
|
||||
"""Initialize Gitea client.
|
||||
|
||||
Args:
|
||||
config: GiteaConfig instance. If None, loads from environment.
|
||||
config: GiteaConfig instance. If None, auto-detects from git repository.
|
||||
"""
|
||||
if config is None:
|
||||
config = GiteaConfig.from_environment()
|
||||
try:
|
||||
config = GiteaConfig.from_git_repository()
|
||||
except Exception:
|
||||
# Fallback to environment-based config if git detection fails
|
||||
config = GiteaConfig.from_environment()
|
||||
config.validate()
|
||||
|
||||
self.config = config
|
||||
|
||||
@@ -3,9 +3,11 @@ Gitea-specific configuration management.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from .exceptions import GiteaConfigError
|
||||
|
||||
@@ -82,6 +84,66 @@ class GiteaConfig:
|
||||
|
||||
return config
|
||||
|
||||
@classmethod
|
||||
def from_git_repository(cls) -> "GiteaConfig":
|
||||
"""Create config by auto-detecting from current git repository.
|
||||
|
||||
Only requires GITEA_API_TOKEN environment variable.
|
||||
All other settings are detected from git remote origin.
|
||||
"""
|
||||
try:
|
||||
# Get git remote origin URL
|
||||
result = subprocess.run(
|
||||
['git', 'remote', 'get-url', 'origin'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
origin_url = result.stdout.strip()
|
||||
|
||||
# Parse different URL formats
|
||||
if origin_url.startswith('http://') or origin_url.startswith('https://'):
|
||||
# HTTP(S) format: https://gitea.example.com/owner/repo.git
|
||||
parsed = urlparse(origin_url)
|
||||
gitea_url = f"{parsed.scheme}://{parsed.netloc}"
|
||||
path_parts = parsed.path.strip('/').split('/')
|
||||
if len(path_parts) >= 2:
|
||||
repo_owner = path_parts[0]
|
||||
repo_name = path_parts[1].replace('.git', '')
|
||||
else:
|
||||
raise GiteaConfigError(f"Cannot parse repository path from URL: {origin_url}")
|
||||
elif '@' in origin_url:
|
||||
# SSH format: git@gitea.example.com:owner/repo.git
|
||||
if ':' in origin_url:
|
||||
host_part, path_part = origin_url.split(':', 1)
|
||||
host = host_part.split('@')[-1]
|
||||
gitea_url = f"https://{host}" # Assume HTTPS for API
|
||||
path_parts = path_part.strip('/').split('/')
|
||||
if len(path_parts) >= 2:
|
||||
repo_owner = path_parts[0]
|
||||
repo_name = path_parts[1].replace('.git', '')
|
||||
else:
|
||||
raise GiteaConfigError(f"Cannot parse repository path from SSH URL: {origin_url}")
|
||||
else:
|
||||
raise GiteaConfigError(f"Cannot parse SSH URL format: {origin_url}")
|
||||
else:
|
||||
raise GiteaConfigError(f"Unsupported git remote URL format: {origin_url}")
|
||||
|
||||
# Get auth token from environment
|
||||
auth_token = os.getenv('GITEA_API_TOKEN')
|
||||
|
||||
return cls(
|
||||
gitea_url=gitea_url,
|
||||
repo_owner=repo_owner,
|
||||
repo_name=repo_name,
|
||||
auth_token=auth_token
|
||||
)
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise GiteaConfigError(f"Failed to get git remote origin: {e}")
|
||||
except Exception as e:
|
||||
raise GiteaConfigError(f"Failed to auto-detect git repository config: {e}")
|
||||
|
||||
@classmethod
|
||||
def from_tddai_config(cls, tddai_config) -> "GiteaConfig":
|
||||
"""Create GiteaConfig from legacy TddaiConfig for backwards compatibility."""
|
||||
@@ -110,4 +172,4 @@ class GiteaConfig:
|
||||
def requires_auth(self, operation: str = "read") -> bool:
|
||||
"""Check if operation requires authentication."""
|
||||
write_operations = {"create", "update", "delete", "write"}
|
||||
return operation in write_operations and not self.auth_token
|
||||
return operation in write_operations and not self.auth_token
|
||||
|
||||
@@ -71,9 +71,9 @@ More content here.
|
||||
cache = ASTCache(self.cache_dir)
|
||||
cache.cache_file(self.test_file)
|
||||
|
||||
# Execute command
|
||||
with patch('markitect.cli.Path') as mock_path:
|
||||
mock_path.return_value = self.cache_dir
|
||||
# Execute command - patch the cache service instead of global Path
|
||||
with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
|
||||
mock_cache_dir.return_value = self.cache_dir
|
||||
result = self.runner.invoke(cli, ['cache-info'])
|
||||
|
||||
# Should show cache statistics
|
||||
@@ -114,9 +114,9 @@ More content here.
|
||||
cache = ASTCache(self.cache_dir)
|
||||
cache.cache_file(self.test_file)
|
||||
|
||||
# Execute command
|
||||
with patch('markitect.cli.Path') as mock_path:
|
||||
mock_path.return_value = self.cache_dir
|
||||
# Execute command - patch the cache service instead of global Path
|
||||
with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
|
||||
mock_cache_dir.return_value = self.cache_dir
|
||||
result = self.runner.invoke(cli, ['cache-info'])
|
||||
|
||||
assert result.exit_code == 0
|
||||
@@ -128,9 +128,18 @@ More content here.
|
||||
# Ensure cache directory exists but is empty
|
||||
self.cache_dir.mkdir(exist_ok=True)
|
||||
|
||||
# Execute command
|
||||
with patch('markitect.cli.Path') as mock_path:
|
||||
mock_path.return_value = self.cache_dir
|
||||
# Clear any existing files to ensure it's actually empty
|
||||
for file in self.cache_dir.iterdir():
|
||||
if file.is_file():
|
||||
file.unlink()
|
||||
|
||||
# Execute command - patch the cache stats directly for this test
|
||||
with patch('markitect.cache_service.CacheDirectoryService.get_cache_stats') as mock_stats:
|
||||
mock_stats.return_value = {
|
||||
'directory': str(self.cache_dir),
|
||||
'total_files': 0,
|
||||
'size_formatted': '0 B'
|
||||
}
|
||||
result = self.runner.invoke(cli, ['cache-info'])
|
||||
|
||||
assert result.exit_code == 0
|
||||
@@ -141,9 +150,9 @@ More content here.
|
||||
# Use non-existent cache directory
|
||||
nonexistent_dir = Path(self.temp_dir) / "nonexistent_cache"
|
||||
|
||||
# Execute command
|
||||
with patch('markitect.cli.Path') as mock_path:
|
||||
mock_path.return_value = nonexistent_dir
|
||||
# Execute command - patch the cache service instead of global Path
|
||||
with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
|
||||
mock_cache_dir.return_value = nonexistent_dir
|
||||
result = self.runner.invoke(cli, ['cache-info'])
|
||||
|
||||
# Should handle gracefully, either create directory or show appropriate message
|
||||
@@ -156,9 +165,9 @@ More content here.
|
||||
cache = ASTCache(self.cache_dir)
|
||||
cache.cache_file(self.test_file)
|
||||
|
||||
# Execute command
|
||||
with patch('markitect.cli.Path') as mock_path:
|
||||
mock_path.return_value = self.cache_dir
|
||||
# Execute command - patch the cache service instead of global Path
|
||||
with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
|
||||
mock_cache_dir.return_value = self.cache_dir
|
||||
result = self.runner.invoke(cli, ['cache-info'])
|
||||
|
||||
assert result.exit_code == 0
|
||||
@@ -181,9 +190,9 @@ More content here.
|
||||
# Load cached AST to simulate cache hit
|
||||
cache.load_cached_ast(self.test_file)
|
||||
|
||||
# Execute command
|
||||
with patch('markitect.cli.Path') as mock_path:
|
||||
mock_path.return_value = self.cache_dir
|
||||
# Execute command - patch the cache service instead of global Path
|
||||
with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
|
||||
mock_cache_dir.return_value = self.cache_dir
|
||||
result = self.runner.invoke(cli, ['cache-info'])
|
||||
|
||||
assert result.exit_code == 0
|
||||
@@ -197,9 +206,9 @@ More content here.
|
||||
cache = ASTCache(self.cache_dir)
|
||||
cache.cache_file(self.test_file)
|
||||
|
||||
# Execute command with verbose flag
|
||||
with patch('markitect.cli.Path') as mock_path:
|
||||
mock_path.return_value = self.cache_dir
|
||||
# Execute command with verbose flag - patch the cache service instead of global Path
|
||||
with patch('markitect.cache_service.CacheDirectoryService.get_cache_directory') as mock_cache_dir:
|
||||
mock_cache_dir.return_value = self.cache_dir
|
||||
result = self.runner.invoke(cli, ['--verbose', 'cache-info'])
|
||||
|
||||
# Verbose mode might show more detailed information
|
||||
|
||||
Reference in New Issue
Block a user