From 0b211e7d994d370288cb59b551dbd2c61596dbec Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Sun, 1 Nov 2026 23:14:02 -0600 Subject: [PATCH] fix(release): leave non-client packages out of the changelog (#61190) --- script/release.ts | 49 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/script/release.ts b/script/release.ts index 8f6a1b53744b..34a3d5a8e525 100755 --- a/script/release.ts +++ b/script/release.ts @@ -9,6 +9,17 @@ import path from "path" import { parseArgs } from "util" const root = path.resolve(import.meta.dir, "..") +// Commits that only touch these folders, such as the console, stats, cloud functions, docs, websites, and infra, are +// left out of the changelog. +const changelogExclusions = [ + ":(exclude)packages/console", + ":(exclude)packages/function", + ":(exclude)packages/posts", + ":(exclude)packages/stats", + ":(exclude)packages/web", + ":(exclude)services", + ":(exclude)infra", +] const review = path.join(root, "RELEASE_REVIEW.md") const { values, positionals } = parseArgs({ args: Bun.argv.slice(2), @@ -59,8 +70,11 @@ const base = values.from ?? (await $`git tag --list "v2.*" --sort=-version:refname`.text()).split("\n").find((tag) => /^v2\.\d+\.\d+$/.test(tag)) if (!base) throw new Error("No stable V2 release tag was found") -console.log(`Comparing ${commitRange(base, values.to)}`) -await generateReview(base, values.to) +console.log(`Comparing ${base}..${values.to}`) +const commits = (await $`git log --format=${"%h %s"} ${commitRange(base, values.to)}`.text()).trim() +if (!commits) throw new Error(`No OpenCode or client changes were found since ${base}`) +console.log(`Found ${commits.split("\n").length} commits for the changelog`) +await generateReview(base, values.to, commits) if (!(await Bun.file(review).exists())) throw new Error("OpenCode did not create RELEASE_REVIEW.md") if (values.print) { @@ -103,7 +117,7 @@ if (answer?.trim().toLowerCase() !== "y" && answer?.trim().toLowerCase() !== "ye await $`gh workflow run release.yml --ref dev ${input} -f release_notes=${releaseNotes}` console.log(`Triggered the ${version} release`) -async function generateReview(base: string, head: string) { +async function generateReview(base: string, head: string, commits: string) { const endpoint = await Service.ensure() const client = OpenCode.make({ baseUrl: endpoint.url, @@ -143,7 +157,7 @@ async function generateReview(base: string, head: string) { })() try { - await client.session.prompt({ sessionID: session.id, text: reviewPrompt(base, head) }) + await client.session.prompt({ sessionID: session.id, text: reviewPrompt(base, head, commits) }) await completed const messages = await client.message.list({ sessionID: session.id, limit: 100, order: "desc" }) const response = messages.data.find((message) => message.type === "assistant") @@ -159,21 +173,26 @@ async function generateReview(base: string, head: string) { // V1 history was merged into dev when V2 was promoted, so it must be excluded from the release range. Merges are skipped // because dev only takes squash merges, and the promotion merge would otherwise show the whole V1 tree. function commitRange(base: string, head: string) { - return `--no-merges ${base}..${head} --not origin/v1` + return ["--no-merges", `${base}..${head}`, "--not", "origin/v1", "--", ".", ...changelogExclusions] } -function reviewPrompt(base: string, head: string) { +function reviewPrompt(base: string, head: string, commits: string) { + const pathspec = [".", ...changelogExclusions.map((exclusion) => `'${exclusion}'`)].join(" ") return `Create a concise pre-release review for a maintainer. -The previous stable V2 release is ${base}. Inspect every relevant commit in \`git log ${commitRange(base, head)}\` and -read each commit's actual diff with \`git show\`. Do not use a whole-tree \`git diff\` between the endpoints, which -includes V1 history merged into dev. Do not compare against V1 release tags or commits outside that range. Do not rely -only on commit titles. Write a -user-facing changelog with sections for Core, TUI, Desktop, SDK, and Extensions, omitting empty sections and changes that -are entirely internal. Group bug fixes separately from improvements. Preserve community contributor attribution when it -is available from merged pull requests, but never thank authors listed in .github/TEAM_MEMBERS. Leave out changes to -the @opencode/ai package in packages/ai unless they change how OpenCode itself behaves for users; then describe only -that OpenCode behavior. +The previous stable V2 release is ${base}. These commits from +\`git log --no-merges ${base}..${head} --not origin/v1 -- ${pathspec}\` are the only ones in scope: + +${commits} + +Inspect every relevant commit and read its actual diff with \`git show -- ${pathspec}\`. The excluded folders +are not part of OpenCode or its clients, so ignore any part of a commit in them. Do not use a whole-tree \`git diff\` +between the endpoints, which includes V1 history merged into dev. Do not compare against V1 release tags or commits +outside that range. Do not rely only on commit titles. Write a user-facing changelog with sections for Core, TUI, +Desktop, SDK, and Extensions, omitting empty sections and changes that are entirely internal. Group bug fixes separately +from improvements. Preserve community contributor attribution when it is available from merged pull requests, but never +thank authors listed in .github/TEAM_MEMBERS. Leave out changes to the @opencode/ai package in packages/ai unless they +change how OpenCode itself behaves for users; then describe only that OpenCode behavior. Start the changelog with a "### Highlights" section: the few changes worth telling people about, written for humans. Pick 2 to 5 user-visible changes a user would notice, try, or share: new capabilities, clearly better workflows, or fixes