docs: generate the site changelog in a site-friendly format#5740
docs: generate the site changelog in a site-friendly format#5740taliesin-ai wants to merge 2 commits into
Conversation
The docs changelog page was a verbatim copy of the working changelog: it opened with a legend, raw /* */ comment blocks rendered as text and an empty [Unreleased] heading, and the Keep-a-Changelog category headers (## Added, ## Fixed, ...) sat at the same level as the version headers, so the page table of contents could not nest them. The release processing now generates the page in a format that works on the site: - changelog.mdx starts with the latest version header; the do-not-edit notice moved into an invisible MDX comment and new releases are inserted below a hidden marker comment instead of '## [Unreleased]' - release.go demotes category headers to '###' when moving UNRELEASED_CHANGELOG.md content into the page, so Starlight nests Added/Changed/Fixed under each version in the table of contents - the whole released history (en + id) is migrated to the same format - validate-changelog.go now moves entries that PRs add directly to the generated page into v3/UNRELEASED_CHANGELOG.md (there is no [Unreleased] section on the page any more), and changelog-v3.yml commits both files and explains the new flow in its PR comment GitHub release notes are unchanged: they are built from the raw UNRELEASED_CHANGELOG.md content as before.
WalkthroughChangelog handling for v3 is reworked to route unreleased entries through ChangesChangelog pipeline rework
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain modules listed in go.work or their selected dependencies" Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Updates the v3 release tooling and docs so the site changelog pages render cleanly (no visible “Unreleased” section, no raw comment junk) and the table of contents nests category headings under each version.
Changes:
- Switch docs changelog generation to insert new releases below a hidden
CHANGELOG-INSERT-MARKERand demote changelog category headings to###for proper ToC nesting. - Extend changelog validation to move misplaced entries from the generated docs page back into
v3/UNRELEASED_CHANGELOG.md, and update workflow messaging/commits accordingly. - Migrate existing English + Indonesian changelog pages to the new marker + heading structure and update contributor guidance.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| v3/UNRELEASED_CHANGELOG.md | Adds an unreleased entry describing the new site-friendly changelog generation. |
| v3/tasks/release/release.go | Introduces insert-marker based site changelog updates and category heading demotion. |
| v3/tasks/release/release_test.go | Updates tests to cover marker-based insertion and formatChangelogForSite. |
| v3/scripts/validate-changelog.go | Reworks validator to relocate entries added to generated changelog back into UNRELEASED. |
| docs/src/content/docs/changelog.mdx | Converts the English site changelog page to the new marker format and heading levels. |
| docs/src/content/docs/id/changelog.mdx | Converts the Indonesian site changelog page to the new marker format and heading levels. |
| CONTRIBUTING.md | Clarifies contributor workflow: don’t edit generated changelog page directly. |
| .github/workflows/changelog-v3.yml | Updates validation invocation, commits both files, and improves PR comment output. |
Comments suppressed due to low confidence (1)
v3/scripts/validate-changelog.go:139
- wasAddedInThisPR uses substring matching (strings.Contains) which can flag and remove a pre-existing changelog line if it happens to be a substring of a newly-added line. Since the workflow writes exact added lines (after stripping '+'), this should use exact trimmed equality to avoid false positives that would delete unrelated released entries.
func wasAddedInThisPR(line string, addedLines []string) bool {
trimmedLine := strings.TrimSpace(line)
for _, addedLine := range addedLines {
trimmedAdded := strings.TrimSpace(addedLine)
if trimmedAdded == trimmedLine {
return true
}
if strings.Contains(trimmedAdded, trimmedLine) && len(trimmedAdded) > 0 {
return true
}
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if strings.HasPrefix(strings.TrimSpace(line), "- ") && wasAddedInThisPR(line, addedLines) { | ||
| section := currentSection | ||
| if section == "" { |
| var ( | ||
| unreleasedChangelogFile = "../../UNRELEASED_CHANGELOG.md" | ||
| changelogFile = "../../../docs/src/content/docs/changelog.mdx" | ||
| ) |
| This file is generated by the release workflow. Changelog entries are | ||
| collected in `v3/UNRELEASED_CHANGELOG.md` and moved here, reformatted | ||
| for the site, when a release is created. |
| cd v3/scripts | ||
| OUTPUT=$(go run validate-changelog.go ../../docs/src/content/docs/changelog.mdx /tmp/pr_added_lines.txt 2>&1) | ||
| OUTPUT=$(go run validate-changelog.go ../../docs/src/content/docs/changelog.mdx /tmp/pr_added_lines.txt ../UNRELEASED_CHANGELOG.md 2>&1) | ||
| echo "$OUTPUT" |
There was a problem hiding this comment.
Actionable comments posted: 6
♻️ Duplicate comments (2)
docs/src/content/docs/id/changelog.mdx (2)
1147-1151: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winTruncated/malformed changelog entry (mirrors English file).
The
v3.0.0-alpha.25entry is missing its leading-marker and reads as a mid-sentence fragment, matching the issue indocs/src/content/docs/changelog.mdxlines 1235-1239.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/src/content/docs/id/changelog.mdx` around lines 1147 - 1151, Fix the malformed v3.0.0-alpha.25 changelog entry in the localized changelog so it matches the intended bullet format instead of a stray sentence fragment. Update the entry under the relevant markdown section in changelog.mdx to include the missing leading list marker and restore the full translated sentence, keeping it consistent with the same release entry in the main changelog. Use the existing v3.0.0-alpha.25 heading and the related list item text as the anchors when editing.
1131-1141: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick winDuplicate
v3.0.0-alpha.29version block (mirrors English file).Same duplicated header/empty-subsections issue as
docs/src/content/docs/changelog.mdxlines 1219-1229.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/src/content/docs/id/changelog.mdx` around lines 1131 - 1141, The changelog section has a duplicated v3.0.0-alpha.29 release block with repeated empty subsections; remove the extra duplicate and keep only one header for that version. Update the localized changelog entry in changelog.mdx so it matches the intended sequence around v3.0.0-alpha.29 and the following v3.0.0-alpha.27 entry, using the version headings and subsection labels as the markers to locate the duplicated block.
🧹 Nitpick comments (2)
docs/src/content/docs/changelog.mdx (1)
1042-1277: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMany empty category headers with no bullets.
Numerous historical version blocks (e.g.
v3.0.0-alpha.78throughalpha.65) carry### Added/### Fixedheaders with no bullet content beneath them. Since the site nests these under the version heading in the ToC, readers will see empty subsection entries. Consider stripping empty category headers during generation (informatChangelogForSite) rather than emitting them verbatim.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/src/content/docs/changelog.mdx` around lines 1042 - 1277, The changelog output includes many empty section headers under version entries, which creates empty ToC subsections. Update formatChangelogForSite to skip emitting category headings like Added/Fixed/Changed/Removed when they have no bullet items beneath them, and ensure the version blocks (such as v3.0.0-alpha.78 through v3.0.0-alpha.65) only include non-empty sections.v3/tasks/release/release_test.go (1)
1086-1110: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider adding a test for the missing-marker error path.
TestFormatChangelogForSitecovers header demotion well, but there's no test exercisingapplyChangelogUpdates's newlen(split) != 2error branch (release.go Lines 729-732) whenchangelogInsertMarkeris absent or duplicated fromchangelogFile. Cheap to add and guards an important failure mode for the new marker-based insertion.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@v3/tasks/release/release_test.go` around lines 1086 - 1110, Add a test that covers the new missing/duplicated marker failure path in applyChangelogUpdates, since TestFormatChangelogForSite only verifies header formatting. Create a case where changelogFile does not contain exactly one changelogInsertMarker so the len(split) != 2 branch is hit, and assert the expected error is returned. Use applyChangelogUpdates and changelogInsertMarker to locate the logic, and keep the test focused on the absent or duplicated marker scenario.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/changelog-v3.yml:
- Around line 178-202: The PR comment text in the changelog workflow is escaping
newlines incorrectly, so the `message` built in the `fixed`/`cannot_fix`/`error`
branch renders literal backslash-ns. Update the string concatenation in the
changelog comment builder to use real newline escapes consistently, matching the
earlier `result === 'fixed'` branch, and ensure the `<details>` block and
markdown fence around `fixedContent` in the `message` variable from the workflow
script render as proper markdown.
In `@docs/src/content/docs/changelog.mdx`:
- Around line 1246-1251: The changelog entry is using the wrong list marker and
is categorized under the wrong section. Update the v3.0.0-alpha.22 entry in the
changelog so the “Fix extra-broad Linux package dependencies, fix outdated RPM
dependencies.” item uses the same bullet style as the rest of the file and move
it from the “Changed” section to the “Fixed” section to match its bug-fix
wording.
- Around line 1219-1229: The changelog has a duplicated v3.0.0-alpha.29 block in
the sequence around the alpha.29 entry, so remove the repeated entry and keep
only one occurrence. Update the changelog content in changelog.mdx by collapsing
the duplicate release section into a single v3.0.0-alpha.29 entry, preserving
the surrounding version order and headings.
- Around line 1235-1239: The v3.0.0-alpha.25 changelog entry is truncated and
missing its bullet formatting, so restore the full bullet text in the changelog
section. Update the affected markdown entry in changelog.mdx so the item is a
properly formatted list bullet and the sentence reads as a complete changelog
note, using the existing version heading and surrounding release note style as
the guide.
In `@docs/src/content/docs/id/changelog.mdx`:
- Around line 1158-1163: The changelog entry has a stray plus marker and is
under the wrong section; update the v3.0.0-alpha.22 item in the Indonesian
changelog so the fix line uses the normal bullet marker and appears under ###
Diperbaiki instead of ### Diubah. Make the same content correction consistently
with the corresponding changelog entry elsewhere, using the surrounding section
headers in changelog.mdx to locate the entry.
In `@v3/scripts/validate-changelog.go`:
- Around line 143-196: attemptFix currently makes a non-atomic change by writing
changelogPath after removing issue lines and only then writing unreleasedPath,
so a failure in the second write can lose entries. Update attemptFix to persist
the UNRELEASED_CHANGELOG.md changes first, then write the cleaned changelog
content only after that succeeds, using the existing helpers writeFile,
readFile, and the category insertion logic around
changelogCategories/findCategoryInsertPos.
---
Duplicate comments:
In `@docs/src/content/docs/id/changelog.mdx`:
- Around line 1147-1151: Fix the malformed v3.0.0-alpha.25 changelog entry in
the localized changelog so it matches the intended bullet format instead of a
stray sentence fragment. Update the entry under the relevant markdown section in
changelog.mdx to include the missing leading list marker and restore the full
translated sentence, keeping it consistent with the same release entry in the
main changelog. Use the existing v3.0.0-alpha.25 heading and the related list
item text as the anchors when editing.
- Around line 1131-1141: The changelog section has a duplicated v3.0.0-alpha.29
release block with repeated empty subsections; remove the extra duplicate and
keep only one header for that version. Update the localized changelog entry in
changelog.mdx so it matches the intended sequence around v3.0.0-alpha.29 and the
following v3.0.0-alpha.27 entry, using the version headings and subsection
labels as the markers to locate the duplicated block.
---
Nitpick comments:
In `@docs/src/content/docs/changelog.mdx`:
- Around line 1042-1277: The changelog output includes many empty section
headers under version entries, which creates empty ToC subsections. Update
formatChangelogForSite to skip emitting category headings like
Added/Fixed/Changed/Removed when they have no bullet items beneath them, and
ensure the version blocks (such as v3.0.0-alpha.78 through v3.0.0-alpha.65) only
include non-empty sections.
In `@v3/tasks/release/release_test.go`:
- Around line 1086-1110: Add a test that covers the new missing/duplicated
marker failure path in applyChangelogUpdates, since TestFormatChangelogForSite
only verifies header formatting. Create a case where changelogFile does not
contain exactly one changelogInsertMarker so the len(split) != 2 branch is hit,
and assert the expected error is returned. Use applyChangelogUpdates and
changelogInsertMarker to locate the logic, and keep the test focused on the
absent or duplicated marker scenario.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9b99f192-5f41-4dac-85be-18b0526ccfa6
📒 Files selected for processing (8)
.github/workflows/changelog-v3.ymlCONTRIBUTING.mddocs/src/content/docs/changelog.mdxdocs/src/content/docs/id/changelog.mdxv3/UNRELEASED_CHANGELOG.mdv3/scripts/validate-changelog.gov3/tasks/release/release.gov3/tasks/release/release_test.go
| message = '## 🔧 Changelog Updated\n\nMisplaced entries were automatically moved to `v3/UNRELEASED_CHANGELOG.md`. The changes have been committed to this PR.'; | ||
| } else if (result === 'fixed' || result === 'cannot_fix' || result === 'error') { | ||
| // Read the fixed changelog content | ||
| // Read the fixed unreleased changelog content | ||
| const fs = require('fs'); | ||
| let fixedContent = ''; | ||
| try { | ||
| fixedContent = fs.readFileSync('docs/src/content/docs/changelog.mdx', 'utf8'); | ||
| fixedContent = fs.readFileSync('v3/UNRELEASED_CHANGELOG.md', 'utf8'); | ||
| } catch (error) { | ||
| fixedContent = 'Error reading fixed changelog content'; | ||
| } | ||
|
|
||
| message = '## ⚠️ Changelog Validation Issue\\n\\n' + | ||
| '@' + author + ' Your PR contains changelog entries that were added to already-released versions. These need to be moved to the `[Unreleased]` section.\\n\\n' + | ||
| (committed === 'true' ? | ||
| '✅ **Auto-fix applied**: The changes have been automatically committed to this PR.' : | ||
| '❌ **Manual fix required**: Please apply the changes shown below manually.') + '\\n\\n' + | ||
| '@' + author + ' Your PR adds changelog entries to `docs/src/content/docs/changelog.mdx`. That file is generated by the release workflow and only contains released versions, so entries added there directly would be lost. New entries belong in `v3/UNRELEASED_CHANGELOG.md`.\\n\\n' + | ||
| (committed === 'true' ? | ||
| '✅ **Auto-fix applied**: The entries have been moved to `v3/UNRELEASED_CHANGELOG.md` and committed to this PR.' : | ||
| '❌ **Manual fix required**: Please move your entries to `v3/UNRELEASED_CHANGELOG.md` as shown below.') + '\\n\\n' + | ||
| '<details>\\n' + | ||
| '<summary>📝 Click to see the corrected changelog content</summary>\\n\\n' + | ||
| '```mdx\\n' + | ||
| '<summary>📝 Click to see the corrected v3/UNRELEASED_CHANGELOG.md content</summary>\\n\\n' + | ||
| '```md\\n' + | ||
| fixedContent + | ||
| '\\n```\\n\\n' + | ||
| '</details>\\n\\n' + | ||
| '**What happened?** \\n' + | ||
| 'The validation script detected that you added changelog entries to a version section that has already been released (like `v3.0.0-alpha.10`). All new entries should go in the `[Unreleased]` section under the appropriate category (`### Added`, `### Fixed`, etc.).\\n\\n' + | ||
| (committed !== 'true' ? '**Action needed:** Please copy the corrected content from above and replace your changelog file.' : ''); | ||
| 'The validation script detected changelog entries added directly to the generated changelog page. All new entries should go in `v3/UNRELEASED_CHANGELOG.md` under the appropriate category (`## Added`, `## Fixed`, etc.); they are moved to the site changelog automatically when a release is created.\\n\\n' + | ||
| (committed !== 'true' ? '**Action needed:** Please remove the entries from `docs/src/content/docs/changelog.mdx` and add them to `v3/UNRELEASED_CHANGELOG.md` as shown above.' : ''); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Literal \n will leak into the PR comment instead of newlines/code fences.
The fixed/cannot_fix/error branch (lines 189-202) uses \\n\\n (double backslash) throughout, while the fixed && committed branch at line 178 correctly uses \n\n (single backslash). In a JS string literal, \\n produces the literal two characters \ and n, not a newline. This breaks the intended formatting of the comment body, including the markdown code fence around the changelog snippet (```md\\n ... \\n```\\n\\n), which will render as garbled text with visible backslash-n sequences instead of a proper collapsible code block.
🛠️ Proposed fix
- message = '## ⚠️ Changelog Validation Issue\\n\\n' +
- '@' + author + ' Your PR adds changelog entries to `docs/src/content/docs/changelog.mdx`. That file is generated by the release workflow and only contains released versions, so entries added there directly would be lost. New entries belong in `v3/UNRELEASED_CHANGELOG.md`.\\n\\n' +
- (committed === 'true' ?
- '✅ **Auto-fix applied**: The entries have been moved to `v3/UNRELEASED_CHANGELOG.md` and committed to this PR.' :
- '❌ **Manual fix required**: Please move your entries to `v3/UNRELEASED_CHANGELOG.md` as shown below.') + '\\n\\n' +
- '<details>\\n' +
- '<summary>📝 Click to see the corrected v3/UNRELEASED_CHANGELOG.md content</summary>\\n\\n' +
- '```md\\n' +
- fixedContent +
- '\\n```\\n\\n' +
- '</details>\\n\\n' +
- '**What happened?** \\n' +
- 'The validation script detected changelog entries added directly to the generated changelog page. All new entries should go in `v3/UNRELEASED_CHANGELOG.md` under the appropriate category (`## Added`, `## Fixed`, etc.); they are moved to the site changelog automatically when a release is created.\\n\\n' +
- (committed !== 'true' ? '**Action needed:** Please remove the entries from `docs/src/content/docs/changelog.mdx` and add them to `v3/UNRELEASED_CHANGELOG.md` as shown above.' : '');
+ message = '## ⚠️ Changelog Validation Issue\n\n' +
+ '@' + author + ' Your PR adds changelog entries to `docs/src/content/docs/changelog.mdx`. That file is generated by the release workflow and only contains released versions, so entries added there directly would be lost. New entries belong in `v3/UNRELEASED_CHANGELOG.md`.\n\n' +
+ (committed === 'true' ?
+ '✅ **Auto-fix applied**: The entries have been moved to `v3/UNRELEASED_CHANGELOG.md` and committed to this PR.' :
+ '❌ **Manual fix required**: Please move your entries to `v3/UNRELEASED_CHANGELOG.md` as shown below.') + '\n\n' +
+ '<details>\n' +
+ '<summary>📝 Click to see the corrected v3/UNRELEASED_CHANGELOG.md content</summary>\n\n' +
+ '```md\n' +
+ fixedContent +
+ '\n```\n\n' +
+ '</details>\n\n' +
+ '**What happened?** \n' +
+ 'The validation script detected changelog entries added directly to the generated changelog page. All new entries should go in `v3/UNRELEASED_CHANGELOG.md` under the appropriate category (`## Added`, `## Fixed`, etc.); they are moved to the site changelog automatically when a release is created.\n\n' +
+ (committed !== 'true' ? '**Action needed:** Please remove the entries from `docs/src/content/docs/changelog.mdx` and add them to `v3/UNRELEASED_CHANGELOG.md` as shown above.' : '');🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/changelog-v3.yml around lines 178 - 202, The PR comment
text in the changelog workflow is escaping newlines incorrectly, so the
`message` built in the `fixed`/`cannot_fix`/`error` branch renders literal
backslash-ns. Update the string concatenation in the changelog comment builder
to use real newline escapes consistently, matching the earlier `result ===
'fixed'` branch, and ensure the `<details>` block and markdown fence around
`fixedContent` in the `message` variable from the workflow script render as
proper markdown.
| ## v3.0.0-alpha.29 - 2025-09-25 | ||
|
|
||
| ## Added | ||
|
|
||
| ## Changed | ||
|
|
||
| ## Fixed | ||
|
|
||
| ### Added | ||
| ### Changed | ||
| ### Fixed | ||
| ## v3.0.0-alpha.29 - 2025-09-25 | ||
|
|
||
| ## Added | ||
|
|
||
| ## Changed | ||
|
|
||
| ## Fixed | ||
|
|
||
| ### Added | ||
| ### Changed | ||
| ### Fixed | ||
| ## v3.0.0-alpha.27 - 2025-09-07 |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="docs/src/content/docs/changelog.mdx"
# Show the relevant section with line numbers.
sed -n '1200,1240p' "$file" | cat -n
echo
echo "---- exact occurrences of the alpha.29 header ----"
grep -nF '## v3.0.0-alpha.29 - 2025-09-25' "$file" || true
echo
echo "---- nearby context around each occurrence ----"
python3 - <<'PY'
from pathlib import Path
path = Path("docs/src/content/docs/changelog.mdx")
lines = path.read_text().splitlines()
needle = "## v3.0.0-alpha.29 - 2025-09-25"
for i, line in enumerate(lines, 1):
if line == needle:
print(f"\n=== occurrence at line {i} ===")
for j in range(max(1, i-2), min(len(lines), i+8)+1):
print(f"{j:5d}: {lines[j-1]}")
PYRepository: wailsapp/wails
Length of output: 1741
Remove the duplicate v3.0.0-alpha.29 entry
docs/src/content/docs/changelog.mdx repeats the same v3.0.0-alpha.29 - 2025-09-25 block twice in a row; collapse it to a single changelog entry.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/src/content/docs/changelog.mdx` around lines 1219 - 1229, The changelog
has a duplicated v3.0.0-alpha.29 block in the sequence around the alpha.29
entry, so remove the repeated entry and keep only one occurrence. Update the
changelog content in changelog.mdx by collapsing the duplicate release section
into a single v3.0.0-alpha.29 entry, preserving the surrounding version order
and headings.
| ## v3.0.0-alpha.25 - 2025-08-16 | ||
|
|
||
| ## Changed | ||
| ### Changed | ||
| no longer ignored, and override the config value. | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Look for the original/full text of this entry in git history or UNRELEASED_CHANGELOG history
rg -n "no longer ignored, and override the config value" -C5Repository: wailsapp/wails
Length of output: 152
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the exact changelog section around the cited lines.
sed -n '1228,1245p' docs/src/content/docs/changelog.mdx
# Search for nearby wording and the same release heading elsewhere in the repo.
rg -n "v3\.0\.0-alpha\.25|no longer ignored|override the config value" docs src -C 3
# If git history is available, look for the same release entry in prior versions of this file.
git log --oneline -- docs/src/content/docs/changelog.mdx | head -n 20Repository: wailsapp/wails
Length of output: 1682
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show the exact local context with line numbers.
sed -n '1230,1241p' docs/src/content/docs/changelog.mdx | cat -n
# Check the same release block in the Indonesian changelog for parity.
sed -n '1144,1153p' docs/src/content/docs/id/changelog.mdx | cat -n
# Search for any fuller version of the fragment in the repository.
rg -n "no longer ignored, and override the config value|ignored, and override the config value|override the config value" docs -C 2Repository: wailsapp/wails
Length of output: 1293
Restore the missing changelog bullet text. The v3.0.0-alpha.25 entry is truncated here: the bullet marker is missing and the sentence starts mid-thought.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/src/content/docs/changelog.mdx` around lines 1235 - 1239, The
v3.0.0-alpha.25 changelog entry is truncated and missing its bullet formatting,
so restore the full bullet text in the changelog section. Update the affected
markdown entry in changelog.mdx so the item is a properly formatted list bullet
and the sentence reads as a complete changelog note, using the existing version
heading and surrounding release note style as the guide.
| ## v3.0.0-alpha.22 - 2025-08-10 | ||
|
|
||
| ## Added | ||
|
|
||
| ## Changed | ||
| ### Added | ||
| ### Changed | ||
| + Fix extra-broad Linux package dependencies, fix outdated RPM dependencies. | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Stray + bullet marker and miscategorized entry.
Line 1250 uses + instead of - (the marker used everywhere else in the file), and the entry text ("Fix extra-broad Linux package dependencies, fix outdated RPM dependencies.") describes a bug fix but is placed under ### Changed rather than ### Fixed.
🐛 Proposed fix
### Added
-### Changed
-+ Fix extra-broad Linux package dependencies, fix outdated RPM dependencies.
+### Changed
+
+### Fixed
+- Fix extra-broad Linux package dependencies, fix outdated RPM dependencies.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ## v3.0.0-alpha.22 - 2025-08-10 | |
| ## Added | |
| ## Changed | |
| ### Added | |
| ### Changed | |
| + Fix extra-broad Linux package dependencies, fix outdated RPM dependencies. | |
| ## v3.0.0-alpha.22 - 2025-08-10 | |
| ### Added | |
| ### Changed | |
| ### Fixed | |
| - Fix extra-broad Linux package dependencies, fix outdated RPM dependencies. |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/src/content/docs/changelog.mdx` around lines 1246 - 1251, The changelog
entry is using the wrong list marker and is categorized under the wrong section.
Update the v3.0.0-alpha.22 entry in the changelog so the “Fix extra-broad Linux
package dependencies, fix outdated RPM dependencies.” item uses the same bullet
style as the rest of the file and move it from the “Changed” section to the
“Fixed” section to match its bug-fix wording.
| ## v3.0.0-alpha.22 - 2025-08-10 | ||
|
|
||
| ## Ditambahkan | ||
|
|
||
| ## Diubah | ||
| ### Ditambahkan | ||
| ### Diubah | ||
| + Fix extra-broad Linux package dependencies, fix outdated RPM dependencies. | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Stray + bullet marker and miscategorized entry (mirrors English file).
Line 1162 uses + instead of -, and the fix-related entry is placed under ### Diubah (Changed) instead of ### Diperbaiki (Fixed). Same content defect as docs/src/content/docs/changelog.mdx lines 1246-1251 — fix in both places consistently.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/src/content/docs/id/changelog.mdx` around lines 1158 - 1163, The
changelog entry has a stray plus marker and is under the wrong section; update
the v3.0.0-alpha.22 item in the Indonesian changelog so the fix line uses the
normal bullet marker and appears under ### Diperbaiki instead of ### Diubah.
Make the same content correction consistently with the corresponding changelog
entry elsewhere, using the surrounding section headers in changelog.mdx to
locate the entry.
| // attemptFix removes the misplaced entries from the generated changelog and | ||
| // inserts them into the matching category sections of UNRELEASED_CHANGELOG.md. | ||
| func attemptFix(content string, issues []Issue, changelogPath, unreleasedPath string) (bool, error) { | ||
| lines := strings.Split(content, "\n") | ||
|
|
||
| // Find unreleased section | ||
| unreleasedStart := -1 | ||
| unreleasedEnd := -1 | ||
|
|
||
| for i, line := range lines { | ||
| if strings.Contains(line, "[Unreleased]") { | ||
| unreleasedStart = i | ||
| for j := i + 1; j < len(lines); j++ { | ||
| if strings.HasPrefix(lines[j], "## ") && !strings.Contains(lines[j], "[Unreleased]") { | ||
| unreleasedEnd = j | ||
| break | ||
| } | ||
| } | ||
| break | ||
| } | ||
| } | ||
|
|
||
| if unreleasedStart == -1 { | ||
| return false, fmt.Errorf("Could not find [Unreleased] section") | ||
| } | ||
|
|
||
| // Group issues by category | ||
| issuesByCategory := make(map[string][]Issue) | ||
| for _, issue := range issues { | ||
| issuesByCategory[issue.Category] = append(issuesByCategory[issue.Category], issue) | ||
| } | ||
|
|
||
| // Remove issues from original locations (in reverse order) | ||
| var linesToRemove []int | ||
| // Remove issue lines from the changelog (highest line number first) | ||
| linesToRemove := make([]int, 0, len(issues)) | ||
| for _, issue := range issues { | ||
| linesToRemove = append(linesToRemove, issue.Line) | ||
| } | ||
|
|
||
| // Sort in reverse order | ||
| for i := 0; i < len(linesToRemove); i++ { | ||
| for j := i + 1; j < len(linesToRemove); j++ { | ||
| if linesToRemove[i] < linesToRemove[j] { | ||
| linesToRemove[i], linesToRemove[j] = linesToRemove[j], linesToRemove[i] | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Remove lines | ||
| for _, lineNum := range linesToRemove { | ||
| lines = append(lines[:lineNum], lines[lineNum+1:]...) | ||
| } | ||
|
|
||
| // Add entries to unreleased section | ||
| for category, categoryIssues := range issuesByCategory { | ||
| categoryFound := false | ||
| insertPos := unreleasedStart + 1 | ||
|
|
||
| for i := unreleasedStart + 1; i < unreleasedEnd && i < len(lines); i++ { | ||
| if strings.Contains(lines[i], "### "+category) || strings.Contains(lines[i], "## "+category) { | ||
| categoryFound = true | ||
| for j := i + 1; j < unreleasedEnd && j < len(lines); j++ { | ||
| if strings.HasPrefix(lines[j], "### ") || strings.HasPrefix(lines[j], "## ") { | ||
| insertPos = j | ||
| break | ||
| } | ||
| if j == len(lines)-1 || j == unreleasedEnd-1 { | ||
| insertPos = j + 1 | ||
| break | ||
| } | ||
| } | ||
| break | ||
| } | ||
| } | ||
| // Insert the entries into UNRELEASED_CHANGELOG.md | ||
| unreleasedContent, err := readFile(unreleasedPath) | ||
| if err != nil { | ||
| return false, fmt.Errorf("failed to read %s: %w", unreleasedPath, err) | ||
| } | ||
| unreleasedLines := strings.Split(unreleasedContent, "\n") | ||
|
|
||
| if !categoryFound { | ||
| if unreleasedEnd > 0 { | ||
| insertPos = unreleasedEnd | ||
| } else { | ||
| insertPos = unreleasedStart + 1 | ||
| } | ||
| issuesByCategory := make(map[string][]Issue) | ||
| for _, issue := range issues { | ||
| issuesByCategory[issue.Category] = append(issuesByCategory[issue.Category], issue) | ||
| } | ||
|
|
||
| newLines := []string{ | ||
| "", | ||
| "### " + category, | ||
| "", | ||
| } | ||
| lines = append(lines[:insertPos], append(newLines, lines[insertPos:]...)...) | ||
| insertPos += len(newLines) | ||
| unreleasedEnd += len(newLines) | ||
| // Iterate categories in a stable order | ||
| for _, category := range changelogCategories { | ||
| categoryIssues := issuesByCategory[category] | ||
| if len(categoryIssues) == 0 { | ||
| continue | ||
| } | ||
| insertPos := findCategoryInsertPos(unreleasedLines, category) | ||
| if insertPos == -1 { | ||
| return false, fmt.Errorf("could not find '## %s' section in %s", category, unreleasedPath) | ||
| } | ||
|
|
||
| // Add entries to the category | ||
| for _, issue := range categoryIssues { | ||
| lines = append(lines[:insertPos], append([]string{issue.Content}, lines[insertPos:]...)...) | ||
| unreleasedLines = append(unreleasedLines[:insertPos], append([]string{issue.Content}, unreleasedLines[insertPos:]...)...) | ||
| insertPos++ | ||
| unreleasedEnd++ | ||
| } | ||
| } | ||
|
|
||
| // Write back to file | ||
| newContent := strings.Join(lines, "\n") | ||
| return true, writeFile(outputPath, newContent) | ||
| if err := writeFile(changelogPath, strings.Join(lines, "\n")); err != nil { | ||
| return false, err | ||
| } | ||
| return true, writeFile(unreleasedPath, strings.Join(unreleasedLines, "\n")) | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win
Non-atomic writes risk permanently losing changelog entries.
attemptFix writes changelogPath (with the misplaced lines already removed) before writing unreleasedPath (with those same lines inserted). If the second writeFile call fails for any reason (permissions, disk full, path issue), the entries have already been stripped from changelog.mdx on disk but were never persisted to UNRELEASED_CHANGELOG.md — they're gone. Since main exits on this error path regardless of the returned fixed bool, there's no recovery.
Writing the destination file first (and only then removing content from the source) makes the failure mode "duplicated entry" instead of "lost entry."
🛡️ Proposed fix: write unreleasedPath before changelogPath
- if err := writeFile(changelogPath, strings.Join(lines, "\n")); err != nil {
- return false, err
- }
- return true, writeFile(unreleasedPath, strings.Join(unreleasedLines, "\n"))
+ // Write the destination first: if this fails, changelog.mdx is left
+ // untouched and no entries are lost. Writing changelog.mdx first would
+ // risk permanently losing entries if this write then failed.
+ if err := writeFile(unreleasedPath, strings.Join(unreleasedLines, "\n")); err != nil {
+ return false, err
+ }
+ return true, writeFile(changelogPath, strings.Join(lines, "\n"))📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // attemptFix removes the misplaced entries from the generated changelog and | |
| // inserts them into the matching category sections of UNRELEASED_CHANGELOG.md. | |
| func attemptFix(content string, issues []Issue, changelogPath, unreleasedPath string) (bool, error) { | |
| lines := strings.Split(content, "\n") | |
| // Find unreleased section | |
| unreleasedStart := -1 | |
| unreleasedEnd := -1 | |
| for i, line := range lines { | |
| if strings.Contains(line, "[Unreleased]") { | |
| unreleasedStart = i | |
| for j := i + 1; j < len(lines); j++ { | |
| if strings.HasPrefix(lines[j], "## ") && !strings.Contains(lines[j], "[Unreleased]") { | |
| unreleasedEnd = j | |
| break | |
| } | |
| } | |
| break | |
| } | |
| } | |
| if unreleasedStart == -1 { | |
| return false, fmt.Errorf("Could not find [Unreleased] section") | |
| } | |
| // Group issues by category | |
| issuesByCategory := make(map[string][]Issue) | |
| for _, issue := range issues { | |
| issuesByCategory[issue.Category] = append(issuesByCategory[issue.Category], issue) | |
| } | |
| // Remove issues from original locations (in reverse order) | |
| var linesToRemove []int | |
| // Remove issue lines from the changelog (highest line number first) | |
| linesToRemove := make([]int, 0, len(issues)) | |
| for _, issue := range issues { | |
| linesToRemove = append(linesToRemove, issue.Line) | |
| } | |
| // Sort in reverse order | |
| for i := 0; i < len(linesToRemove); i++ { | |
| for j := i + 1; j < len(linesToRemove); j++ { | |
| if linesToRemove[i] < linesToRemove[j] { | |
| linesToRemove[i], linesToRemove[j] = linesToRemove[j], linesToRemove[i] | |
| } | |
| } | |
| } | |
| // Remove lines | |
| for _, lineNum := range linesToRemove { | |
| lines = append(lines[:lineNum], lines[lineNum+1:]...) | |
| } | |
| // Add entries to unreleased section | |
| for category, categoryIssues := range issuesByCategory { | |
| categoryFound := false | |
| insertPos := unreleasedStart + 1 | |
| for i := unreleasedStart + 1; i < unreleasedEnd && i < len(lines); i++ { | |
| if strings.Contains(lines[i], "### "+category) || strings.Contains(lines[i], "## "+category) { | |
| categoryFound = true | |
| for j := i + 1; j < unreleasedEnd && j < len(lines); j++ { | |
| if strings.HasPrefix(lines[j], "### ") || strings.HasPrefix(lines[j], "## ") { | |
| insertPos = j | |
| break | |
| } | |
| if j == len(lines)-1 || j == unreleasedEnd-1 { | |
| insertPos = j + 1 | |
| break | |
| } | |
| } | |
| break | |
| } | |
| } | |
| // Insert the entries into UNRELEASED_CHANGELOG.md | |
| unreleasedContent, err := readFile(unreleasedPath) | |
| if err != nil { | |
| return false, fmt.Errorf("failed to read %s: %w", unreleasedPath, err) | |
| } | |
| unreleasedLines := strings.Split(unreleasedContent, "\n") | |
| if !categoryFound { | |
| if unreleasedEnd > 0 { | |
| insertPos = unreleasedEnd | |
| } else { | |
| insertPos = unreleasedStart + 1 | |
| } | |
| issuesByCategory := make(map[string][]Issue) | |
| for _, issue := range issues { | |
| issuesByCategory[issue.Category] = append(issuesByCategory[issue.Category], issue) | |
| } | |
| newLines := []string{ | |
| "", | |
| "### " + category, | |
| "", | |
| } | |
| lines = append(lines[:insertPos], append(newLines, lines[insertPos:]...)...) | |
| insertPos += len(newLines) | |
| unreleasedEnd += len(newLines) | |
| // Iterate categories in a stable order | |
| for _, category := range changelogCategories { | |
| categoryIssues := issuesByCategory[category] | |
| if len(categoryIssues) == 0 { | |
| continue | |
| } | |
| insertPos := findCategoryInsertPos(unreleasedLines, category) | |
| if insertPos == -1 { | |
| return false, fmt.Errorf("could not find '## %s' section in %s", category, unreleasedPath) | |
| } | |
| // Add entries to the category | |
| for _, issue := range categoryIssues { | |
| lines = append(lines[:insertPos], append([]string{issue.Content}, lines[insertPos:]...)...) | |
| unreleasedLines = append(unreleasedLines[:insertPos], append([]string{issue.Content}, unreleasedLines[insertPos:]...)...) | |
| insertPos++ | |
| unreleasedEnd++ | |
| } | |
| } | |
| // Write back to file | |
| newContent := strings.Join(lines, "\n") | |
| return true, writeFile(outputPath, newContent) | |
| if err := writeFile(changelogPath, strings.Join(lines, "\n")); err != nil { | |
| return false, err | |
| } | |
| return true, writeFile(unreleasedPath, strings.Join(unreleasedLines, "\n")) | |
| } | |
| // attemptFix removes the misplaced entries from the generated changelog and | |
| // inserts them into the matching category sections of UNRELEASED_CHANGELOG.md. | |
| func attemptFix(content string, issues []Issue, changelogPath, unreleasedPath string) (bool, error) { | |
| lines := strings.Split(content, "\n") | |
| // Remove issue lines from the changelog (highest line number first) | |
| linesToRemove := make([]int, 0, len(issues)) | |
| for _, issue := range issues { | |
| linesToRemove = append(linesToRemove, issue.Line) | |
| } | |
| for i := 0; i < len(linesToRemove); i++ { | |
| for j := i + 1; j < len(linesToRemove); j++ { | |
| if linesToRemove[i] < linesToRemove[j] { | |
| linesToRemove[i], linesToRemove[j] = linesToRemove[j], linesToRemove[i] | |
| } | |
| } | |
| } | |
| for _, lineNum := range linesToRemove { | |
| lines = append(lines[:lineNum], lines[lineNum+1:]...) | |
| } | |
| // Insert the entries into UNRELEASED_CHANGELOG.md | |
| unreleasedContent, err := readFile(unreleasedPath) | |
| if err != nil { | |
| return false, fmt.Errorf("failed to read %s: %w", unreleasedPath, err) | |
| } | |
| unreleasedLines := strings.Split(unreleasedContent, "\n") | |
| issuesByCategory := make(map[string][]Issue) | |
| for _, issue := range issues { | |
| issuesByCategory[issue.Category] = append(issuesByCategory[issue.Category], issue) | |
| } | |
| // Iterate categories in a stable order | |
| for _, category := range changelogCategories { | |
| categoryIssues := issuesByCategory[category] | |
| if len(categoryIssues) == 0 { | |
| continue | |
| } | |
| insertPos := findCategoryInsertPos(unreleasedLines, category) | |
| if insertPos == -1 { | |
| return false, fmt.Errorf("could not find '## %s' section in %s", category, unreleasedPath) | |
| } | |
| for _, issue := range categoryIssues { | |
| unreleasedLines = append(unreleasedLines[:insertPos], append([]string{issue.Content}, unreleasedLines[insertPos:]...)...) | |
| insertPos++ | |
| } | |
| } | |
| // Write the destination first: if this fails, changelog.mdx is left | |
| // untouched and no entries are lost. Writing changelog.mdx first would | |
| // risk permanently losing entries if this write then failed. | |
| if err := writeFile(unreleasedPath, strings.Join(unreleasedLines, "\n")); err != nil { | |
| return false, err | |
| } | |
| return true, writeFile(changelogPath, strings.Join(lines, "\n")) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@v3/scripts/validate-changelog.go` around lines 143 - 196, attemptFix
currently makes a non-atomic change by writing changelogPath after removing
issue lines and only then writing unreleasedPath, so a failure in the second
write can lose entries. Update attemptFix to persist the UNRELEASED_CHANGELOG.md
changes first, then write the cleaned changelog content only after that
succeeds, using the existing helpers writeFile, readFile, and the category
insertion logic around changelogCategories/findCategoryInsertPos.
Description
The changelog page at https://v3.wails.io/changelog/ was a verbatim copy of the working changelog file: it opened with a legend, raw
/* */comment blocks rendered as literal text and an empty[Unreleased]heading, and the Keep-a-Changelog category headers (## Added,## Fixed, ...) sat at the same heading level as the version headers, so the page's table of contents could not nest them.This extends the UNRELEASED_CHANGELOG processing so the site file is generated in a format that works on the site:
v3.0.0-alpha2.112 - 2026-07-03). The do-not-edit notice moved into an invisible MDX comment, and new releases are inserted below a hiddenCHANGELOG-INSERT-MARKERcomment instead of a visible## [Unreleased]heading. The emoji legend is now a single sentence instead of a bullet list.release.godemotes category headers to###when movingUNRELEASED_CHANGELOG.mdcontent into the page, so Starlight nests Added/Changed/Fixed under each version. The entire released history (English + Indonesian pages) is migrated to the same format.validate-changelog.gonow moves entries that PRs add directly to the generated page intov3/UNRELEASED_CHANGELOG.md(there is no[Unreleased]section on the page any more).changelog-v3.ymlcommits both files and its PR comment explains the new flow, showing the correctedUNRELEASED_CHANGELOG.mdinstead of pasting the whole 1600-line changelog.UNRELEASED_CHANGELOG.mdcontent.Contributor flow is unchanged: entries go in
v3/UNRELEASED_CHANGELOG.md(or are auto-added on merge), and the nightly release moves them to the site page.Verification
go test ./v3/tasks/release/passes, including a new test that runsapplyChangelogUpdatesend-to-end against the marker format and aformatChangelogForSiteunit test.### Added/### Fixed; both were removed fromchangelog.mdxand inserted into the matching## Added/## Fixedsections ofUNRELEASED_CHANGELOG.md(VALIDATION_RESULT=fixed).astro buildof the docs passes. The built page has no rendered comment junk, the first content heading isv3.0.0-alpha2.112 - 2026-07-03, and the ToC nests Added/Changed/Fixed at depth 1 under each version at depth 0 (verified in the generated HTML for both/changelog/and/id/changelog/).🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes