Skip to content

Commit 429cb27

Browse files
authored
fix(ci): unblock rust regen by flattening $ref siblings (#41)
* chore(ci): bump openapi-generator to 7.22.0 * fix(ci): flatten $ref siblings so the rust generator can regen
1 parent 40df916 commit 429cb27

3 files changed

Lines changed: 77 additions & 1 deletion

File tree

.github/workflows/regenerate.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,18 @@ jobs:
4242
https://api.github.com/repos/hotdata-dev/www.hotdata.dev/contents/api/openapi.yaml \
4343
-o openapi.yaml
4444
45+
# OpenAPI 3.1 lets a `$ref` carry sibling keywords (e.g. a per-branch
46+
# `description` on a `oneOf` member). That's valid, and the Python/TS
47+
# generators consume it fine, but the Rust backend NPEs on it
48+
# (AbstractRustCodegen.toModelName — reproduced through generator 7.22.0,
49+
# no upstream fix yet). Flatten `$ref`-with-siblings to pure refs in our
50+
# throwaway generation input only; the canonical www spec and the other
51+
# SDKs are untouched. See scripts/normalize-openapi.py.
52+
- name: Normalize spec for the Rust generator
53+
run: |
54+
python3 -c "import yaml" 2>/dev/null || pip3 install --quiet pyyaml
55+
python3 scripts/normalize-openapi.py openapi.yaml
56+
4557
# Targeted clean: delete ONLY generator-owned subtrees. The hand-written
4658
# ergonomic layer (src/lib.rs, src/auth.rs, src/arrow.rs, src/client.rs)
4759
# is preserved here and additionally protected by .openapi-generator-ignore

openapitools.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
33
"spaces": 2,
44
"generator-cli": {
5-
"version": "7.20.0"
5+
"version": "7.22.0"
66
}
77
}

scripts/normalize-openapi.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/usr/bin/env python3
2+
"""Flatten ``$ref``-with-siblings so the openapi-generator Rust backend can run.
3+
4+
OpenAPI 3.1 (JSON Schema 2020-12) lets a ``$ref`` carry sibling keywords — e.g. a
5+
per-branch ``description`` on a ``oneOf`` member. That is valid, and the Python
6+
and TypeScript generators consume it fine, but the Rust generator NPEs in
7+
``AbstractRustCodegen.toModelName`` because it materializes the branch as an
8+
*unnamed* inline schema. (Reproduced on generator 7.20.0 and 7.22.0; the upstream
9+
backend has no fix yet.) The fatal case in our spec is ``JobResult``'s ``oneOf``,
10+
whose four ``$ref`` branches each carry a ``description``.
11+
12+
We don't need those siblings in the generated Rust client — per-branch ``oneOf``
13+
docs don't render in Rust regardless — so for every node that has a ``$ref``
14+
alongside other keys we drop the other keys, leaving a pure ref the generator can
15+
name. This rewrites ONLY the throwaway spec fed to the generator in
16+
``regenerate.yml``; the canonical spec in www.hotdata.dev (and the Python/TS
17+
SDKs) are untouched.
18+
19+
Usage: ``normalize-openapi.py <spec.yaml>`` (edits the file in place).
20+
"""
21+
22+
from __future__ import annotations
23+
24+
import sys
25+
26+
import yaml
27+
28+
29+
def strip_ref_siblings(node: object) -> int:
30+
"""Recursively drop keys that sit alongside a ``$ref``. Returns the count."""
31+
removed = 0
32+
if isinstance(node, dict):
33+
if "$ref" in node and len(node) > 1:
34+
for key in [k for k in node if k != "$ref"]:
35+
del node[key]
36+
removed += 1
37+
for value in list(node.values()):
38+
removed += strip_ref_siblings(value)
39+
elif isinstance(node, list):
40+
for item in node:
41+
removed += strip_ref_siblings(item)
42+
return removed
43+
44+
45+
def main() -> int:
46+
if len(sys.argv) != 2:
47+
print("usage: normalize-openapi.py <spec.yaml>", file=sys.stderr)
48+
return 2
49+
path = sys.argv[1]
50+
51+
with open(path, encoding="utf-8") as handle:
52+
spec = yaml.safe_load(handle)
53+
54+
removed = strip_ref_siblings(spec)
55+
56+
with open(path, "w", encoding="utf-8") as handle:
57+
yaml.safe_dump(spec, handle, sort_keys=False, allow_unicode=True)
58+
59+
print(f"normalize-openapi: stripped {removed} sibling key(s) from $ref nodes in {path}")
60+
return 0
61+
62+
63+
if __name__ == "__main__":
64+
raise SystemExit(main())

0 commit comments

Comments
 (0)