fix: validate upstream changeset range start

This commit is contained in:
Mark IJbema
2026-06-16 10:35:35 +02:00
parent b4f9904f15
commit 05b59ba0f7
4 changed files with 27 additions and 19 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
---
"@kilocode/cli": minor
"kilo-code": minor
"@kilocode/cli": patch
"kilo-code": patch
---
Changes from opencode v1.14.51 to v1.15.4 upstream:
+1 -1
View File
@@ -69,7 +69,7 @@ After merging upstream opencode releases, use `opencode-changesets.ts` to turn t
bun script/upstream/opencode-changesets.ts --from 1.17.0 --to 1.17.7
```
The script fetches releases from `anomalyco/opencode`, selects published releases in the semver range `(from, to]`, and writes one `.changeset/opencode-vX-Y-Z-to-vX-Y-Z.md` file for the whole range. It requires the target release to exist, merges notes from every release into shared `##` sections and `###` categories, then folds those headings into each bullet (for example, `Core Bugfixes: ...`) so Changesets can embed the notes cleanly in package changelogs. It generates a minor changeset for the fixed release group, `@kilocode/cli` and `kilo-code`. Generated notes omit contributor thank-you blocks and the upstream `Desktop` and `SDK` sections by default because Kilo does not ship the opencode desktop app and SDK release notes are not user-facing for Kilo.
The script fetches releases from `anomalyco/opencode`, selects published releases in the semver range `(from, to]`, and writes one `.changeset/opencode-vX-Y-Z-to-vX-Y-Z.md` file for the whole range. It requires the target release to exist, merges notes from every release into shared `##` sections and `###` categories, then folds those headings into each bullet (for example, `Core Bugfixes: ...`) so Changesets can embed the notes cleanly in package changelogs. It generates a patch changeset for the fixed release group, `@kilocode/cli` and `kilo-code`. Generated notes omit contributor thank-you blocks and the upstream `Desktop` and `SDK` sections by default because Kilo does not ship the opencode desktop app and SDK release notes are not user-facing for Kilo.
## Merge Process
+12 -8
View File
@@ -28,12 +28,16 @@ describe("opencode changesets", () => {
expect(() => select(releases, "1.2.0", "99.9.9")).toThrow("Target opencode release does not exist")
})
test("requires the starting release to exist", () => {
expect(() => select(releases, "1.1.9", "1.2.3")).toThrow("Starting opencode release does not exist")
})
test("formats changeset markdown", () => {
expect(
changeset([{ tag_name: "v1.2.2", body: "\r\n## Core\r\n\r\n- Fix issue\r\n" }], "1.2.1", "1.2.2"),
).toBe(`---
"@kilocode/cli": minor
"kilo-code": minor
"@kilocode/cli": patch
"kilo-code": patch
---
Changes from opencode v1.2.1 to v1.2.2 upstream:
@@ -67,8 +71,8 @@ Changes from opencode v1.2.1 to v1.2.2 upstream:
},
], "1.2.1", "1.2.2"),
).toBe(`---
"@kilocode/cli": minor
"kilo-code": minor
"@kilocode/cli": patch
"kilo-code": patch
---
Changes from opencode v1.2.1 to v1.2.2 upstream:
@@ -116,8 +120,8 @@ Changes from opencode v1.2.1 to v1.2.2 upstream:
},
], "1.2.0", "1.2.2"),
).toBe(`---
"@kilocode/cli": minor
"kilo-code": minor
"@kilocode/cli": patch
"kilo-code": patch
---
Changes from opencode v1.2.0 to v1.2.2 upstream:
@@ -148,8 +152,8 @@ Changes from opencode v1.2.0 to v1.2.2 upstream:
},
], "1.2.1", "1.2.2"),
).toBe(`---
"@kilocode/cli": minor
"kilo-code": minor
"@kilocode/cli": patch
"kilo-code": patch
---
Changes from opencode v1.2.1 to v1.2.2 upstream:
+12 -8
View File
@@ -24,7 +24,7 @@ type Group = Map<string, Map<string, string[]>>
const repo = "anomalyco/opencode"
const pkgs = ["@kilocode/cli", "kilo-code"]
const bump: Bump = "minor"
const bump: Bump = "patch"
const drop = ["Desktop", "SDK"]
const usage = `
@@ -184,11 +184,21 @@ export function select(releases: Release[], from: string, to: string) {
if (semver.gt(base, head) || base === head) throw new Error(`Expected from version to be lower than to version`)
const seen = new Set<string>()
const selected = releases
const published = releases
.filter((release) => !release.draft)
.filter((release) => !release.prerelease)
.map((release) => ({ release, version: semver.valid(release.tag_name.replace(/^v/, "")) }))
.filter((item): item is { release: Release; version: string } => Boolean(item.version))
if (!published.some((item) => item.version === base)) {
throw new Error(`Starting opencode release does not exist or is not published: ${tag(base)}`)
}
if (!published.some((item) => item.version === head)) {
throw new Error(`Target opencode release does not exist or is not published: ${tag(head)}`)
}
return published
.filter((item) => {
if (seen.has(item.version)) return false
seen.add(item.version)
@@ -196,12 +206,6 @@ export function select(releases: Release[], from: string, to: string) {
})
.sort((a, b) => semver.compare(a.version, b.version))
.map((item) => ({ ...item.release, tag_name: tag(item.version) }))
if (!selected.some((release) => release.tag_name === tag(head))) {
throw new Error(`Target opencode release does not exist or is not published: ${tag(head)}`)
}
return selected
}
export function changeset(releases: Release[], from: string, to: string) {