Skip to content

Commit 54a3575

Browse files
committed
ci: validate tasks
1 parent e8e05de commit 54a3575

1 file changed

Lines changed: 138 additions & 0 deletions

File tree

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
name: validate-task
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
paths:
7+
- ".github/workflows/validate-task.yml"
8+
- "test-cases/task.schema.json"
9+
- "test-cases/**/task.json"
10+
- "test-cases/**/extra_info/**"
11+
push:
12+
branches: [main]
13+
paths:
14+
- ".github/workflows/validate-task.yml"
15+
- "test-cases/task.schema.json"
16+
- "test-cases/**/task.json"
17+
- "test-cases/**/extra_info/**"
18+
workflow_dispatch:
19+
20+
jobs:
21+
validate-task:
22+
runs-on: ubuntu-latest
23+
24+
steps:
25+
- uses: actions/checkout@v6
26+
with:
27+
fetch-depth: 0
28+
29+
- name: Set up Python
30+
uses: actions/setup-python@v6
31+
with:
32+
python-version: "3.11"
33+
34+
- name: Install validator
35+
run: python -m pip install "jsonschema=4.26.0"
36+
37+
- name: Collect changed task files
38+
id: changed
39+
shell: bash
40+
run: |
41+
set -euo pipefail
42+
43+
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
44+
find test-cases -path "*/task.json" -o -path "*/extra_info/*" > changed-files.txt
45+
elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
46+
base="${{ github.event.pull_request.base.sha }}"
47+
git diff --name-only "$base"...HEAD > changed-files.txt
48+
elif [[ "${{ github.event_name }}" == "push" && "${{ github.event.before }}" != "0000000000000000000000000000000000000000" ]]; then
49+
git diff --name-only "${{ github.event.before }}" "${{ github.sha }}" > changed-files.txt
50+
else
51+
find test-cases -path "*/task.json" -o -path "*/extra_info/*" > changed-files.txt
52+
fi
53+
54+
echo "Changed files:"
55+
cat changed-files.txt
56+
57+
- name: Validate changed tasks
58+
run: |
59+
python - <<'PY'
60+
import json
61+
import sys
62+
from pathlib import Path
63+
64+
from jsonschema import Draft202012Validator
65+
66+
repo = Path(".")
67+
schema_path = repo / "test-cases" / "task.schema.json"
68+
changed_paths = [
69+
Path(line.strip())
70+
for line in Path("changed-files.txt").read_text().splitlines()
71+
if line.strip()
72+
]
73+
74+
schema = json.loads(schema_path.read_text())
75+
validator = Draft202012Validator(schema)
76+
77+
validate_all = schema_path in changed_paths
78+
task_files: set[Path] = set()
79+
changed_json_files: set[Path] = set()
80+
81+
if validate_all:
82+
task_files.update(repo.glob("test-cases/**/task.json"))
83+
84+
for path in changed_paths:
85+
if not str(path).startswith("test-cases/"):
86+
continue
87+
if path.name == "task.json" and path.exists():
88+
task_files.add(path)
89+
changed_json_files.add(path)
90+
continue
91+
if "extra_info" in path.parts:
92+
extra_index = path.parts.index("extra_info")
93+
task_dir = Path(*path.parts[:extra_index])
94+
task_file = task_dir / "task.json"
95+
if task_file.exists():
96+
task_files.add(task_file)
97+
if path.suffix == ".json" and path.exists():
98+
changed_json_files.add(path)
99+
100+
errors: list[str] = []
101+
102+
for json_file in sorted(changed_json_files):
103+
try:
104+
json.loads(json_file.read_text())
105+
except Exception as exc:
106+
errors.append(f"{json_file}: invalid JSON: {exc}")
107+
108+
for task_file in sorted(task_files):
109+
try:
110+
task = json.loads(task_file.read_text())
111+
except Exception as exc:
112+
errors.append(f"{task_file}: invalid JSON: {exc}")
113+
continue
114+
115+
for error in sorted(validator.iter_errors(task), key=lambda item: list(item.path)):
116+
location = "/" + "/".join(str(part) for part in error.path)
117+
errors.append(f"{task_file}{location}: {error.message}")
118+
119+
extra_info = task.get("extra_info") or []
120+
if not isinstance(extra_info, list):
121+
continue
122+
for index, item in enumerate(extra_info):
123+
if not isinstance(item, dict) or not item.get("path"):
124+
continue
125+
extra_path = task_file.parent / item["path"]
126+
if not extra_path.exists():
127+
errors.append(
128+
f"{task_file}: extra_info[{index}].path does not exist: {item['path']}"
129+
)
130+
131+
if errors:
132+
print("Task validation failed:")
133+
for error in errors:
134+
print(f"- {error}")
135+
sys.exit(1)
136+
137+
print(f"Validated {len(task_files)} task file(s) and {len(changed_json_files)} changed JSON file(s).")
138+
PY

0 commit comments

Comments
 (0)