Skip to content

fix: stabilize release changelog generation#19987

Merged
Hona merged 6 commits intoanomalyco:devfrom
Hona:fix/changelog-llm
Mar 30, 2026
Merged

fix: stabilize release changelog generation#19987
Hona merged 6 commits intoanomalyco:devfrom
Hona:fix/changelog-llm

Conversation

@Hona
Copy link
Copy Markdown
Member

@Hona Hona commented Mar 30, 2026

Summary

Release changelogs were shifted by one version (e.g. v1.3.5 showed v1.3.4 changes) because the LLM was improvising the commit range instead of computing it deterministically.

  • script/changelog.ts now gathers commits, sections, reverts, and contributors via gh api + git log -- LLM only summarizes diffs
  • script/version.ts pins the upper bound to GITHUB_SHA so future commits cannot leak into the current release
  • .opencode/command/changelog.md consumes the structured data via shell interpolation instead of querying GitHub itself
  • Added UPCOMING_CHANGELOG.md to .gitignore

Keep release commit discovery and contributor thanks deterministic while letting the changelog command write diff-aware summaries.
Copilot AI review requested due to automatic review settings March 30, 2026 04:07
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors the release changelog workflow to make the “data gathering” step deterministic (commit selection, section grouping, contributor input) and keep the .opencode changelog command focused on diff-aware release-note writing.

Changes:

  • Reworks script/changelog.ts to produce a stable, sectioned commit list plus deterministic community-contributor input.
  • Updates the changelog opencode command prompt to consume the structured script output (and to ignore any existing UPCOMING_CHANGELOG.md).
  • Adds UPCOMING_CHANGELOG.md to .gitignore to keep generated previews out of git state.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 3 comments.

File Description
script/changelog.ts Generates deterministic grouped commit bullets and optional community-contributor block for changelog generation.
.opencode/command/changelog.md Updates the LLM instructions to rely on bun script/changelog.ts output and preserve deterministic attribution/thanks behavior.
.gitignore Ignores the generated UPCOMING_CHANGELOG.md file.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +42 to +45
function tag(input: string) {
if (input === "HEAD") return input
if (input.startsWith("v")) return input
return `v${input}`
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tag() unconditionally prefixes non-v* inputs with v, which breaks legitimate git refs like main, HEAD~1, or a commit SHA (e.g. --to main becomes vmain, causing gh api .../compare/... and git log to fail). Consider only adding the v prefix when the input looks like a version (e.g. semver), and otherwise pass the ref through unchanged.

Suggested change
function tag(input: string) {
if (input === "HEAD") return input
if (input.startsWith("v")) return input
return `v${input}`
function isVersionLike(input: string): boolean {
// Match simple semver-like patterns without a leading "v", e.g. "1", "1.2", "1.2.3", optionally with suffixes.
return /^[0-9]+(\.[0-9]+){0,2}([\-+].*)?$/.test(input)
}
function tag(input: string) {
if (input === "HEAD") return input
if (input.startsWith("v")) return input
if (isVersionLike(input)) return `v${input}`
return input

Copilot uses AI. Check for mistakes.
}
async function published(to: string) {
if (to === "HEAD") return
const body = await $`gh release view ${tag(to)} --json body --jq .body`.text().catch(() => "")
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

published() uses gh release view ... without scoping to the repo/GH_REPO value used elsewhere in this script. If GH_REPO is set (or the working directory isn't the same repo), this can read the wrong release or fail. Pass --repo ${repo} (or -R ${repo}) to keep behavior consistent with the other gh api "/repos/${repo}/..." calls.

Suggested change
const body = await $`gh release view ${tag(to)} --json body --jq .body`.text().catch(() => "")
const body = await $`gh release view ${tag(to)} --repo ${repo} --json body --jq .body`.text().catch(() => "")

Copilot uses AI. Check for mistakes.
Comment on lines +29 to +60
const order = ["Core", "TUI", "Desktop", "SDK", "Extensions"] as const
const sections = {
core: "Core",
tui: "TUI",
app: "Desktop",
tauri: "Desktop",
sdk: "SDK",
plugin: "SDK",
"extensions/zed": "Extensions",
"extensions/vscode": "Extensions",
github: "Extensions",
} as const

function tag(input: string) {
if (input === "HEAD") return input
if (input.startsWith("v")) return input
return `v${input}`
}

async function latest() {
const data = await $`gh api "/repos/${repo}/releases?per_page=100"`.json()
const release = (data as Release[]).find((item) => !item.draft)
if (!release) throw new Error("No releases found")
return release.tag_name.replace(/^v/, "")
}

function section(areas: Set<string>) {
const priority = ["core", "tui", "app", "tauri", "sdk", "plugin", "extensions/zed", "extensions/vscode", "github"]
for (const area of priority) {
if (areas.has(area)) return sections[area as keyof typeof sections]
}
return "Core"
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sections/section() still include plugin and github keys, but commits() no longer adds plugin or github to areas (plugin is folded into sdk, and github/ is folded into extensions/vscode). Dropping the unused keys (and removing them from the priority list) will prevent future confusion about which area strings are actually emitted.

Copilot uses AI. Check for mistakes.
Hona added 5 commits March 30, 2026 14:12
Pass the version job's exact commit into the changelog command and allow changelog refs to use SHAs as well as version tags.
Paginate compare data for long release windows, avoid reusing published contributor blocks for explicit from/to previews, and remove the no-notable-changes prompt ambiguity.
@Hona Hona enabled auto-merge (squash) March 30, 2026 04:30
@Hona Hona merged commit 6926fe1 into anomalyco:dev Mar 30, 2026
8 checks passed
loocor pushed a commit to loocor/opencode that referenced this pull request Mar 30, 2026
afanty2021 pushed a commit to afanty2021/opencode that referenced this pull request Mar 30, 2026
balcsida pushed a commit to balcsida/opencode that referenced this pull request Apr 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants