aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/build-changelog.py46
1 files changed, 34 insertions, 12 deletions
diff --git a/scripts/build-changelog.py b/scripts/build-changelog.py
index 1b00a5e..8973761 100644
--- a/scripts/build-changelog.py
+++ b/scripts/build-changelog.py
@@ -275,21 +275,31 @@ def write_page(page):
return len(new)
+PREAMBLE = ('# newOS4 changelog\n\n'
+ 'Generated from git history by `scripts/build-changelog.py` — do not edit by hand '
+ 'between the markers.\n\n')
+# The preamble is emitted EXACTLY once. Before 2026-11-05 it was part of the generated body *and*
+# old[:m.start()] was preserved on top of it, so each run prepended another copy: 44 runs left 44
+# copies of the H1 at the top of the file (and pushed the real first release from line 6 to 179).
+PREAMBLE_RE = re.compile(re.escape('# newOS4 changelog') +
+ r'\n\nGenerated from git history by `scripts/build-changelog\.py` — '
+ r'do not edit by hand between the markers\.\n+')
+
+
def write_md(page, rows):
- """App-side Keep-a-Changelog history; generated region is delimited."""
- out = ['# newOS4 changelog', '',
- 'Generated from git history by `scripts/build-changelog.py` — do not edit by hand '
- 'between the markers.', '', '<!-- generated:start -->', '']
+ """App-side Keep-a-Changelog history; only the region between the markers is generated."""
+ region = ['<!-- generated:start -->', '']
for entry in page['entries']:
- out.append('## %s — %s' % (entry['version'], entry['date']))
- out.append('')
+ region.append('## %s — %s' % (entry['version'], entry['date']))
+ region.append('')
if entry['note']:
- out.extend(['_' + re.sub(r'<[^>]+>', '', entry['note']) + '_', ''])
+ region.extend(['_' + re.sub(r'<[^>]+>', '', entry['note']) + '_', ''])
for item in entry['items']:
- out.append('- ' + re.sub(r'<[^>]+>', '`', item).replace('``', '`').replace('``', '`'))
- out.append('')
- out.extend(['<!-- generated:end -->', ''])
- body = '\n'.join(out)
+ region.append('- ' + re.sub(r'<[^>]+>', '`', item).replace('``', '`').replace('``', '`'))
+ region.append('')
+ region.extend(['<!-- generated:end -->', ''])
+ region_text = '\n'.join(region)
+
if os.path.exists(MD):
with open(MD, encoding='utf-8') as fh:
old = fh.read()
@@ -299,7 +309,19 @@ def write_md(page, rows):
# hand-edit added, and silently dropping it is worse than failing loudly.
raise SystemExit('CHANGELOG.md exists but has no generated:start/end markers - '
'refusing to overwrite it')
- body = old[:m.start()] + body + old[m.end():]
+ head, tail = old[:m.start()], old[m.end():]
+ copies = len(PREAMBLE_RE.findall(head))
+ if copies != 1:
+ rest = PREAMBLE_RE.sub('', head).strip('\n')
+ head = PREAMBLE + (rest + '\n\n' if rest else '')
+ print('changelog: collapsed %d preamble copies in CHANGELOG.md' % copies)
+ body = head + region_text + tail
+ else:
+ body = PREAMBLE + region_text
+ # Guard against the 2026-11-05 regression class: the generated region may appear exactly once.
+ # The old code concatenated the preamble into `body` and kept old[:m.start()] as well, so every
+ # run appended another copy — 44 runs, 44 H1s, and the first release pushed to line 179.
+ assert body.count('<!-- generated:start -->') == 1, 'CHANGELOG.md would contain a duplicated region'
write_atomic(MD, body)
return len(body)