ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
work_tracker.py
Go to the documentation of this file.
1# SPDX-License-Identifier: MIT
2# Copyright (c) 2026 Brighton Sikarskie
3"""Load the single machine-readable GitHub tracker authority."""
4
5from __future__ import annotations
6
7import json
8import re
9from dataclasses import dataclass
10from functools import lru_cache
11from pathlib import Path
12from typing import NoReturn
13
14from work_git import WorkError
15
16REPOSITORY_RE = re.compile(r"^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$")
17LOGIN_RE = re.compile(r"^[A-Za-z0-9-]{1,39}$")
18SCHEMA_VERSION = 1
19
20
21def fail(message: str, cause: BaseException | None = None) -> NoReturn:
22 """Raise one consistently constructed tracker-schema error."""
23 error = WorkError(message)
24 if cause is not None:
25 raise error from cause
26 raise error
27
28
29@dataclass(frozen=True)
30class TrackerSchema:
31 """Exact GitHub target plus allowed project field names."""
32
33 github_host: str
34 repository: str
35 project_owner: str
36 project_number: int
37 statuses: tuple[str, ...]
38 tracks: tuple[str, ...]
39
40
41def _string_list(payload: object, key: str) -> tuple[str, ...]:
42 """Read one non-empty duplicate-free string list."""
43 if not isinstance(payload, dict):
44 fail("tracker schema root must be an object")
45 raw = payload.get(key)
46 if not isinstance(raw, list) or not raw:
47 fail(f"tracker schema {key} must be a non-empty list")
48 values = tuple(raw)
49 if any(not isinstance(value, str) or not value or not value.isprintable() for value in values):
50 fail(f"tracker schema {key} contains an invalid value")
51 if len(set(values)) != len(values):
52 fail(f"tracker schema {key} contains a duplicate")
53 return values
54
55
56@lru_cache(maxsize=1)
57def tracker_schema() -> TrackerSchema:
58 """Load and validate ``scripts/dev/work/tracker.json`` once per process."""
59 path = Path(__file__).resolve().parents[1] / "tracker.json"
60 try:
61 payload = json.loads(path.read_text(encoding="ascii"))
62 except (OSError, UnicodeError, json.JSONDecodeError) as exc:
63 fail(f"tracker schema could not be read: {exc}", exc)
64 expected = {
65 "schema_version",
66 "github_host",
67 "repository",
68 "project_owner",
69 "project_number",
70 "statuses",
71 "tracks",
72 }
73 valid_root = isinstance(payload, dict) and set(payload) == expected
74 if not valid_root or payload.get("schema_version") != SCHEMA_VERSION:
75 fail("tracker schema keys or version are unsupported")
76 host = payload["github_host"]
77 repository = payload["repository"]
78 owner = payload["project_owner"]
79 number = payload["project_number"]
80 if host != "github.com":
81 fail("tracker schema must pin github.com")
82 if not isinstance(repository, str) or REPOSITORY_RE.fullmatch(repository) is None:
83 fail("tracker schema repository must be owner/name")
84 if not isinstance(owner, str) or LOGIN_RE.fullmatch(owner) is None:
85 fail("tracker schema project_owner is invalid")
86 if not isinstance(number, int) or isinstance(number, bool) or number < 1:
87 fail("tracker schema project_number must be positive")
88 return TrackerSchema(
89 github_host=host,
90 repository=repository,
91 project_owner=owner,
92 project_number=number,
93 statuses=_string_list(payload, "statuses"),
94 tracks=_string_list(payload, "tracks"),
95 )