diff --git a/packages/opencode/test/kilocode/commit-message/generate.test.ts b/packages/opencode/test/kilocode/commit-message/generate.test.ts index 70acf2da35b..87a93dd4d30 100644 --- a/packages/opencode/test/kilocode/commit-message/generate.test.ts +++ b/packages/opencode/test/kilocode/commit-message/generate.test.ts @@ -1,8 +1,5 @@ import { describe, expect, test, mock, beforeEach } from "bun:test" -import { $ } from "bun" -import * as fs from "fs/promises" -import path from "path" -import { tmpdir } from "../../fixture/fixture" +import type { GitContext } from "@/kilocode/commit-message/types" // Mock dependencies before importing the module under test. // IMPORTANT: Bun's mock.module() is process-wide and permanent. To avoid @@ -13,24 +10,32 @@ const realLog = await import("@/util/log") const realProvider = await import("@/provider/provider") const realLLM = await import("@/session/llm") const realAgent = await import("@/agent/agent") +const realGitContext = await import("@/kilocode/commit-message/git-context") let mockStreamText = "feat(src): add hello world logging" -async function change(dir: string, files: Record = { "src/index.ts": "console.log('hello')\n" }) { - for (const [file, text] of Object.entries(files)) { - const target = path.join(dir, file) - await fs.mkdir(path.dirname(target), { recursive: true }) - await Bun.write(target, text) - await $`git add ${file}`.cwd(dir).quiet() - } +const defaultGitContext: GitContext = { + branch: "main", + recentCommits: ["abc1234 initial commit"], + files: [ + { + status: "modified", + path: "src/index.ts", + diff: "+console.log('hello')", + }, + ], } -async function generated(text = mockStreamText) { - mockStreamText = text - await using tmp = await tmpdir({ git: true }) - await change(tmp.path) - return generateCommitMessage({ path: tmp.path }) -} +let mockGitContext: GitContext = { ...defaultGitContext } +let captured: { path: string; selected?: string[] } = { path: "" } + +mock.module("@/kilocode/commit-message/git-context", () => ({ + ...realGitContext, + getGitContext: async (repoPath: string, selectedFiles?: string[]) => { + captured = { path: repoPath, selected: selectedFiles } + return mockGitContext + }, +})) mock.module("@/provider/provider", () => ({ ...realProvider, @@ -81,70 +86,80 @@ import { generateCommitMessage } from "../../../src/kilocode/commit-message/gene describe("commit-message.generate", () => { beforeEach(() => { mockStreamText = "feat(src): add hello world logging" + mockGitContext = { ...defaultGitContext } + captured = { path: "" } }) describe("prompt construction", () => { test("passes path to getGitContext", async () => { - await using tmp = await tmpdir({ git: true }) - await change(tmp.path) - const result = await generateCommitMessage({ path: tmp.path }) + const result = await generateCommitMessage({ path: "/repo" }) expect(result.message).toBeTruthy() + expect(captured.path).toBe("/repo") }) test("generates message from git context with multiple files", async () => { mockStreamText = "feat(api): add api module" - await using tmp = await tmpdir({ git: true }) - await change(tmp.path, { - "src/api.ts": "export function api() {}\n", - "src/index.ts": "import { api } from './api'\n", - }) - - const result = await generateCommitMessage({ path: tmp.path }) + mockGitContext = { + branch: "main", + recentCommits: ["abc1234 initial commit"], + files: [ + { status: "added", path: "src/api.ts", diff: "+export function api() {}" }, + { status: "modified", path: "src/index.ts", diff: "+import { api } from './api'" }, + ], + } + const result = await generateCommitMessage({ path: "/repo" }) expect(result.message).toBe("feat(api): add api module") }) }) describe("response cleaning", () => { test("strips code block markers from response", async () => { - const result = await generated("```\nfeat: add feature\n```") + mockStreamText = "```\nfeat: add feature\n```" + const result = await generateCommitMessage({ path: "/repo" }) expect(result.message).toBe("feat: add feature") }) test("strips code block markers with language tag", async () => { - const result = await generated("```text\nfix(auth): resolve token refresh\n```") + mockStreamText = "```text\nfix(auth): resolve token refresh\n```" + const result = await generateCommitMessage({ path: "/repo" }) expect(result.message).toBe("fix(auth): resolve token refresh") }) test("strips surrounding double quotes", async () => { - const result = await generated('"feat: add new feature"') + mockStreamText = '"feat: add new feature"' + const result = await generateCommitMessage({ path: "/repo" }) expect(result.message).toBe("feat: add new feature") }) test("strips surrounding single quotes", async () => { - const result = await generated("'fix: resolve bug'") + mockStreamText = "'fix: resolve bug'" + const result = await generateCommitMessage({ path: "/repo" }) expect(result.message).toBe("fix: resolve bug") }) test("strips whitespace around the message", async () => { - const result = await generated(" \n chore: update deps \n ") + mockStreamText = " \n chore: update deps \n " + const result = await generateCommitMessage({ path: "/repo" }) expect(result.message).toBe("chore: update deps") }) test("strips code blocks AND quotes together", async () => { - const result = await generated('```\n"refactor: simplify logic"\n```') + mockStreamText = '```\n"refactor: simplify logic"\n```' + const result = await generateCommitMessage({ path: "/repo" }) expect(result.message).toBe("refactor: simplify logic") }) test("returns clean message when no markers present", async () => { - const result = await generated("docs: update readme") + mockStreamText = "docs: update readme" + const result = await generateCommitMessage({ path: "/repo" }) expect(result.message).toBe("docs: update readme") }) }) describe("error on no changes", () => { test("throws when no git changes are found", async () => { - await using tmp = await tmpdir({ git: true }) - await expect(generateCommitMessage({ path: tmp.path })).rejects.toThrow( + mockGitContext = { branch: "main", recentCommits: [], files: [] } + await expect(generateCommitMessage({ path: "/repo" })).rejects.toThrow( "No changes found to generate a commit message for", ) }) @@ -152,29 +167,24 @@ describe("commit-message.generate", () => { describe("selectedFiles pass-through", () => { test("passes selectedFiles to getGitContext", async () => { - await using tmp = await tmpdir({ git: true }) - await change(tmp.path, { - "src/a.ts": "export const a = 1\n", - "src/b.ts": "export const b = 1\n", - }) const result = await generateCommitMessage({ - path: tmp.path, + path: "/repo", selectedFiles: ["src/a.ts"], }) expect(result.message).toBeTruthy() + expect(captured.path).toBe("/repo") + expect(captured.selected).toEqual(["src/a.ts"]) }) }) describe("custom prompt", () => { test("uses default prompt when no custom prompt provided", async () => { - const result = await generated() + const result = await generateCommitMessage({ path: "/repo" }) expect(result.message).toBeTruthy() }) test("uses custom prompt when provided", async () => { - await using tmp = await tmpdir({ git: true }) - await change(tmp.path) - const result = await generateCommitMessage({ path: tmp.path, prompt: "Write a haiku commit message." }) + const result = await generateCommitMessage({ path: "/repo", prompt: "Write a haiku commit message." }) expect(result.message).toBeTruthy() }) }) diff --git a/packages/opencode/test/memory/abort-leak.test.ts b/packages/opencode/test/memory/abort-leak.test.ts index b19f0d3f627..539bac0111b 100644 --- a/packages/opencode/test/memory/abort-leak.test.ts +++ b/packages/opencode/test/memory/abort-leak.test.ts @@ -26,7 +26,9 @@ const getHeapMB = () => { } describe("memory: abort controller leak", () => { - test("webfetch does not leak memory over many invocations", async () => { + // kilocode_change start - TODO(#8990): skip flaky test on Linux CI + test.skip("webfetch does not leak memory over many invocations", async () => { + // kilocode_change end await Instance.provide({ directory: projectRoot, fn: async () => { diff --git a/packages/opencode/test/session/prompt-effect.test.ts b/packages/opencode/test/session/prompt-effect.test.ts index c60651fa945..499669ebd60 100644 --- a/packages/opencode/test/session/prompt-effect.test.ts +++ b/packages/opencode/test/session/prompt-effect.test.ts @@ -190,6 +190,7 @@ function makeHttp() { const it = testEffect(makeHttp()) const unix = process.platform !== "win32" ? it.live : it.live.skip +const unixSkip = it.live.skip // kilocode_change - TODO(#8990): skip flaky cancel tests on Linux CI // Config that registers a custom "test" provider with a "test-model" model // so Provider.getModel("test", "test-model") succeeds inside the loop. @@ -1197,7 +1198,8 @@ it.live( 3_000, ) -unix( +// kilocode_change start - TODO(#8990): flaky on Linux CI +unixSkip( "cancel interrupts shell and resolves cleanly", () => withSh(() => @@ -1233,8 +1235,10 @@ unix( ), 30_000, ) +// kilocode_change end -unix( +// kilocode_change start - TODO(#8990): flaky on Linux CI +unixSkip( "cancel persists aborted shell result when shell ignores TERM", () => withSh(() => @@ -1265,6 +1269,7 @@ unix( ), 30_000, ) +// kilocode_change end unix( "cancel finalizes interrupted bash tool output through normal truncation", @@ -1317,7 +1322,8 @@ unix( 30_000, ) -unix( +// kilocode_change start - TODO(#8990): flaky on Linux CI +unixSkip( "cancel interrupts loop queued behind shell", () => provideTmpdirInstance( @@ -1344,6 +1350,7 @@ unix( ), 30_000, ) +// kilocode_change end unix( "shell rejects when another shell is already running",