feat(palier-1): journal d'événements, détail d'issue, vieillissement, WIP
- board_events append-only + log_event/get_events/column_entry_times/
get_metrics (débit, temps de cycle); journalisation des moves,
créations, fermetures/rouvertures (UI et réconciliation Gitea),
commentaires; un reclassement intra-colonne ne journalise pas
- client Gitea: get_issue, get_issue_comments (paginés), create_comment
- API: GET /api/issues/{o}/{r}/{n} (404 propre), POST .../comments,
GET /api/events, GET /api/metrics, page /activity
- config: KANBANTE_WIP_LIMITS (colonne:limite) et KANBANTE_AGING_DAYS;
le board calcule le temps en colonne (journal, replis updated_at
puis création de l'issue)
- reconcile_board_state retourne aussi les numéros fermés/purgés
This commit is contained in:
+21
-1
@@ -17,6 +17,12 @@ Environment variables:
|
||||
KANBANTE_MAX_NOTE_CHARS Maximum size of a project note (default 20000).
|
||||
KANBANTE_SYNC_GITEA "1" (default) = moving a card to/from "done"
|
||||
closes / reopens the Gitea issue.
|
||||
KANBANTE_WIP_LIMITS Comma list "column:limit" (e.g.
|
||||
"in_progress:5,review:3"). Columns not
|
||||
listed are unlimited. Soft limits: the UI
|
||||
warns, moves are never blocked.
|
||||
KANBANTE_AGING_DAYS Days in the same column before a card is
|
||||
flagged as aging (default 7; "stale" at 2x).
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -25,7 +31,7 @@ from pathlib import Path
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
APP_VERSION = "0.2.0"
|
||||
APP_VERSION = "0.3.0"
|
||||
|
||||
|
||||
def _env_bool(name: str, default: bool) -> bool:
|
||||
@@ -51,6 +57,16 @@ def _env_float(name: str, default: float) -> float:
|
||||
return default
|
||||
|
||||
|
||||
def _env_wip_limits(name: str) -> dict[str, int]:
|
||||
limits: dict[str, int] = {}
|
||||
for chunk in os.getenv(name, "").split(","):
|
||||
column, sep, value = chunk.partition(":")
|
||||
column = column.strip()
|
||||
if sep and column and value.strip().isdigit():
|
||||
limits[column] = int(value.strip())
|
||||
return limits
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Settings:
|
||||
gitea_url: str = "https://git.dracodev.net"
|
||||
@@ -63,6 +79,8 @@ class Settings:
|
||||
cache_ttl: float = 30.0
|
||||
max_note_chars: int = 20_000
|
||||
sync_gitea: bool = True
|
||||
wip_limits: dict | None = None
|
||||
aging_days: int = 7
|
||||
|
||||
@property
|
||||
def auth_enabled(self) -> bool:
|
||||
@@ -84,4 +102,6 @@ def get_settings() -> Settings:
|
||||
cache_ttl=_env_float("KANBANTE_CACHE_TTL", 30.0),
|
||||
max_note_chars=_env_int("KANBANTE_MAX_NOTE_CHARS", 20_000),
|
||||
sync_gitea=_env_bool("KANBANTE_SYNC_GITEA", True),
|
||||
wip_limits=_env_wip_limits("KANBANTE_WIP_LIMITS"),
|
||||
aging_days=_env_int("KANBANTE_AGING_DAYS", 7),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user