diff --git a/pipekit/cli.py b/pipekit/cli.py index b94f2ce..6d7a9e1 100644 --- a/pipekit/cli.py +++ b/pipekit/cli.py @@ -139,6 +139,26 @@ def cmd_run(args) -> int: return 0 if outcome.status == "success" else 1 +def cmd_run_group(args) -> int: + group = repo.get_group_by_name(args.group) + if group is None: + print(f"error: group {args.group!r} not found") + return 1 + try: + outcome = engine.run_group(group["id"], dry_run=args.dry_run) + except engine.LockBusy as e: + print(f"busy: {e}") + return 75 # EX_TEMPFAIL — retryable, distinct from a real failure + + tag = "DRY RUN — no jrunner calls made" if args.dry_run else "" + print(f"group_run_id={outcome.group_run_id} status={outcome.status} " + f"modules={len(outcome.module_outcomes)} {tag}".rstrip()) + for o in outcome.module_outcomes: + line = f" run_id={o.run_id} status={o.status} rows={o.row_count}" + print(f"{line} error={o.error}" if o.error else line) + return 0 if outcome.status in ("success", "dry_run") else 1 + + def cmd_serve(args) -> int: import uvicorn from .api import create_app @@ -351,6 +371,13 @@ def main(argv: list[str] | None = None) -> int: help="build SQL but do not invoke jrunner") p_run.set_defaults(func=cmd_run) + p_rg = sub.add_parser("run-group", + help="run all enabled modules in a group (synchronous)") + p_rg.add_argument("group", help="group name") + p_rg.add_argument("--dry-run", action="store_true", + help="build SQL but do not invoke jrunner") + p_rg.set_defaults(func=cmd_run_group) + p_exp = sub.add_parser( "export", help="dump config (drivers/connections/modules/groups) to text files") p_exp.add_argument("--dir", help="target dir (default /config)")