From 05b59ba0f7462464ecc488293303493be7effbbc Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Tue, 16 Jun 2026 10:35:35 +0200 Subject: [PATCH] fix: validate upstream changeset range start --- .changeset/opencode-v1-14-51-to-v1-15-4.md | 4 ++-- script/upstream/README.md | 2 +- script/upstream/opencode-changesets.test.ts | 20 ++++++++++++-------- script/upstream/opencode-changesets.ts | 20 ++++++++++++-------- 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/.changeset/opencode-v1-14-51-to-v1-15-4.md b/.changeset/opencode-v1-14-51-to-v1-15-4.md index faec06f35a..8e2e5886da 100644 --- a/.changeset/opencode-v1-14-51-to-v1-15-4.md +++ b/.changeset/opencode-v1-14-51-to-v1-15-4.md @@ -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: diff --git a/script/upstream/README.md b/script/upstream/README.md index 54b9c94ed2..0ec8999b9b 100644 --- a/script/upstream/README.md +++ b/script/upstream/README.md @@ -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 diff --git a/script/upstream/opencode-changesets.test.ts b/script/upstream/opencode-changesets.test.ts index e680620ca9..1c61e667a8 100644 --- a/script/upstream/opencode-changesets.test.ts +++ b/script/upstream/opencode-changesets.test.ts @@ -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: diff --git a/script/upstream/opencode-changesets.ts b/script/upstream/opencode-changesets.ts index a77ca8e32c..0b7be3c683 100644 --- a/script/upstream/opencode-changesets.ts +++ b/script/upstream/opencode-changesets.ts @@ -24,7 +24,7 @@ type Group = Map> 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() - 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) {