oh-my-opencode/src/hooks/auto-update-checker/checker/pinned-version-updater.test.ts
YeonGyu-Kim 67b4665c28 fix(auto-update): revert config pin on install failure to prevent version mismatch
When bun install fails after updating the config pin, the config now shows the
new version but the actual package is the old one. Add revertPinnedVersion() to
roll back the config entry on install failure, keeping config and installed
version in sync.

Ref #1472
2026-02-11 13:52:20 +09:00

134 lines
3.9 KiB
TypeScript

import { describe, test, expect, beforeEach, afterEach } from "bun:test"
import * as fs from "node:fs"
import * as path from "node:path"
import * as os from "node:os"
import { updatePinnedVersion, revertPinnedVersion } from "./pinned-version-updater"
describe("pinned-version-updater", () => {
let tmpDir: string
let configPath: string
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "omo-updater-test-"))
configPath = path.join(tmpDir, "opencode.json")
})
afterEach(() => {
fs.rmSync(tmpDir, { recursive: true, force: true })
})
describe("updatePinnedVersion", () => {
test("updates pinned version in config", () => {
//#given
const config = JSON.stringify({
plugin: ["oh-my-opencode@3.1.8"],
})
fs.writeFileSync(configPath, config)
//#when
const result = updatePinnedVersion(configPath, "oh-my-opencode@3.1.8", "3.4.0")
//#then
expect(result).toBe(true)
const updated = fs.readFileSync(configPath, "utf-8")
expect(updated).toContain("oh-my-opencode@3.4.0")
expect(updated).not.toContain("oh-my-opencode@3.1.8")
})
test("returns false when entry not found", () => {
//#given
const config = JSON.stringify({
plugin: ["some-other-plugin"],
})
fs.writeFileSync(configPath, config)
//#when
const result = updatePinnedVersion(configPath, "oh-my-opencode@3.1.8", "3.4.0")
//#then
expect(result).toBe(false)
})
test("returns false when no plugin array exists", () => {
//#given
const config = JSON.stringify({ agent: {} })
fs.writeFileSync(configPath, config)
//#when
const result = updatePinnedVersion(configPath, "oh-my-opencode@3.1.8", "3.4.0")
//#then
expect(result).toBe(false)
})
})
describe("revertPinnedVersion", () => {
test("reverts from failed version back to original entry", () => {
//#given
const config = JSON.stringify({
plugin: ["oh-my-opencode@3.4.0"],
})
fs.writeFileSync(configPath, config)
//#when
const result = revertPinnedVersion(configPath, "3.4.0", "oh-my-opencode@3.1.8")
//#then
expect(result).toBe(true)
const reverted = fs.readFileSync(configPath, "utf-8")
expect(reverted).toContain("oh-my-opencode@3.1.8")
expect(reverted).not.toContain("oh-my-opencode@3.4.0")
})
test("reverts to unpinned entry", () => {
//#given
const config = JSON.stringify({
plugin: ["oh-my-opencode@3.4.0"],
})
fs.writeFileSync(configPath, config)
//#when
const result = revertPinnedVersion(configPath, "3.4.0", "oh-my-opencode")
//#then
expect(result).toBe(true)
const reverted = fs.readFileSync(configPath, "utf-8")
expect(reverted).toContain('"oh-my-opencode"')
expect(reverted).not.toContain("oh-my-opencode@3.4.0")
})
test("returns false when failed version not found", () => {
//#given
const config = JSON.stringify({
plugin: ["oh-my-opencode@3.1.8"],
})
fs.writeFileSync(configPath, config)
//#when
const result = revertPinnedVersion(configPath, "3.4.0", "oh-my-opencode@3.1.8")
//#then
expect(result).toBe(false)
})
})
describe("update then revert roundtrip", () => {
test("config returns to original state after update + revert", () => {
//#given
const originalConfig = JSON.stringify({
plugin: ["oh-my-opencode@3.1.8"],
})
fs.writeFileSync(configPath, originalConfig)
//#when
updatePinnedVersion(configPath, "oh-my-opencode@3.1.8", "3.4.0")
revertPinnedVersion(configPath, "3.4.0", "oh-my-opencode@3.1.8")
//#then
const finalConfig = fs.readFileSync(configPath, "utf-8")
expect(finalConfig).toContain("oh-my-opencode@3.1.8")
expect(finalConfig).not.toContain("oh-my-opencode@3.4.0")
})
})
})