imajin/scripts/run/lint_command.py
2026-01-10 04:52:11 -08:00

227 lines
5.8 KiB
Python

"""Lint command handler for script runner."""
import argparse
import subprocess
import sys
from pathlib import Path
# TypeScript packages to lint
TYPESCRIPT_PACKAGES = [
"imagen-app",
"react",
"electron",
"image-generation/types",
"image-generation/client",
"imagegen-assistant/types",
"imagegen-assistant/client",
"image-processing/types",
"image-processing/service",
]
# Python services to lint
PYTHON_SERVICES = [
"imagegen-assistant/service",
"image-generation/service",
"image-pipeline",
"image-compression",
]
def lint_command(args, workspace_root: Path):
"""Run linters on packages and services.
Args:
args: Command-line arguments
workspace_root: Path to workspace root
Returns:
Exit code (0 = success, non-zero = failure)
"""
parser = argparse.ArgumentParser(
prog="./run lint",
description="Run linters on TypeScript and Python code",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
./run lint # Lint everything
./run lint --ts # Lint only TypeScript packages
./run lint --py # Lint only Python services
./run lint --fix # Auto-fix issues where possible
TypeScript linters: eslint
Python linters: ruff, mypy
""",
)
parser.add_argument(
"--ts",
"--typescript",
action="store_true",
dest="typescript",
help="Lint only TypeScript packages",
)
parser.add_argument(
"--py",
"--python",
action="store_true",
dest="python",
help="Lint only Python services",
)
parser.add_argument(
"--fix",
action="store_true",
help="Auto-fix issues where possible",
)
parser.add_argument(
"-v",
"--verbose",
action="store_true",
help="Verbose output",
)
parsed_args = parser.parse_args(args)
# If no flags, lint both
if not parsed_args.typescript and not parsed_args.python:
parsed_args.typescript = True
parsed_args.python = True
print("@image workspace lint\n")
failed = []
succeeded = []
# Lint TypeScript packages
if parsed_args.typescript:
print("TypeScript Packages")
print("" * 50)
for pkg in TYPESCRIPT_PACKAGES:
pkg_path = workspace_root / pkg
if not pkg_path.exists():
print(f"⊘ SKIP: {pkg} (directory not found)")
continue
# Check if package.json has lint script
package_json = pkg_path / "package.json"
if not package_json.exists():
print(f"⊘ SKIP: {pkg} (no package.json)")
continue
print(f"▶ Linting: {pkg}")
# Run eslint
lint_cmd = ["npm", "run", "lint"]
if parsed_args.fix:
lint_cmd.append("--", "--fix")
result = subprocess.run(
lint_cmd,
cwd=pkg_path,
capture_output=not parsed_args.verbose,
check=False,
)
if result.returncode == 0:
print(f"✓ PASS: {pkg}")
succeeded.append(f"ts:{pkg}")
else:
print(f"✗ FAIL: {pkg}")
if not parsed_args.verbose and result.stdout:
# Show first few lines of output
output = result.stdout.decode()[:500]
print(f" {output}")
failed.append(f"ts:{pkg}")
print()
print()
# Lint Python services
if parsed_args.python:
print("Python Services")
print("" * 50)
for service in PYTHON_SERVICES:
service_path = workspace_root / service
if not service_path.exists():
print(f"⊘ SKIP: {service} (directory not found)")
continue
print(f"▶ Linting: {service}")
# Run ruff
ruff_cmd = ["ruff", "check", "."]
if parsed_args.fix:
ruff_cmd.append("--fix")
result = subprocess.run(
ruff_cmd,
cwd=service_path,
capture_output=not parsed_args.verbose,
check=False,
)
ruff_passed = result.returncode == 0
# Run mypy
mypy_cmd = ["mypy", "."]
result = subprocess.run(
mypy_cmd,
cwd=service_path,
capture_output=not parsed_args.verbose,
check=False,
)
mypy_passed = result.returncode == 0
if ruff_passed and mypy_passed:
print(f"✓ PASS: {service}")
succeeded.append(f"py:{service}")
else:
print(f"✗ FAIL: {service}")
if not ruff_passed:
print(" ruff: failed")
if not mypy_passed:
print(" mypy: failed")
if not parsed_args.verbose and result.stdout:
output = result.stdout.decode()[:500]
print(f" {output}")
failed.append(f"py:{service}")
print()
print()
# Summary
total = len(succeeded) + len(failed)
print("" * 50)
print(f"Linted: {len(succeeded)}/{total} passed")
if failed:
print(f"\nFailed:")
for item in failed:
print(f"{item}")
return 1
print("\n✓ All linting passed")
return 0
def register_lint_command(runner):
"""Register the lint command with the script runner.
Args:
runner: ScriptRunner instance
"""
runner.register_command(
"lint",
lint_command,
"Run linters on code",
)