chore: archive previous Aider worker
This commit is contained in:
141
old_2026-08-31/src/lai_automation/config.py
Normal file
141
old_2026-08-31/src/lai_automation/config.py
Normal file
@@ -0,0 +1,141 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
_DEFAULT_SETUP_COMMANDS = (
|
||||
"composer install --no-interaction --prefer-dist;;"
|
||||
"npm ci;;"
|
||||
"npm run build;;"
|
||||
"php artisan migrate:fresh --force"
|
||||
)
|
||||
|
||||
|
||||
def _bool(name: str, default: bool = False) -> bool:
|
||||
return os.getenv(name, str(default)).lower() in {"1", "true", "yes", "on"}
|
||||
|
||||
|
||||
def _commands(value: str) -> tuple[str, ...]:
|
||||
return tuple(command.strip() for command in value.split(";;") if command.strip())
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Settings:
|
||||
database_host: str
|
||||
database_port: int
|
||||
database_name: str
|
||||
database_user: str
|
||||
database_password: str
|
||||
source_repository: str
|
||||
source_branch: str
|
||||
workspace_root: Path
|
||||
mode: str
|
||||
allow_direct_main: bool
|
||||
gitea_url: str
|
||||
gitea_owner: str
|
||||
gitea_repository: str
|
||||
gitea_token: str
|
||||
gitea_username: str
|
||||
agent_command: str
|
||||
agent_model: str
|
||||
agent_timeout_seconds: int
|
||||
agent_idle_timeout_seconds: int
|
||||
setup_commands: tuple[str, ...]
|
||||
test_commands: tuple[str, ...]
|
||||
test_database_host: str
|
||||
test_database_port: int
|
||||
test_database_name: str
|
||||
test_database_user: str
|
||||
test_database_password: str
|
||||
test_customer_database: str
|
||||
test_config_database: str
|
||||
poll_seconds: int
|
||||
max_changed_files: int
|
||||
max_changed_lines: int
|
||||
max_agent_attempts: int
|
||||
stale_claim_minutes: int
|
||||
dry_run: bool
|
||||
|
||||
@classmethod
|
||||
def from_env(cls) -> Settings:
|
||||
mode = os.getenv("AUTOMATION_MODE", "dry-run").lower()
|
||||
if mode not in {"dry-run", "pr", "direct-main"}:
|
||||
raise ValueError("AUTOMATION_MODE must be dry-run, pr, or direct-main")
|
||||
|
||||
settings = cls(
|
||||
database_host=os.getenv("FAILURE_DB_HOST", "host.docker.internal"),
|
||||
database_port=int(os.getenv("FAILURE_DB_PORT", "33060")),
|
||||
database_name=os.getenv("FAILURE_DB_NAME", "laravel_ai_chat"),
|
||||
database_user=os.getenv("FAILURE_DB_USER", "laravel"),
|
||||
database_password=os.getenv("FAILURE_DB_PASSWORD", ""),
|
||||
source_repository=os.getenv(
|
||||
"SOURCE_REPOSITORY", "https://gitea.tisinfra.de/christian.meyer/lai.git"
|
||||
),
|
||||
source_branch=os.getenv("SOURCE_BRANCH", "main"),
|
||||
workspace_root=Path(os.getenv("WORKSPACE_ROOT", "/workspaces")),
|
||||
mode=mode,
|
||||
allow_direct_main=_bool("ALLOW_DIRECT_MAIN"),
|
||||
gitea_url=os.getenv("GITEA_URL", "https://gitea.tisinfra.de"),
|
||||
gitea_owner=os.getenv("GITEA_OWNER", "christian.meyer"),
|
||||
gitea_repository=os.getenv("GITEA_REPOSITORY", "lai"),
|
||||
gitea_token=os.getenv("GITEA_TOKEN", ""),
|
||||
gitea_username=os.getenv("GITEA_USERNAME", "automation-bot"),
|
||||
agent_command=os.getenv("AGENT_COMMAND", "aider"),
|
||||
agent_model=os.getenv("AGENT_MODEL", "mistral/devstral-latest"),
|
||||
agent_timeout_seconds=int(os.getenv("AGENT_TIMEOUT_SECONDS", "900")),
|
||||
agent_idle_timeout_seconds=int(os.getenv("AGENT_IDLE_TIMEOUT_SECONDS", "300")),
|
||||
setup_commands=_commands(
|
||||
os.getenv("SETUP_COMMANDS", _DEFAULT_SETUP_COMMANDS)
|
||||
),
|
||||
test_commands=_commands(
|
||||
os.getenv("TEST_COMMANDS", "php artisan test")
|
||||
),
|
||||
test_database_host=os.getenv("TEST_DB_HOST", "host.docker.internal"),
|
||||
test_database_port=int(os.getenv("TEST_DB_PORT", "33060")),
|
||||
test_database_name=os.getenv("TEST_DB_NAME", "laravel_ai_chat_agent_test"),
|
||||
test_database_user=os.getenv("TEST_DB_USER", "lai_test_runner"),
|
||||
test_database_password=os.getenv("TEST_DB_PASSWORD", ""),
|
||||
test_customer_database=os.getenv("TEST_CUSTOMER_DB", "customer_agent_test"),
|
||||
test_config_database=os.getenv("TEST_CONFIG_DB", "cockpit_agent_test"),
|
||||
poll_seconds=int(os.getenv("POLL_SECONDS", "60")),
|
||||
max_changed_files=int(os.getenv("MAX_CHANGED_FILES", "12")),
|
||||
max_changed_lines=int(os.getenv("MAX_CHANGED_LINES", "800")),
|
||||
max_agent_attempts=int(os.getenv("MAX_AGENT_ATTEMPTS", "2")),
|
||||
stale_claim_minutes=int(os.getenv("STALE_CLAIM_MINUTES", "90")),
|
||||
dry_run=mode == "dry-run",
|
||||
)
|
||||
settings.validate()
|
||||
return settings
|
||||
|
||||
def validate(self) -> None:
|
||||
if self.mode == "direct-main" and not self.allow_direct_main:
|
||||
raise ValueError("direct-main requires ALLOW_DIRECT_MAIN=true")
|
||||
if self.mode in {"pr", "direct-main"} and not self.gitea_token:
|
||||
raise ValueError(f"{self.mode} requires GITEA_TOKEN")
|
||||
if not self.database_password:
|
||||
raise ValueError("FAILURE_DB_PASSWORD is required")
|
||||
if not self.test_database_password:
|
||||
raise ValueError("TEST_DB_PASSWORD is required")
|
||||
if not self.test_commands:
|
||||
raise ValueError("TEST_COMMANDS must contain at least one command")
|
||||
test_databases = {
|
||||
"TEST_DB_NAME": self.test_database_name,
|
||||
"TEST_CUSTOMER_DB": self.test_customer_database,
|
||||
"TEST_CONFIG_DB": self.test_config_database,
|
||||
}
|
||||
for setting_name, database_name in test_databases.items():
|
||||
if "test" not in database_name.lower():
|
||||
raise ValueError(f"{setting_name} must name an isolated test database")
|
||||
if database_name == self.database_name:
|
||||
raise ValueError(f"{setting_name} must differ from FAILURE_DB_NAME")
|
||||
if len(set(test_databases.values())) != len(test_databases):
|
||||
raise ValueError("TEST_DB_NAME, TEST_CUSTOMER_DB, and TEST_CONFIG_DB must be distinct")
|
||||
if not 60 <= self.agent_timeout_seconds <= 3600:
|
||||
raise ValueError("AGENT_TIMEOUT_SECONDS must be between 60 and 3600")
|
||||
if not 60 <= self.agent_idle_timeout_seconds <= self.agent_timeout_seconds:
|
||||
raise ValueError(
|
||||
"AGENT_IDLE_TIMEOUT_SECONDS must be between 60 and AGENT_TIMEOUT_SECONDS"
|
||||
)
|
||||
if not 1 <= self.max_agent_attempts <= 7:
|
||||
raise ValueError("MAX_AGENT_ATTEMPTS must be between 1 and 7")
|
||||
Reference in New Issue
Block a user