Skip to content

Commit f1dd13b

Browse files
committed
ci: regenerate from the committed spec so the drift check is hermetic
1 parent 19fdb85 commit f1dd13b

2 files changed

Lines changed: 21 additions & 2 deletions

File tree

.github/workflows/ci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,13 @@ jobs:
2626

2727
- run: uv sync --locked --all-extras --dev
2828

29+
# Hermetic: regenerates from the committed spec, so this verifies that the committed
30+
# generated code still reproduces from it, with no network dependency. Refreshing the
31+
# spec itself is the release workflow's job.
2932
- name: Codegen drift check
3033
if: matrix.python == '3.12'
34+
env:
35+
ROXYAPI_SPEC_FILE: specs/openapi.json
3136
run: |
3237
uv run python generate.py
3338
git diff --exit-code -- specs/openapi.json src/roxy_sdk/factory.py \

generate.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"""
88

99
import json
10+
import os
1011
import shutil
1112
import subprocess
1213
import sys
@@ -35,9 +36,22 @@ def _fetch_with_retry(url: str, attempts: int = 5) -> bytes:
3536
raise RuntimeError("unreachable")
3637

3738

38-
def fetch_spec() -> dict:
39+
def _load_raw_spec() -> bytes:
40+
"""Read the spec from disk when ROXYAPI_SPEC_FILE is set, fetch it otherwise.
41+
42+
Reading from a file keeps generation offline and byte-reproducible, which is what the
43+
codegen drift check in CI relies on.
44+
"""
45+
spec_file = os.environ.get("ROXYAPI_SPEC_FILE")
46+
if spec_file:
47+
print(f"Reading OpenAPI spec from {spec_file} (offline, ROXYAPI_SPEC_FILE)")
48+
return Path(spec_file).read_bytes()
3949
print(f"Fetching OpenAPI spec from {SPEC_URL}")
40-
spec = json.loads(_fetch_with_retry(SPEC_URL))
50+
return _fetch_with_retry(SPEC_URL)
51+
52+
53+
def fetch_spec() -> dict:
54+
spec = json.loads(_load_raw_spec())
4155

4256
# Patch server URL to absolute prod URL
4357
if spec.get("servers") and spec["servers"][0].get("url") == "/api/v2":

0 commit comments

Comments
 (0)