Skip to content

Commit 97d79fb

Browse files
feat: add --require-license strict mode flag
Closes #35
1 parent 0757319 commit 97d79fb

1 file changed

Lines changed: 42 additions & 5 deletions

File tree

src/deadcode/cli.py

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import json
6+
import os
67
import sys
78
from pathlib import Path
89

@@ -14,6 +15,17 @@
1415
from .config import DeadCodeConfig
1516
from .scanner import DeadCodeScanner, Finding
1617

18+
try:
19+
from revenueholdings_license import require_license as _rh_require_license
20+
21+
_HAS_RH_LICENSE = True
22+
except ImportError:
23+
_HAS_RH_LICENSE = False
24+
25+
def _rh_require_license(product: str) -> None: # type: ignore[misc]
26+
pass
27+
28+
1729
console = Console()
1830
err_console = Console(stderr=True)
1931

@@ -37,10 +49,21 @@
3749
multiple=True,
3850
help="Include only matching files (gitignore-style whitelist)",
3951
)
52+
@click.option(
53+
"--require-license",
54+
is_flag=True,
55+
envvar="REVENUEHOLDINGS_REQUIRE_LICENSE",
56+
help=(
57+
"Exit with an error if revenueholdings-license is not installed "
58+
"or if the license check fails. "
59+
"Also enabled via REVENUEHOLDINGS_REQUIRE_LICENSE=1."
60+
),
61+
)
4062
@click.version_option(__version__, prog_name="deadcode")
4163
@click.pass_context
4264
def cli(
43-
ctx: click.Context, project: str, ignore: tuple[str, ...], include: tuple[str, ...]
65+
ctx: click.Context, project: str, ignore: tuple[str, ...], include: tuple[str, ...],
66+
require_license: bool,
4467
) -> None:
4568
"""DeadCode — Find and remove dead code in TS/React/Next.js projects.
4669
@@ -51,9 +74,23 @@ def cli(
5174
ctx.obj["project"] = project
5275
ctx.obj["ignore"] = list(ignore) if ignore else None
5376
ctx.obj["include"] = list(include) if include else None
77+
ctx.obj["require_license"] = require_license or bool(
78+
os.environ.get("REVENUEHOLDINGS_REQUIRE_LICENSE")
79+
)
5480
# Load .deadcode.yml config
5581
ctx.obj["config"] = DeadCodeConfig.load(project)
5682

83+
# License check
84+
strict = ctx.obj["require_license"]
85+
if _HAS_RH_LICENSE:
86+
_rh_require_license("deadcode")
87+
elif strict:
88+
err_console.print(
89+
"[bold red]Error:[/bold red] revenueholdings-license is not installed. "
90+
"Install it with: pip install revenueholdings-license"
91+
)
92+
sys.exit(1)
93+
5794

5895
def _merge_config_ignore(ctx: click.Context) -> list[str] | None:
5996
"""Merge CLI --ignore flags with .deadcode.yml ignore patterns."""
@@ -155,7 +192,7 @@ def scan(
155192
console.print("OK — 0 findings")
156193
else:
157194
for f in findings:
158-
console.print(f"{f.file}:{f.line} \u2014 {f.category}: {f.name}")
195+
console.print(f"{f.file}:{f.line} {f.category}: {f.name}")
159196
console.print(f"\n{len(findings)} findings")
160197
elif effective_format == "github":
161198
# GitHub Actions annotation syntax
@@ -177,7 +214,7 @@ def scan(
177214
)
178215

179216
if not findings:
180-
console.print("[green] No dead code found![/green]")
217+
console.print("[green]\u2713 No dead code found![/green]")
181218
else:
182219
# Group by category
183220
by_category: dict[str, list[Finding]] = {}
@@ -291,7 +328,7 @@ def remove(ctx: click.Context, dry_run: bool, category: str | None) -> None:
291328
removable = [f for f in findings if f.removable]
292329

293330
if not removable:
294-
console.print("[green] Nothing removable found.[/green]")
331+
console.print("[green]\u2713 Nothing removable found.[/green]")
295332
return
296333

297334
# Group by file
@@ -332,7 +369,7 @@ def remove(ctx: click.Context, dry_run: bool, category: str | None) -> None:
332369
filepath.write_text("".join(lines), encoding="utf-8")
333370
removed_count += len(lines_to_remove)
334371
console.print(
335-
f"[green][/green] Cleaned {rel_file} ({len(lines_to_remove)} lines)"
372+
f"[green]\u2713[/green] Cleaned {rel_file} ({len(lines_to_remove)} lines)"
336373
)
337374

338375
action = "Would remove" if dry_run else "Removed"

0 commit comments

Comments
 (0)