""" 配置管理模块 支持环境分发、防抖策略和队列配置 """ from typing import Dict, List, Optional from pydantic import Field, validator from pydantic_settings import BaseSettings import yaml from pathlib import Path class EnvironmentConfig(BaseSettings): """环境配置""" branches: List[str] = Field(default_factory=list) jenkins_job: str jenkins_url: str priority: int = Field(default=1, ge=1, le=10) class DeduplicationConfig(BaseSettings): """防抖配置""" enabled: bool = True window_seconds: int = Field(default=300, ge=1) # 5分钟防抖窗口 strategy: str = Field(default="commit_branch") # commit_hash + branch cache_ttl: int = Field(default=3600, ge=1) # 缓存1小时 class QueueConfig(BaseSettings): """队列配置""" max_concurrent: int = Field(default=10, ge=1) max_retries: int = Field(default=3, ge=0) retry_delay: int = Field(default=60, ge=1) # 秒 priority_levels: int = Field(default=3, ge=1, le=10) class JenkinsConfig(BaseSettings): """Jenkins 配置""" username: str token: str timeout: int = Field(default=30, ge=1) retry_attempts: int = Field(default=3, ge=1) class DatabaseConfig(BaseSettings): """数据库配置""" url: str = Field(default="sqlite:///./webhook_ambassador.db") echo: bool = False pool_size: int = Field(default=10, ge=1) max_overflow: int = Field(default=20, ge=0) class RedisConfig(BaseSettings): """Redis 配置""" url: str = Field(default="redis://localhost:6379/0") password: Optional[str] = None db: int = Field(default=0, ge=0) class LoggingConfig(BaseSettings): """日志配置""" level: str = Field(default="INFO") format: str = Field(default="json") file: Optional[str] = None class SecurityConfig(BaseSettings): """安全配置""" secret_key: str webhook_secret_header: str = Field(default="X-Gitea-Signature") rate_limit_per_minute: int = Field(default=100, ge=1) class Settings(BaseSettings): """主配置类""" # 基础配置 app_name: str = "Gitea Webhook Ambassador" version: str = "1.0.0" debug: bool = False # 服务器配置 host: str = "0.0.0.0" port: int = Field(default=8000, ge=1, le=65535) # 数据库配置 database_url: str = Field(default="sqlite:///./webhook_ambassador.db") # Redis 配置 redis_url: str = Field(default="redis://localhost:6379/0") redis_password: str = Field(default="") redis_db: int = Field(default=0) # Jenkins 配置 jenkins_username: str = Field(default="admin") jenkins_token: str = Field(default="") jenkins_timeout: int = Field(default=30) # 安全配置 security_secret_key: str = Field(default="") security_webhook_secret_header: str = Field(default="X-Gitea-Signature") security_rate_limit_per_minute: int = Field(default=100) # 日志配置 logging_level: str = Field(default="INFO") logging_format: str = Field(default="json") logging_file: str = Field(default="") # 队列配置 queue_max_concurrent: int = Field(default=10) queue_max_retries: int = Field(default=3) queue_retry_delay: int = Field(default=60) queue_priority_levels: int = Field(default=3) # 防抖配置 deduplication_enabled: bool = Field(default=True) deduplication_window_seconds: int = Field(default=300) deduplication_strategy: str = Field(default="commit_branch") deduplication_cache_ttl: int = Field(default=3600) # 业务配置 environments: Dict[str, EnvironmentConfig] = Field(default_factory=dict) deduplication: DeduplicationConfig = DeduplicationConfig() queue: QueueConfig = QueueConfig() class Config: env_file = ".env" env_nested_delimiter = "__" @validator("environments", pre=True) def load_environments_from_file(cls, v): """从配置文件加载环境配置""" if isinstance(v, dict) and v: return v # 尝试从配置文件加载 config_file = Path("config/environments.yaml") if config_file.exists(): with open(config_file, "r", encoding="utf-8") as f: config_data = yaml.safe_load(f) return config_data.get("environments", {}) # 默认配置 return { "dev": EnvironmentConfig( branches=["dev", "develop", "development"], jenkins_job="alpha-build", jenkins_url="https://jenkins-alpha.example.com", priority=2 ), "prod": EnvironmentConfig( branches=["prod", "production", "main", "master"], jenkins_job="production-build", jenkins_url="https://jenkins-prod.example.com", priority=1 ), "default": EnvironmentConfig( branches=["*"], jenkins_job="default-build", jenkins_url="https://jenkins-default.example.com", priority=3 ) } def get_environment_for_branch(self, branch: str) -> Optional[EnvironmentConfig]: """根据分支名获取对应的环境配置""" for env_name, env_config in self.environments.items(): if branch in env_config.branches or "*" in env_config.branches: return env_config return None def get_environment_by_name(self, name: str) -> Optional[EnvironmentConfig]: """根据环境名获取配置""" return self.environments.get(name) # 全局配置实例 settings = Settings() def get_settings() -> Settings: """获取配置实例""" return settings def reload_settings(): """重新加载配置""" global settings settings = Settings()