-
Notifications
You must be signed in to change notification settings - Fork 8.1k
tweak: better release notes (grouped changelog) #5768
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6,6 +6,34 @@ import { Script } from "@opencode-ai/script" | |||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const notes = [] as string[] | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const team = [ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "actions-user", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "opencode", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "rekram1-node", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "thdxr", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "kommander", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "jayair", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "fwang", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "adamdotdevin", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "iamdavidhill", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| "opencode-agent[bot]", | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| function getAreaFromPath(file: string): string { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (file.startsWith("packages/")) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const parts = file.replace("packages/", "").split("/") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (parts[0] === "extensions" && parts[1]) return `extensions/${parts[1]}` | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return parts[0] || "other" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (file.startsWith("sdks/")) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const name = file.replace("sdks/", "").split("/")[0] || "other" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return `extensions/${name}` | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const rootDir = file.split("/")[0] | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (rootDir && !rootDir.includes(".")) return rootDir | ||||||||||||||||||||||||||||||||||||||||||||||||||
Hona marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| return "other" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("=== publishing ===\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!Script.preview) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -16,13 +44,59 @@ if (!Script.preview) { | |||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .then((data: any) => data.version) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const log = | ||||||||||||||||||||||||||||||||||||||||||||||||||
| await $`git log v${previous}..HEAD --oneline --format="%h %s" -- packages/opencode packages/sdk packages/plugin packages/tauri packages/desktop`.text() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // Fetch commit authors from GitHub API (hash -> login) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const compare = | ||||||||||||||||||||||||||||||||||||||||||||||||||
| await $`gh api "/repos/sst/opencode/compare/v${previous}...HEAD" --jq '.commits[] | {sha: .sha, login: .author.login, message: .commit.message}'`.text() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const authorByHash = new Map<string, string>() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const contributors = new Map<string, string[]>() | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const commits = log | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .split("\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .filter((line) => line && !line.match(/^\w+ (ignore:|test:|chore:|ci:)/i)) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .join("\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const line of compare.split("\n").filter(Boolean)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const { sha, login, message } = JSON.parse(line) as { sha: string; login: string | null; message: string } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const shortHash = sha.slice(0, 7) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (login) authorByHash.set(shortHash, login) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const title = message.split("\n")[0] || "" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (title.match(/^(ignore:|test:|chore:|ci:|release:)/i)) continue | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (login && !team.includes(login)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!contributors.has(login)) contributors.set(login, []) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| contributors.get(login)?.push(title) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // Batch-fetch files for all commits (hash -> areas) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const diffLog = await $`git log v${previous}..HEAD --name-only --format="%h"`.text() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const areasByHash = new Map<string, Set<string>>() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let currentHash: string | null = null | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const rawLine of diffLog.split("\n")) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const line = rawLine.trim() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!line) continue | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (/^[0-9a-f]{7}$/i.test(line)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| currentHash = line | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!areasByHash.has(currentHash)) areasByHash.set(currentHash, new Set()) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (currentHash) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| areasByHash.get(currentHash)!.add(getAreaFromPath(line)) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| areasByHash.get(currentHash)!.add(getAreaFromPath(line)) | |
| let areas = areasByHash.get(currentHash) | |
| if (!areas) { | |
| areas = new Set<string>() | |
| areasByHash.set(currentHash, areas) | |
| } | |
| areas.add(getAreaFromPath(line)) |
Hona marked this conversation as resolved.
Show resolved
Hide resolved
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The prompt instructs to exclude "ui", "docs", "web", "console", "enterprise", "function", "util", "identity", "slack" areas as "internal packages". However, at least some of these appear to be user-facing: "docs" likely contains documentation that users read, and "web"/"console" might be user-facing interfaces. Additionally, the Instructions state these should be "omitted entirely unless they contain user-facing changes", but changes to documentation or web UI are inherently user-facing. This could result in important user-visible changes being omitted from release notes.
| - "ui", "docs", "web", "console", "enterprise", "function", "util", "identity", "slack" - internal packages | |
| Rules: | |
| - Use the [areas: ...] tags to determine the correct category. If a commit touches multiple areas, put it in the most relevant user-facing category. | |
| - ONLY include commits that have user-facing impact. Omit purely internal changes (CI, build scripts, internal tooling). | |
| - However, DO include refactors that touch user-facing code - refactors can introduce bugs or change behavior. | |
| - "enterprise", "function", "util", "identity", "slack" - internal tooling/packages that are not directly user-facing | |
| Rules: | |
| - Use the [areas: ...] tags to determine the correct category. If a commit touches multiple areas, put it in the most relevant user-facing category. | |
| - ONLY include commits that have user-facing impact. Omit purely internal changes (CI, build scripts, internal tooling). | |
| - However, DO include refactors that touch user-facing code - refactors can introduce bugs or change behavior. | |
| - Changes to documentation ("docs") or user interfaces ("ui", "web", "console") are generally user-facing and SHOULD be included when they affect the user experience. |
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The prompt instructions include "DO NOT add @ mentions for team members" but also require "(@username) at the end of the changelog entry" for non-team contributors. However, the team list uses different formats: some entries have "[bot]" suffix ("opencode-agent[bot]") while the GitHub API returns login names. If a bot account's login is returned without the "[bot]" suffix by the API, it might not match the team list correctly and could be incorrectly treated as a community contributor.
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example in the prompt shows "## TUI", "## Desktop", and "## Extensions" sections, but the category definition on line 132 says "Other" with bold formatting. This inconsistency in formatting (## vs **) could cause the AI model to produce inconsistent output, making the parsing logic on lines 174-179 fail to correctly identify category headers.
| ## TUI | |
| - Added experimental support for the Ty language server (@OpeOginni) | |
| - Added /fork slash command for keyboard-friendly session forking (@ariane-emory) | |
| - Increased retry attempts for failed requests | |
| - Fixed model validation before executing slash commands (@devxoul) | |
| ## Desktop | |
| - Added shell mode support | |
| - Fixed prompt history navigation and optimistic prompt duplication | |
| - Disabled pinch-to-zoom on Linux (@Brendonovich) | |
| ## Extensions | |
| **TUI** | |
| - Added experimental support for the Ty language server (@OpeOginni) | |
| - Added /fork slash command for keyboard-friendly session forking (@ariane-emory) | |
| - Increased retry attempts for failed requests | |
| - Fixed model validation before executing slash commands (@devxoul) | |
| **Desktop** | |
| - Added shell mode support | |
| - Fixed prompt history navigation and optimistic prompt duplication | |
| - Disabled pinch-to-zoom on Linux (@Brendonovich) | |
| **Extensions** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code maps "sdks/" paths to "extensions/{name}" (line 30), but the AI prompt categorizes "sdk" area as part of the "SDK" category (line 130), while "extensions/*" are in the "Extensions" category (line 131). This inconsistency means changes in "sdks/" will be incorrectly categorized as Extensions instead of SDK, which could confuse the changelog grouping.