from __future__ import annotations from dataclasses import dataclass, field from pathlib import Path from typing import Dict, List import os try: # yaml is optioneel; bij ontbreken vallen we terug op defaults import yaml # type: ignore[import] except Exception: # pragma: no cover - defensieve fallback yaml = None @dataclass class GitFlowConfig: main_branch: str = "main" develop_branch: str = "develop" remote_name: str = "origin" feature_prefix: str = "feature/" bugfix_prefix: str = "bugfix/" hotfix_prefix: str = "hotfix/" release_prefix: str = "release/" tag_format: str = "v{version}" # Merge-strategie kan later per actie configureerbaar worden use_no_ff_for_feature: bool = True use_no_ff_for_release: bool = True use_no_ff_for_hotfix: bool = True # Globale dry-run vlag: wanneer True worden muterende git-acties niet # echt uitgevoerd, maar enkel gelogd. dry_run: bool = False # Hooks per event (feature_start, feature_finish, ...) hooks: Dict[str, List[str]] = field(default_factory=dict) # Cleanup-instellingen: lokale branches verwijderen na succesvolle finish delete_feature_after_finish: bool = False delete_bugfix_after_finish: bool = False delete_release_after_finish: bool = False delete_hotfix_after_finish: bool = False # Omgevingen voor tagging (suffixen) en defaults environments: Dict[str, str] = field( default_factory=lambda: { "test": "-test", "staging": "-staging", "production": "", } ) release_default_env: str = "production" hotfix_default_env: str = "production" CONFIG = GitFlowConfig() def load_config() -> None: """Laad configuratie. We lezen optioneel `scripts/git/gitflow.yaml` in en overschrijven velden in `CONFIG` op basis van de inhoud. Als het bestand of de yaml-lib ontbreekt, blijven de defaults gelden. """ if yaml is None: return None # Zoek het config-bestand relatief t.o.v. de huidige werkdirectory. # We gaan ervan uit dat gitflow vanuit de projectroot draait (wrapper). cfg_path = Path("scripts") / "git" / "gitflow.yaml" if not cfg_path.is_file(): return None with cfg_path.open("r", encoding="utf-8") as fh: data = yaml.safe_load(fh) or {} # Eenvoudige mapping: alleen bekende keys worden overgenomen. if not isinstance(data, dict): return None # Basisvelden CONFIG.main_branch = str(data.get("main_branch", CONFIG.main_branch)) CONFIG.develop_branch = str(data.get("develop_branch", CONFIG.develop_branch)) CONFIG.remote_name = str(data.get("remote_name", CONFIG.remote_name)) # Prefixes prefixes = data.get("branch_prefixes") or {} if isinstance(prefixes, dict): CONFIG.feature_prefix = str(prefixes.get("feature", CONFIG.feature_prefix)) CONFIG.bugfix_prefix = str(prefixes.get("bugfix", CONFIG.bugfix_prefix)) CONFIG.hotfix_prefix = str(prefixes.get("hotfix", CONFIG.hotfix_prefix)) CONFIG.release_prefix = str(prefixes.get("release", CONFIG.release_prefix)) # Merge-strategieën strategies = data.get("merge_strategies") or {} if isinstance(strategies, dict): CONFIG.use_no_ff_for_feature = strategies.get( "feature_finish", "no-ff" if CONFIG.use_no_ff_for_feature else "ff" ) == "no-ff" CONFIG.use_no_ff_for_release = strategies.get( "release_finish", "no-ff" if CONFIG.use_no_ff_for_release else "ff" ) == "no-ff" CONFIG.use_no_ff_for_hotfix = strategies.get( "hotfix_finish", "no-ff" if CONFIG.use_no_ff_for_hotfix else "ff" ) == "no-ff" # Tag-format if "tag_format" in data: CONFIG.tag_format = str(data["tag_format"]) # Cleanup-instellingen cleanup = data.get("cleanup") or {} if isinstance(cleanup, dict): CONFIG.delete_feature_after_finish = bool( cleanup.get("delete_feature_after_finish", CONFIG.delete_feature_after_finish) ) CONFIG.delete_bugfix_after_finish = bool( cleanup.get("delete_bugfix_after_finish", CONFIG.delete_bugfix_after_finish) ) CONFIG.delete_release_after_finish = bool( cleanup.get("delete_release_after_finish", CONFIG.delete_release_after_finish) ) CONFIG.delete_hotfix_after_finish = bool( cleanup.get("delete_hotfix_after_finish", CONFIG.delete_hotfix_after_finish) ) # Hooks hooks = data.get("hooks") or {} if isinstance(hooks, dict): normalized: Dict[str, List[str]] = {} for key, value in hooks.items(): if isinstance(value, list): normalized[key] = [str(cmd) for cmd in value] elif isinstance(value, str): normalized[key] = [value] CONFIG.hooks = normalized # Omgevingen en defaults envs = data.get("environments") or {} if isinstance(envs, dict): CONFIG.environments = {str(k): str(v) for k, v in envs.items()} if "release_default_env" in data: CONFIG.release_default_env = str(data["release_default_env"]) if "hotfix_default_env" in data: CONFIG.hotfix_default_env = str(data["hotfix_default_env"]) # Dry-run kan ook via config gezet worden, maar CLI-flag heeft prioriteit; # daarom overschrijven we hier niet expliciet als het al gezet is. if "dry_run" in data and not CONFIG.dry_run: CONFIG.dry_run = bool(data["dry_run"]) return None