- #17: default date range falls back to current month when .env dates are missing - #18: add --version, --verbose, --debug flags - #20: add --url, --api-key, --config CLI overrides - Config supports CLI overrides for URL/API key and explicit config file loading - Update README with new CLI options - Add tests for new flags and config overrides Closes #17, closes #18, closes #20
99 lines
3.3 KiB
Python
99 lines
3.3 KiB
Python
import os
|
||
from datetime import date, timedelta
|
||
from typing import Union
|
||
|
||
from dotenv import load_dotenv
|
||
|
||
load_dotenv(override=False)
|
||
|
||
DEFAULT_REDMINE_VERIFY = "/etc/ssl/certs/ca-certificates.crt"
|
||
FALSE_VALUES = {"0", "false", "no", "off"}
|
||
TRUE_VALUES = {"1", "true", "yes", "on"}
|
||
|
||
|
||
class Config:
|
||
_cli_url: str | None = None
|
||
_cli_api_key: str | None = None
|
||
|
||
@classmethod
|
||
def load_config(cls, path: str) -> None:
|
||
"""Загружает переменные из указанного .env-файла с override."""
|
||
load_dotenv(path, override=True)
|
||
|
||
@classmethod
|
||
def set_redmine_url(cls, url: str) -> None:
|
||
cls._cli_url = url.strip().rstrip("/") if url else None
|
||
|
||
@classmethod
|
||
def set_redmine_api_key(cls, key: str) -> None:
|
||
cls._cli_api_key = key.strip() if key else None
|
||
|
||
@classmethod
|
||
def get_redmine_url(cls) -> str:
|
||
if cls._cli_url is not None:
|
||
return cls._cli_url
|
||
return os.getenv("REDMINE_URL", "").strip().rstrip("/")
|
||
|
||
@classmethod
|
||
def get_redmine_api_key(cls) -> str:
|
||
if cls._cli_api_key is not None:
|
||
return cls._cli_api_key
|
||
return os.getenv("REDMINE_API_KEY", "").strip()
|
||
|
||
@classmethod
|
||
def get_redmine_user(cls) -> str:
|
||
return os.getenv("REDMINE_USER", "").strip()
|
||
|
||
@classmethod
|
||
def get_redmine_password(cls) -> str:
|
||
return os.getenv("REDMINE_PASSWORD", "").strip()
|
||
|
||
@classmethod
|
||
def get_redmine_verify(cls) -> Union[bool, str]:
|
||
value = os.getenv("REDMINE_VERIFY", "").strip()
|
||
if not value:
|
||
return DEFAULT_REDMINE_VERIFY
|
||
|
||
normalized = value.lower()
|
||
if normalized in FALSE_VALUES:
|
||
return False
|
||
if normalized in TRUE_VALUES:
|
||
return True
|
||
return value
|
||
|
||
@classmethod
|
||
def get_author(cls, cli_author: str = "") -> str:
|
||
"""Возвращает автора: из CLI если задан, иначе из .env, иначе — заглушку."""
|
||
if cli_author:
|
||
return cli_author
|
||
return os.getenv("REDMINE_AUTHOR", "").strip()
|
||
|
||
@classmethod
|
||
def get_default_date_range(cls) -> str:
|
||
default_from_date = os.getenv("DEFAULT_FROM_DATE", "").strip()
|
||
default_to_date = os.getenv("DEFAULT_TO_DATE", "").strip()
|
||
if default_from_date and default_to_date:
|
||
return f"{default_from_date}--{default_to_date}"
|
||
|
||
# fallback: текущий месяц
|
||
today = date.today()
|
||
start = today.replace(day=1)
|
||
# последний день месяца: берём первое число следующего месяца и вычитаем день
|
||
if today.month == 12:
|
||
next_month = today.replace(year=today.year + 1, month=1, day=1)
|
||
else:
|
||
next_month = today.replace(month=today.month + 1, day=1)
|
||
end = next_month - timedelta(days=1)
|
||
return f"{start.isoformat()}--{end.isoformat()}"
|
||
|
||
@classmethod
|
||
def validate(cls) -> None:
|
||
if not cls.get_redmine_url():
|
||
raise ValueError("REDMINE_URL is required (set via env or .env)")
|
||
if cls.get_redmine_api_key():
|
||
return
|
||
if not (cls.get_redmine_user() and cls.get_redmine_password()):
|
||
raise ValueError(
|
||
"REDMINE_API_KEY is required, or set both REDMINE_USER and REDMINE_PASSWORD"
|
||
)
|