ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
work_board_move.py
Go to the documentation of this file.
1# SPDX-License-Identifier: MIT
2# Copyright (c) 2026 Brighton Sikarskie
3
4"""Move an issue to a new status on the Kanban board."""
5
6from __future__ import annotations
7
8import sys
9from pathlib import Path
10
11sys.path.insert(0, str(Path(__file__).resolve().parent))
12from work_git import ToolMissingError, WorkError, run_process
13from work_tracker import TrackerSchema, tracker_schema
14
15EXPECTED_ARGC = 3
16GH_TIMEOUT_S = 30
17
18
19def _usage() -> int:
20 """Report the fixed two-argument shape."""
21 print("Usage: work_board_move.py <issue_number> <status>", file=sys.stderr)
22 return 1
23
24
25def _load_schema() -> TrackerSchema | None:
26 """Return the tracker authority, reporting a load failure."""
27 try:
28 return tracker_schema()
29 except WorkError as exc:
30 print(f"error loading tracker schema: {exc}", file=sys.stderr)
31 return None
32
33
34def _resolve_status(schema: TrackerSchema, target: str) -> str | None:
35 """Return the canonical status spelling, reporting an unknown one."""
36 status_map = {status.lower(): status for status in schema.statuses}
37 exact = status_map.get(target.lower())
38 if exact is None:
39 valid = ", ".join(f"'{status}'" for status in schema.statuses)
40 print(f"error: invalid status '{target}'. Must be one of: {valid}", file=sys.stderr)
41 return exact
42
43
44def _move_command(schema: TrackerSchema, issue_number: str, status: str) -> list[str]:
45 """Build one project item-edit argv for the validated move."""
46 issue_url = f"https://{schema.github_host}/{schema.repository}/issues/{issue_number}"
47 return [
48 "gh",
49 "project",
50 "item-edit",
51 str(schema.project_number),
52 "--owner",
53 schema.project_owner,
54 "--url",
55 issue_url,
56 "--field",
57 "Status",
58 "--value",
59 status,
60 ]
61
62
63def _run_move(command: list[str]) -> int:
64 """Execute one item-edit, reporting transport and payload failures."""
65 try:
66 proc = run_process(command, timeout=GH_TIMEOUT_S)
67 except ToolMissingError:
68 print("error: 'gh' CLI is not installed", file=sys.stderr)
69 return 1
70 except WorkError as exc:
71 print(f"error updating board: {exc}", file=sys.stderr)
72 return 1
73 if proc.ok:
74 print("Success!")
75 return 0
76 message = proc.stderr.strip() or proc.stdout.strip() or f"gh exited {proc.returncode}"
77 print(f"error updating board: {message}", file=sys.stderr)
78 if "scopes" in message.lower():
79 print("\nHint: Your gh token might lack the 'project' scope.", file=sys.stderr)
80 print("Run 'gh auth refresh -s project' to update your scopes.", file=sys.stderr)
81 return proc.returncode
82
83
84def main() -> int:
85 """Move one issue to a validated board status."""
86 if len(sys.argv) != EXPECTED_ARGC:
87 return _usage()
88 schema = _load_schema()
89 if schema is None:
90 return 1
91 status = _resolve_status(schema, sys.argv[2])
92 if status is None:
93 return 1
94 print(f"Moving #{sys.argv[1]} to [{status}] on the Kanban board...")
95 return _run_move(_move_command(schema, sys.argv[1], status))
96
97
98if __name__ == "__main__":
99 sys.exit(main())
void main(void)
The application entry point Reset_Handler hands control to.
Definition main.c:298