@@ -67,75 +67,64 @@ jobs:
6767 esac
6868 done
6969
70- # pyproject.toml is hand-maintained (see .openapi-generator-ignore), so the
71- # generator no longer stamps the version. Bump the patch version directly,
72- # rewriting the same `^version = "X"` line scripts/release.sh treats as the
73- # source of truth.
74- - name : Bump package patch version in pyproject.toml
75- id : pkg
76- run : |
77- version=$(python3 - <<'PY'
78- import re, pathlib
79- path = pathlib.Path("pyproject.toml")
80- text = path.read_text()
81- m = re.search(r'(?m)^version = "(\d+)\.(\d+)\.(\d+)"', text)
82- if not m:
83- raise SystemExit("could not find a semver version in pyproject.toml")
84- new = f"{int(m[1])}.{int(m[2])}.{int(m[3]) + 1}"
85- text, n = re.subn(r'(?m)^version = "[^"]+"', f'version = "{new}"', text, count=1)
86- if n != 1:
87- raise SystemExit("failed to rewrite version in pyproject.toml")
88- path.write_text(text)
89- print(new)
90- PY
91- )
92- echo "version=$version" >> "$GITHUB_OUTPUT"
93-
94- # check-release.yml gates merges on a `## [x.y.z]` CHANGELOG section
95- # matching the bumped version, so without a seeded entry every regen PR
96- # fails that check. Insert a stub (the spec-change title under ### Changed)
97- # just above the most recent released section; the PR author refines the
98- # wording before merge. Idempotent: skips if a section for this version
99- # already exists.
100- - name : Seed changelog entry
70+ # The version bump is intentionally NOT done here. A regen is just a set of
71+ # changes; which release they ship in (and the bump kind) is decided later
72+ # by scripts/release.sh prepare. Seed the regen notes under [Unreleased] so
73+ # they accumulate there until a release rolls them into a version. This
74+ # avoids minting a dated version section per regen that may never publish.
75+ - name : Seed changelog entry under [Unreleased]
10176 env :
102- VERSION : ${{ steps.pkg.outputs.version }}
10377 TITLE : ${{ inputs.title }}
10478 run : |
105- export CHANGELOG_DATE=$(date -u +%Y-%m-%d)
10679 python3 - <<'PY'
10780 import os, pathlib, re
108- version = os.environ["VERSION"]
109- date = os.environ["CHANGELOG_DATE"]
11081 title = (os.environ.get("TITLE") or "").strip() \
11182 or "Regenerate the client from the updated Hotdata OpenAPI spec"
83+ bullet = f"- {title}"
11284 path = pathlib.Path("CHANGELOG.md")
11385 text = path.read_text()
114- if re.search(rf"^## \[{re.escape(version)}\]", text, re.M):
115- print(f"CHANGELOG already has a [{version}] section; leaving it untouched.")
116- raise SystemExit(0)
117- unreleased = re.search(r"^## \[Unreleased\]", text, re.M)
118- if not unreleased:
86+
87+ heading = re.search(r"^## \[Unreleased\][^\n]*\n", text, re.M)
88+ if not heading:
11989 raise SystemExit("CHANGELOG.md has no '## [Unreleased]' section to anchor the new entry")
120- # Insert before the first released section after [Unreleased] (falling
121- # back to end of file) so any pending entries under [Unreleased] stay
122- # attributed to it rather than being absorbed by the new version.
123- nxt = re.search(r"^## \[", text[unreleased.end():], re.M)
124- insert_at = unreleased.end() + nxt.start() if nxt else len(text)
125- entry = f"## [{version}] - {date}\n\n### Changed\n\n- {title}\n\n"
126- text = text[:insert_at] + entry + text[insert_at:]
127- path.write_text(text)
128- print(f"Inserted CHANGELOG [{version}] section.")
90+
91+ # Scope edits to the [Unreleased] body (up to the next '## [' or EOF).
92+ start = heading.end()
93+ nxt = re.search(r"^## \[", text[start:], re.M)
94+ end = start + nxt.start() if nxt else len(text)
95+ body = text[start:end]
96+
97+ if any(line.strip() == bullet for line in body.splitlines()):
98+ print("CHANGELOG [Unreleased] already lists this entry; leaving it untouched.")
99+ raise SystemExit(0)
100+
101+ changed = re.search(r"^### Changed[ \t]*\n", body, re.M)
102+ if changed:
103+ # Prepend the bullet to the existing ### Changed list.
104+ i = changed.end()
105+ while i < len(body) and body[i] == "\n":
106+ i += 1
107+ body = body[:i] + bullet + "\n" + body[i:]
108+ else:
109+ # No ### Changed yet: open one right under the heading.
110+ body = "\n### Changed\n\n" + bullet + "\n\n" + body.lstrip("\n")
111+
112+ path.write_text(text[:start] + body + text[end:])
113+ print("Added regen entry under CHANGELOG [Unreleased].")
129114 PY
130115
116+ # No packageVersion: pyproject.toml is hand-maintained and the generator
117+ # doesn't stamp it, while __version__ and the SDK version string both read
118+ # from installed package metadata — so the generator's packageVersion never
119+ # reaches committed output.
131120 - name : Generate client
132121 run : |
133122 npx @openapitools/openapi-generator-cli generate \
134123 -i openapi.yaml \
135124 -g python \
136125 -o . \
137126 -t .openapi-generator-templates \
138- --additional-properties=packageName=hotdata,projectName=hotdata,packageVersion=${{ steps.pkg.outputs.version }}, gitUserId=hotdata-dev,gitRepoId=sdk-python \
127+ --additional-properties=packageName=hotdata,projectName=hotdata,gitUserId=hotdata-dev,gitRepoId=sdk-python \
139128 --skip-validate-spec
140129
141130 # pyproject.toml/requirements*.txt are hand-maintained, so the generator no
@@ -300,8 +289,9 @@ jobs:
300289 # on. The PR is the artifact we want, and breakage surfaces on it as red CI:
301290 # integration-tests.yml installs the package (`pip install -e .`) and runs
302291 # pytest, and check-release.yml builds + installs + imports the wheel on
303- # every PR that bumps pyproject.toml/CHANGELOG.md (which every regen PR
304- # does). Auto-merge is gated on those checks, so a broken regen can't merge.
292+ # every PR touching pyproject.toml/CHANGELOG.md (a regen seeds a [Unreleased]
293+ # changelog entry, so it always touches CHANGELOG.md). Auto-merge is gated on
294+ # those checks, so a broken regen can't merge.
305295
306296 - name : Check integration test scenario parity
307297 env :
0 commit comments