generated from coulomb/repo-seed
first working guide-board architecture core
This commit is contained in:
138
src/guide_board/cli.py
Normal file
138
src/guide_board/cli.py
Normal file
@@ -0,0 +1,138 @@
|
||||
"""Guide Board command line interface."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from guide_board.discovery import discover_extensions
|
||||
from guide_board.errors import GuideBoardError
|
||||
from guide_board.execution import run_assessment
|
||||
from guide_board.io import load_json, write_json
|
||||
from guide_board.planning import (
|
||||
build_run_plan,
|
||||
validate_assessment_profile,
|
||||
validate_target_profile,
|
||||
)
|
||||
from guide_board.schema import assert_valid
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = build_parser()
|
||||
args = parser.parse_args(argv)
|
||||
try:
|
||||
result = args.func(args)
|
||||
except GuideBoardError as exc:
|
||||
print(f"guide-board: {exc}", file=sys.stderr)
|
||||
return 2
|
||||
except (OSError, ValueError) as exc:
|
||||
print(f"guide-board: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if result is not None:
|
||||
print_json(result)
|
||||
return 0
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(prog="guide-board")
|
||||
parser.add_argument("--root", type=Path, default=Path.cwd(), help="repository root")
|
||||
subcommands = parser.add_subparsers(required=True)
|
||||
|
||||
extensions = subcommands.add_parser("extensions", help="extension operations")
|
||||
extension_commands = extensions.add_subparsers(required=True)
|
||||
list_extensions = extension_commands.add_parser("list", help="list discovered extensions")
|
||||
list_extensions.set_defaults(func=cmd_extensions_list)
|
||||
validate_extensions = extension_commands.add_parser(
|
||||
"validate", help="validate discovered extension manifests"
|
||||
)
|
||||
validate_extensions.set_defaults(func=cmd_extensions_validate)
|
||||
|
||||
profile = subcommands.add_parser("profile", help="profile validation")
|
||||
profile_commands = profile.add_subparsers(required=True)
|
||||
target = profile_commands.add_parser("validate-target", help="validate a target profile")
|
||||
target.add_argument("path", type=Path)
|
||||
target.set_defaults(func=cmd_validate_target)
|
||||
assessment = profile_commands.add_parser(
|
||||
"validate-assessment", help="validate an assessment profile"
|
||||
)
|
||||
assessment.add_argument("path", type=Path)
|
||||
assessment.set_defaults(func=cmd_validate_assessment)
|
||||
|
||||
plan = subcommands.add_parser("plan", help="build a run plan")
|
||||
plan.add_argument("--target", type=Path, required=True)
|
||||
plan.add_argument("--assessment", type=Path, required=True)
|
||||
plan.add_argument("--output", type=Path)
|
||||
plan.set_defaults(func=cmd_plan)
|
||||
|
||||
run = subcommands.add_parser("run", help="run the baseline assessment executor")
|
||||
run.add_argument("--target", type=Path, required=True)
|
||||
run.add_argument("--assessment", type=Path, required=True)
|
||||
run.add_argument("--output-dir", type=Path)
|
||||
run.set_defaults(func=cmd_run)
|
||||
|
||||
schema = subcommands.add_parser("schema", help="schema validation")
|
||||
schema.add_argument("schema_name")
|
||||
schema.add_argument("path", type=Path)
|
||||
schema.set_defaults(func=cmd_schema_validate)
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def cmd_extensions_list(args: argparse.Namespace) -> dict[str, Any]:
|
||||
extensions = discover_extensions(args.root)
|
||||
return {
|
||||
"extensions": [
|
||||
{
|
||||
"id": extension.id,
|
||||
"name": extension.manifest["name"],
|
||||
"version": extension.manifest["version"],
|
||||
"type": extension.manifest["extension_type"],
|
||||
"path": str(extension.path.relative_to(args.root)),
|
||||
}
|
||||
for extension in extensions
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def cmd_extensions_validate(args: argparse.Namespace) -> dict[str, Any]:
|
||||
extensions = discover_extensions(args.root)
|
||||
return {
|
||||
"status": "valid",
|
||||
"extensions": [extension.id for extension in extensions],
|
||||
}
|
||||
|
||||
|
||||
def cmd_validate_target(args: argparse.Namespace) -> dict[str, Any]:
|
||||
profile = validate_target_profile(args.path)
|
||||
return {"status": "valid", "target_profile": profile["id"]}
|
||||
|
||||
|
||||
def cmd_validate_assessment(args: argparse.Namespace) -> dict[str, Any]:
|
||||
profile = validate_assessment_profile(args.path)
|
||||
return {"status": "valid", "assessment_profile": profile["id"]}
|
||||
|
||||
|
||||
def cmd_plan(args: argparse.Namespace) -> dict[str, Any] | None:
|
||||
plan = build_run_plan(args.root, args.target, args.assessment)
|
||||
if args.output:
|
||||
write_json(args.output, plan)
|
||||
return {"status": "written", "path": str(args.output)}
|
||||
return plan
|
||||
|
||||
|
||||
def cmd_run(args: argparse.Namespace) -> dict[str, Any]:
|
||||
return run_assessment(args.root, args.target, args.assessment, args.output_dir)
|
||||
|
||||
|
||||
def cmd_schema_validate(args: argparse.Namespace) -> dict[str, Any]:
|
||||
document = load_json(args.path)
|
||||
assert_valid(document, args.schema_name)
|
||||
return {"status": "valid", "schema": args.schema_name, "path": str(args.path)}
|
||||
|
||||
|
||||
def print_json(value: Any) -> None:
|
||||
print(json.dumps(value, indent=2, sort_keys=True))
|
||||
Reference in New Issue
Block a user