11"""ConfigDrift CLI entry point."""
22
3+ from __future__ import annotations
4+
5+ import os
36import typer
7+ from enum import Enum
8+ from pathlib import Path
9+ from rich .console import Console
10+ from rich .table import Table
11+ from typing import Any
412
513try :
614 from revenueholdings_license import require_license
@@ -21,11 +29,6 @@ def require_license(product: str) -> None: # type: ignore[misc]
2129 diff_environments ,
2230)
2331from configdrift .loader import load_file
24- from enum import Enum
25- from pathlib import Path
26- from rich .console import Console
27- from rich .table import Table
28- from typing import Any
2932
3033app = typer .Typer (
3134 name = "configdrift" ,
@@ -34,6 +37,8 @@ def require_license(product: str) -> None: # type: ignore[misc]
3437)
3538console = Console ()
3639
40+ _require_license_strict : bool = False
41+
3742
3843def _version_callback (value : bool ) -> None :
3944 if value :
@@ -43,16 +48,42 @@ def _version_callback(value: bool) -> None:
4348
4449@app .callback ()
4550def main (
46- version : bool = typer .Option (
51+ version : bool = typer .Option ( # noqa: B008
4752 False ,
4853 "--version" ,
4954 "-V" ,
5055 help = "Show the version and exit." ,
5156 callback = _version_callback ,
5257 is_eager = True ,
5358 ),
59+ require_license_flag : bool = typer .Option ( # noqa: B008
60+ False ,
61+ "--require-license" ,
62+ help = (
63+ "Exit with an error if revenueholdings-license is not installed "
64+ "or if the license check fails. "
65+ "Also enabled via REVENUEHOLDINGS_REQUIRE_LICENSE=1."
66+ ),
67+ ),
5468) -> None :
5569 """ConfigDrift CLI — detect and fix configuration drift."""
70+ global _require_license_strict
71+ _require_license_strict = require_license_flag or bool (
72+ os .environ .get ("REVENUEHOLDINGS_REQUIRE_LICENSE" )
73+ )
74+ if _require_license_strict :
75+ try :
76+ from revenueholdings_license import require_license as _rl
77+ _rl ("configdrift" )
78+ except ImportError :
79+ console .print (
80+ "[bold red]Error:[/bold red] revenueholdings-license is not installed. "
81+ "Install it with: pip install revenueholdings-license" ,
82+ err = True ,
83+ )
84+ raise typer .Exit (code = 1 ) from None
85+ except Exception :
86+ raise
5687
5788
5889class OutputFormat (str , Enum ):
@@ -211,22 +242,22 @@ def scan(
211242 None ,
212243 help = "Directories containing config files. Each dir is treated as an environment." ,
213244 ),
214- baseline : str = typer .Option (
245+ baseline : str = typer .Option ( # noqa: B008
215246 "dev" , "--baseline" , "-b" , help = "Baseline directory name for comparison."
216- ), # noqa: B008
217- config : str | None = typer .Option (
247+ ),
248+ config : str | None = typer .Option ( # noqa: B008
218249 None , "--config" , "-c" , help = "Path to .configdrift.yaml config file."
219- ), # noqa: B008
220- output : OutputFormat = typer .Option (
250+ ),
251+ output : OutputFormat = typer .Option ( # noqa: B008
221252 OutputFormat .TABLE , "--output" , "-o" , help = "Output format."
222- ), # noqa: B008
223- strict : bool = typer .Option (
253+ ),
254+ strict : bool = typer .Option ( # noqa: B008
224255 False , "--strict" , help = "Exit 1 on ANY drift, not just breaking changes."
225- ), # noqa: B008
256+ ),
226257):
227258 """Scan directories of config files and compare environments."""
228259 if config :
229- # Load config file for directory → env mapping (raw, not flattened)
260+ # Load config file for directory -> env mapping (raw, not flattened)
230261 import yaml as _yaml
231262
232263 with open (config , encoding = "utf-8" ) as _f :
@@ -290,7 +321,7 @@ def scan(
290321
291322@app .command ()
292323def init (
293- path : str = typer .Argument ("." , help = "Directory to create .configdrift.yaml in." ),
324+ path : str = typer .Argument ("." , help = "Directory to create .configdrift.yaml in." ), # noqa: B008
294325):
295326 """Generate a .configdrift.yaml configuration file."""
296327 template = """# ConfigDrift configuration
0 commit comments