Files
driver-standard/napalm_standard/cli.py
T
christianmanivong c3151d62fa
CI / test (3.11) (pull_request) Successful in 27s
CI / test (3.12) (pull_request) Successful in 24s
CI / test (3.13) (pull_request) Successful in 23s
fix(ratchet): refuse a package directory that does not exist
napalm-hpe-aruba-procurve ships napalm_procurve; guessed from its name, the
ratchet measured nothing and wrote an empty baseline without a word.
2026-10-23 08:49:47 +02:00

106 lines
3.5 KiB
Python

"""napalm-standard: the commands the shared workflow runs in every driver repo.
napalm-standard check [--tag vX.Y.Z] [PATH] does the repo meet the standard?
napalm-standard ratchet [--write] [PATH] hold the quality baseline, or rewrite it
napalm-standard notes vX.Y.Z [PATH] print that version's CHANGELOG section
napalm-standard release vX.Y.Z [PATH] create or update the Gitea release;
reads GITEA_URL, GITEA_REPOSITORY, GITEA_TOKEN
napalm-standard package [PATH] print the import package (for mypy, bandit, cov)
"""
from __future__ import annotations
import argparse
import os
import pathlib
import sys
import tomllib
from napalm_standard import ratchet
from napalm_standard.changelog import changelog_section
from napalm_standard.check import Repo, check_repo
from napalm_standard.release import gitea_api, publish
_RELEASE_ENV = ("GITEA_URL", "GITEA_REPOSITORY", "GITEA_TOKEN")
def _repo(path: pathlib.Path) -> Repo:
return Repo(path, tomllib.loads((path / "pyproject.toml").read_text()))
def _check(args: argparse.Namespace) -> int:
findings = check_repo(args.path, tag=args.tag)
for finding in findings:
print(finding)
if findings:
print(f"{len(findings)} finding(s); see STANDARDS.md in NAPALM/driver-standard")
return 1
print("meets the standard")
return 0
def _ratchet(args: argparse.Namespace) -> int:
try:
code, text = ratchet.run(args.path, _repo(args.path).package, write=args.write)
except FileNotFoundError as exc:
print(exc, file=sys.stderr)
return 2
print(text)
return code
def _notes(args: argparse.Namespace) -> int:
section = changelog_section((args.path / "CHANGELOG.md").read_text(), args.tag)
if section is None:
return 1
print(section)
return 0
def _release(args: argparse.Namespace) -> int:
missing = [name for name in _RELEASE_ENV if not os.environ.get(name)]
if missing:
print(f"missing environment: {', '.join(missing)}", file=sys.stderr)
return 2
api = gitea_api(*(os.environ[name] for name in _RELEASE_ENV))
changelog = (args.path / "CHANGELOG.md").read_text()
result = publish(args.tag, _repo(args.path).name, changelog, api)
print(f"release {result.get('id')} for {args.tag}")
return 0
def _package(args: argparse.Namespace) -> int:
print(_repo(args.path).package)
return 0
def _parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
prog="napalm-standard",
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
commands = parser.add_subparsers(dest="command", required=True)
def command(name: str, handler: object) -> argparse.ArgumentParser:
sub = commands.add_parser(name)
sub.set_defaults(handler=handler)
return sub
check = command("check", _check)
check.add_argument("--tag", help="also apply the release rules for this tag")
ratchet_cmd = command("ratchet", _ratchet)
ratchet_cmd.add_argument("--write", action="store_true", help="record today's state")
for name, handler in (("notes", _notes), ("release", _release)):
command(name, handler).add_argument("tag")
command("package", _package)
for sub in commands.choices.values():
sub.add_argument("path", nargs="?", type=pathlib.Path, default=pathlib.Path("."))
return parser
def main(argv: list[str] | None = None) -> int:
args = _parser().parse_args(argv)
code: int = args.handler(args)
return code