FRAMEWORK DECOUPLING: - Remove all MarkiTect-specific references from tddai core modules - Update tddai-assistant.md to use generic examples and language - Change CLI output from "MarkiTect Issues" to "Project Issues" - Update coverage_analyzer.py docstring to be project-neutral CONFIGURATION SYSTEM: - Make tddai configuration flexible via environment variables - Add comprehensive documentation for project setup in config.py - Create .env.tddai and tddai-setup.sh for MarkiTect-specific config - Support configurable workspace naming (.tddai_workspace default) TEST INFRASTRUCTURE CLEANUP: - Fix IssueWriter test failures caused by config validation changes - Implement _get_test_config() helper for isolated test configurations - Ensure all 13 IssueWriter tests pass with proper test patterns - Maintain clean test separation and project independence FRAMEWORK PORTABILITY: - TDD8 methodology now completely generic and reusable - Configuration examples for GitHub/GitLab integration - Ready for extraction to separate repository when needed - All 45 tests pass cleanly confirming successful refactoring 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
112 lines
3.0 KiB
Python
112 lines
3.0 KiB
Python
"""
|
|
Configuration management for tddai.
|
|
|
|
The tddai framework is project-agnostic and can be configured per project
|
|
via environment variables:
|
|
|
|
- TDDAI_WORKSPACE_DIR: Workspace directory name (default: .tddai_workspace)
|
|
- TDDAI_GITEA_URL: Git platform URL
|
|
- TDDAI_REPO_OWNER: Repository owner/organization
|
|
- TDDAI_REPO_NAME: Repository name
|
|
|
|
Example .env file for a project:
|
|
```
|
|
TDDAI_WORKSPACE_DIR=.myproject_workspace
|
|
TDDAI_GITEA_URL=https://github.com
|
|
TDDAI_REPO_OWNER=myusername
|
|
TDDAI_REPO_NAME=myproject
|
|
```
|
|
"""
|
|
|
|
import os
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
from dataclasses import dataclass
|
|
|
|
from .exceptions import ConfigurationError
|
|
|
|
|
|
@dataclass
|
|
class TddaiConfig:
|
|
"""Configuration settings for tddai."""
|
|
|
|
# Workspace settings
|
|
workspace_dir: Path = Path(".tddai_workspace")
|
|
current_issue_file: str = "current_issue.json"
|
|
|
|
# Git repository settings (must be configured per project)
|
|
gitea_url: str = ""
|
|
repo_owner: str = ""
|
|
repo_name: str = ""
|
|
|
|
# Test settings
|
|
tests_dir: Path = Path("tests")
|
|
test_file_pattern: str = "test_issue_{issue_num}_{scenario}.py"
|
|
|
|
# AI settings
|
|
claude_code_command: str = "claude"
|
|
|
|
@property
|
|
def issues_api_url(self) -> str:
|
|
"""Get the full issues API URL."""
|
|
return f"{self.gitea_url}/api/v1/repos/{self.repo_owner}/{self.repo_name}/issues"
|
|
|
|
@property
|
|
def current_issue_path(self) -> Path:
|
|
"""Get the path to current issue file."""
|
|
return self.workspace_dir / self.current_issue_file
|
|
|
|
@classmethod
|
|
def from_environment(cls) -> "TddaiConfig":
|
|
"""Create config from environment variables."""
|
|
config = cls()
|
|
|
|
# Override with environment variables if present
|
|
gitea_url = os.getenv("TDDAI_GITEA_URL")
|
|
if gitea_url:
|
|
config.gitea_url = gitea_url
|
|
|
|
repo_owner = os.getenv("TDDAI_REPO_OWNER")
|
|
if repo_owner:
|
|
config.repo_owner = repo_owner
|
|
|
|
repo_name = os.getenv("TDDAI_REPO_NAME")
|
|
if repo_name:
|
|
config.repo_name = repo_name
|
|
|
|
workspace_dir = os.getenv("TDDAI_WORKSPACE_DIR")
|
|
if workspace_dir:
|
|
config.workspace_dir = Path(workspace_dir)
|
|
|
|
return config
|
|
|
|
def validate(self) -> None:
|
|
"""Validate configuration settings."""
|
|
if not self.gitea_url:
|
|
raise ConfigurationError("gitea_url cannot be empty")
|
|
|
|
if not self.repo_owner:
|
|
raise ConfigurationError("repo_owner cannot be empty")
|
|
|
|
if not self.repo_name:
|
|
raise ConfigurationError("repo_name cannot be empty")
|
|
|
|
|
|
# Global config instance
|
|
_config: Optional[TddaiConfig] = None
|
|
|
|
|
|
def get_config() -> TddaiConfig:
|
|
"""Get the global configuration instance."""
|
|
global _config
|
|
if _config is None:
|
|
_config = TddaiConfig.from_environment()
|
|
_config.validate()
|
|
return _config
|
|
|
|
|
|
def set_config(config: TddaiConfig) -> None:
|
|
"""Set the global configuration instance."""
|
|
global _config
|
|
config.validate()
|
|
_config = config |