Skip to content

Commit f012938

Browse files
committed
Extend logic to use generation time data too
1 parent 8aed677 commit f012938

12 files changed

Lines changed: 276 additions & 128 deletions

.github/workflows/test_and_docs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ on:
3030
concurrency:
3131
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
3232
cancel-in-progress: ${{ github.ref_name != 'main' && !startsWith(github.ref_name, 'release/') }}
33+
env:
34+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3335
jobs:
3436
test_and_docs:
3537
runs-on: ubuntu-22.04

scripts/known_good/known_good_to_workspace_metadata.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ def main():
3838
try:
3939
known_good = load_known_good(Path(args.known_good))
4040
except FileNotFoundError as e:
41-
raise SystemExit(f"ERROR: {e}") from e
41+
raise SystemExit(f"ERROR: {e}")
4242
except ValueError as e:
43-
raise SystemExit(f"ERROR: {e}") from e
43+
raise SystemExit(f"ERROR: {e}")
4444

4545
modules = list(known_good.modules.values())
4646

scripts/known_good/models/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@
1212
# *******************************************************************************
1313
"""Models for score reference integration tools."""
1414

15-
from .module import Metadata, Module
15+
from .module import Module, Metadata
1616

1717
__all__ = ["Module", "Metadata"]

scripts/known_good/models/known_good.py

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import json
1919
from dataclasses import dataclass
2020
from pathlib import Path
21-
from typing import Any
21+
from typing import Any, Dict
2222

2323
from .module import Module
2424

@@ -30,34 +30,34 @@ class KnownGood:
3030
Module structure: modules = {"group1": {"module1": Module}, "group2": {"module2": Module}}
3131
"""
3232

33-
modules: dict[str, dict[str, Module]]
33+
modules: Dict[str, Dict[str, Module]]
3434
timestamp: str
3535

3636
@classmethod
37-
def from_dict(cls, data: dict[str, Any]) -> KnownGood:
37+
def from_dict(cls, data: Dict[str, Any]) -> KnownGood:
3838
"""Create a KnownGood instance from a dictionary.
3939
4040
Expected structure:
4141
{"modules": {"group1": {"score_baselibs": {...}}, "group2": {"score_logging": {...}}}}
4242
4343
Args:
44-
data: dictionary containing known_good.json data
44+
data: Dictionary containing known_good.json data
4545
4646
Returns:
4747
KnownGood instance
4848
"""
4949
modules_dict = data.get("modules", {})
5050
timestamp = data.get("timestamp", "")
5151

52-
parsed_modules: dict[str, dict[str, Module]] = {}
52+
parsed_modules: Dict[str, Dict[str, Module]] = {}
5353
for group_name, group_modules in modules_dict.items():
5454
if isinstance(group_modules, dict):
5555
modules_list = Module.parse_modules(group_modules)
5656
parsed_modules[group_name] = {m.name: m for m in modules_list}
5757

5858
return cls(modules=parsed_modules, timestamp=timestamp)
5959

60-
def to_dict(self) -> dict[str, Any]:
60+
def to_dict(self) -> Dict[str, Any]:
6161
"""Convert KnownGood instance to dictionary for JSON output.
6262
6363
Returns:
@@ -70,7 +70,7 @@ def to_dict(self) -> dict[str, Any]:
7070

7171
return {"modules": modules_output, "timestamp": self.timestamp}
7272

73-
def write(self, output_path: Path, *, dry_run: bool = False) -> None:
73+
def write(self, output_path: Path, dry_run: bool = False) -> None:
7474
"""Write known_good data to file or print for dry-run.
7575
7676
Args:
@@ -89,7 +89,8 @@ def write(self, output_path: Path, *, dry_run: bool = False) -> None:
8989
print(output_json, end="")
9090
print("---- END UPDATED JSON ----")
9191
else:
92-
output_path.write_text(output_json, encoding="utf-8")
92+
with open(output_path, "w", encoding="utf-8") as f:
93+
f.write(output_json)
9394
print(f"Successfully wrote updated known_good.json to {output_path}")
9495

9596

@@ -103,21 +104,22 @@ def load_known_good(path: Path) -> KnownGood:
103104
KnownGood instance with parsed modules
104105
"""
105106

106-
try:
107-
text = path.read_text(encoding="utf-8")
108-
data = json.loads(text)
109-
except json.JSONDecodeError as e:
110-
lines = text.splitlines()
111-
line = lines[e.lineno - 1] if 0 <= e.lineno - 1 < len(lines) else ""
112-
pointer = " " * (e.colno - 1) + "^"
113-
114-
hint = ""
115-
if "Expecting value" in e.msg:
116-
hint = "Possible causes: trailing comma, missing value, or extra comma."
117-
118-
raise ValueError(
119-
f"Invalid JSON at line {e.lineno}, column {e.colno}\n{line}\n{pointer}\n{e.msg}. {hint}"
120-
) from None
107+
with open(path, "r", encoding="utf-8") as f:
108+
text = f.read()
109+
try:
110+
data = json.loads(text)
111+
except json.JSONDecodeError as e:
112+
lines = text.splitlines()
113+
line = lines[e.lineno - 1] if 0 <= e.lineno - 1 < len(lines) else ""
114+
pointer = " " * (e.colno - 1) + "^"
115+
116+
hint = ""
117+
if "Expecting value" in e.msg:
118+
hint = "Possible causes: trailing comma, missing value, or extra comma."
119+
120+
raise ValueError(
121+
f"Invalid JSON at line {e.lineno}, column {e.colno}\n{line}\n{pointer}\n{e.msg}. {hint}"
122+
) from None
121123

122124
if not isinstance(data, dict) or not isinstance(data.get("modules"), dict):
123125
raise ValueError(f"Invalid known_good.json at {path} (expected object with 'modules' dict)")

scripts/known_good/models/module.py

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import logging
1818
from dataclasses import dataclass, field
19-
from typing import Any
19+
from typing import Any, Dict, List
2020
from urllib.parse import urlparse
2121

2222

@@ -37,7 +37,7 @@ class Metadata:
3737
langs: list[str] = field(default_factory=lambda: ["cpp", "rust"])
3838

3939
@classmethod
40-
def from_dict(cls, data: dict[str, Any]) -> Metadata:
40+
def from_dict(cls, data: Dict[str, Any]) -> Metadata:
4141
"""Create a Metadata instance from a dictionary.
4242
4343
Args:
@@ -53,7 +53,7 @@ def from_dict(cls, data: dict[str, Any]) -> Metadata:
5353
langs=data.get("langs", ["cpp", "rust"]),
5454
)
5555

56-
def to_dict(self) -> dict[str, Any]:
56+
def to_dict(self) -> Dict[str, Any]:
5757
"""Convert Metadata instance to dictionary representation.
5858
5959
Returns:
@@ -79,30 +79,30 @@ class Module:
7979
pin_version: bool = False
8080

8181
@classmethod
82-
def from_dict(cls, name: str, module_data: dict[str, Any]) -> Module:
82+
def from_dict(cls, name: str, module_data: Dict[str, Any]) -> Module:
8383
"""Create a Module instance from a dictionary representation.
8484
8585
Args:
86-
name: The module name
87-
module_data: Dictionary containing module configuration with keys:
88-
- repo (str): Repository URL
89-
- hash or commit (str): Commit hash
90-
- version (str, optional): Module version (when present, hash is ignored)
91-
- bazel_patches (list[str], optional): List of patch files for Bazel
92-
- metadata (dict, optional): Metadata configuration
93-
Example: {
94-
"code_root_path": "path/to/code/root",
95-
"extra_test_config": [""],
96-
"exclude_test_targets": [""],
97-
"langs": ["cpp", "rust"]
98-
}
99-
If not present, uses default Metadata values.
100-
- branch (str, optional): Git branch name (default: main)
101-
- pin_version (bool, optional): If true, module hash is not updated
102-
to latest HEAD by update scripts (default: false)
86+
name: The module name
87+
module_data: Dictionary containing module configuration with keys:
88+
- repo (str): Repository URL
89+
- hash or commit (str): Commit hash
90+
- version (str, optional): Module version (when present, hash is ignored)
91+
- bazel_patches (list[str], optional): List of patch files for Bazel
92+
- metadata (dict, optional): Metadata configuration
93+
Example: {
94+
"code_root_path": "path/to/code/root",
95+
"extra_test_config": [""],
96+
"exclude_test_targets": [""],
97+
"langs": ["cpp", "rust"]
98+
}
99+
If not present, uses default Metadata values.
100+
- branch (str, optional): Git branch name (default: main)
101+
- pin_version (bool, optional): If true, module hash is not updated
102+
to latest HEAD by update scripts (default: false)
103103
104104
Returns:
105-
Module instance
105+
Module instance
106106
"""
107107
repo = module_data.get("repo", "")
108108
# Support both 'hash' and 'commit' keys
@@ -119,14 +119,17 @@ def from_dict(cls, name: str, module_data: dict[str, Any]) -> Module:
119119

120120
# Parse metadata - if not present or is None/empty dict, use defaults
121121
metadata_data = module_data.get("metadata")
122-
metadata = Metadata.from_dict(metadata_data) if metadata_data is not None else Metadata()
123-
124-
# Enable once we are able to remove '*' in known_good.json
125-
# if any("*" in target for target in metadata.exclude_test_targets):
126-
# raise Exception(
127-
# f"Module {name} has wildcard '*' in exclude_test_targets, which is not allowed. "
128-
# "Please specify explicit test targets to exclude or remove the key if no exclusions are needed."
129-
# )
122+
if metadata_data is not None:
123+
metadata = Metadata.from_dict(metadata_data)
124+
# Enable once we are able to remove '*' in known_good.json
125+
# if any("*" in target for target in metadata.exclude_test_targets):
126+
# raise Exception(
127+
# f"Module {name} has wildcard '*' in exclude_test_targets, which is not allowed. "
128+
# "Please specify explicit test targets to exclude or remove the key if no exclusions are needed."
129+
# )
130+
else:
131+
# If metadata key is missing, create with defaults
132+
metadata = Metadata()
130133

131134
branch = module_data.get("branch", "main")
132135
pin_version = module_data.get("pin_version", False)
@@ -143,7 +146,7 @@ def from_dict(cls, name: str, module_data: dict[str, Any]) -> Module:
143146
)
144147

145148
@classmethod
146-
def parse_modules(cls, modules_dict: dict[str, Any]) -> list[Module]:
149+
def parse_modules(cls, modules_dict: Dict[str, Any]) -> List[Module]:
147150
"""Parse modules dictionary into Module dataclass instances.
148151
149152
Args:
@@ -184,13 +187,13 @@ def owner_repo(self) -> str:
184187

185188
return f"{parts[0]}/{parts[1]}"
186189

187-
def to_dict(self) -> dict[str, Any]:
190+
def to_dict(self) -> Dict[str, Any]:
188191
"""Convert Module instance to dictionary representation for JSON output.
189192
190193
Returns:
191194
Dictionary with module configuration
192195
"""
193-
result: dict[str, Any] = {"repo": self.repo}
196+
result: Dict[str, Any] = {"repo": self.repo}
194197
if self.version:
195198
result["version"] = self.version
196199
else:

scripts/known_good/override_known_good_repo.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@
2626
"""
2727

2828
import argparse
29-
import datetime as dt
30-
import logging
29+
import os
3130
import re
31+
import datetime as dt
3232
from pathlib import Path
33+
from typing import Dict, List
34+
import logging
3335

3436
from models import Module
3537
from models.known_good import KnownGood, load_known_good
@@ -38,7 +40,7 @@
3840
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
3941

4042

41-
def parse_and_apply_overrides(modules: dict[str, Module], repo_overrides: list[str]) -> int:
43+
def parse_and_apply_overrides(modules: Dict[str, Module], repo_overrides: List[str]) -> int:
4244
"""
4345
Parse repo override arguments and apply them to modules.
4446
@@ -130,7 +132,7 @@ def parse_and_apply_overrides(modules: dict[str, Module], repo_overrides: list[s
130132
return overrides_applied
131133

132134

133-
def apply_overrides(known_good: KnownGood, repo_overrides: list[str]) -> KnownGood:
135+
def apply_overrides(known_good: KnownGood, repo_overrides: List[str]) -> KnownGood:
134136
"""Apply repository commit overrides to the known_good data.
135137
136138
Args:
@@ -207,25 +209,25 @@ def main() -> None:
207209
if args.verbose:
208210
logging.getLogger().setLevel(logging.DEBUG)
209211

210-
known_path = Path(args.known).resolve()
211-
output_path = Path(args.output).resolve()
212+
known_path = os.path.abspath(args.known)
213+
output_path = os.path.abspath(args.output)
212214

213215
# Load, update, and output
214216
logging.info(f"Loading {known_path}")
215217
try:
216218
known_good = load_known_good(known_path)
217219
except FileNotFoundError as e:
218-
raise SystemExit(f"ERROR: {e}") from e
220+
raise SystemExit(f"ERROR: {e}")
219221
except ValueError as e:
220-
raise SystemExit(f"ERROR: {e}") from e
222+
raise SystemExit(f"ERROR: {e}")
221223

222224
if not args.module_overrides:
223225
parser.error("at least one --module-override is required")
224226

225227
overrides = args.module_overrides
226228

227229
updated_known_good = apply_overrides(known_good, overrides)
228-
updated_known_good.write(Path(output_path), dry_run=args.dry_run)
230+
updated_known_good.write(Path(output_path), args.dry_run)
229231

230232

231233
if __name__ == "__main__":

0 commit comments

Comments
 (0)