fix(doctor): quote paths and respect version channels in fix messages
This commit is contained in:
parent
d4033da41a
commit
3d66a30406
18
src/cli/doctor/checks/system-loaded-version.test.ts
Normal file
18
src/cli/doctor/checks/system-loaded-version.test.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { describe, expect, it } from "bun:test"
|
||||||
|
|
||||||
|
import { getSuggestedInstallTag } from "./system-loaded-version"
|
||||||
|
|
||||||
|
describe("system loaded version", () => {
|
||||||
|
describe("getSuggestedInstallTag", () => {
|
||||||
|
it("returns prerelease channel when current version is prerelease", () => {
|
||||||
|
//#given
|
||||||
|
const currentVersion = "3.2.0-beta.4"
|
||||||
|
|
||||||
|
//#when
|
||||||
|
const installTag = getSuggestedInstallTag(currentVersion)
|
||||||
|
|
||||||
|
//#then
|
||||||
|
expect(installTag).toBe("beta")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -77,3 +77,7 @@ export async function getLatestPluginVersion(currentVersion: string | null): Pro
|
|||||||
const channel = extractChannel(currentVersion)
|
const channel = extractChannel(currentVersion)
|
||||||
return getLatestVersion(channel)
|
return getLatestVersion(channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getSuggestedInstallTag(currentVersion: string | null): string {
|
||||||
|
return extractChannel(currentVersion)
|
||||||
|
}
|
||||||
|
|||||||
104
src/cli/doctor/checks/system.test.ts
Normal file
104
src/cli/doctor/checks/system.test.ts
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import { beforeEach, describe, expect, it, mock } from "bun:test"
|
||||||
|
|
||||||
|
const mockFindOpenCodeBinary = mock(async () => ({ path: "/usr/local/bin/opencode" }))
|
||||||
|
const mockGetOpenCodeVersion = mock(async () => "1.0.200")
|
||||||
|
const mockCompareVersions = mock(() => true)
|
||||||
|
const mockGetPluginInfo = mock(() => ({
|
||||||
|
registered: true,
|
||||||
|
entry: "oh-my-opencode",
|
||||||
|
isPinned: false,
|
||||||
|
pinnedVersion: null,
|
||||||
|
configPath: null,
|
||||||
|
isLocalDev: false,
|
||||||
|
}))
|
||||||
|
const mockGetLoadedPluginVersion = mock(() => ({
|
||||||
|
cacheDir: "/Users/test/Library/Caches/opencode with spaces",
|
||||||
|
cachePackagePath: "/tmp/package.json",
|
||||||
|
installedPackagePath: "/tmp/node_modules/oh-my-opencode/package.json",
|
||||||
|
expectedVersion: "3.0.0",
|
||||||
|
loadedVersion: "3.1.0",
|
||||||
|
}))
|
||||||
|
const mockGetLatestPluginVersion = mock(async () => null)
|
||||||
|
|
||||||
|
mock.module("./system-binary", () => ({
|
||||||
|
findOpenCodeBinary: mockFindOpenCodeBinary,
|
||||||
|
getOpenCodeVersion: mockGetOpenCodeVersion,
|
||||||
|
compareVersions: mockCompareVersions,
|
||||||
|
}))
|
||||||
|
|
||||||
|
mock.module("./system-plugin", () => ({
|
||||||
|
getPluginInfo: mockGetPluginInfo,
|
||||||
|
}))
|
||||||
|
|
||||||
|
mock.module("./system-loaded-version", () => ({
|
||||||
|
getLoadedPluginVersion: mockGetLoadedPluginVersion,
|
||||||
|
getLatestPluginVersion: mockGetLatestPluginVersion,
|
||||||
|
}))
|
||||||
|
|
||||||
|
const { checkSystem } = await import("./system?test")
|
||||||
|
|
||||||
|
describe("system check", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockFindOpenCodeBinary.mockReset()
|
||||||
|
mockGetOpenCodeVersion.mockReset()
|
||||||
|
mockCompareVersions.mockReset()
|
||||||
|
mockGetPluginInfo.mockReset()
|
||||||
|
mockGetLoadedPluginVersion.mockReset()
|
||||||
|
mockGetLatestPluginVersion.mockReset()
|
||||||
|
|
||||||
|
mockFindOpenCodeBinary.mockResolvedValue({ path: "/usr/local/bin/opencode" })
|
||||||
|
mockGetOpenCodeVersion.mockResolvedValue("1.0.200")
|
||||||
|
mockCompareVersions.mockReturnValue(true)
|
||||||
|
mockGetPluginInfo.mockReturnValue({
|
||||||
|
registered: true,
|
||||||
|
entry: "oh-my-opencode",
|
||||||
|
isPinned: false,
|
||||||
|
pinnedVersion: null,
|
||||||
|
configPath: null,
|
||||||
|
isLocalDev: false,
|
||||||
|
})
|
||||||
|
mockGetLoadedPluginVersion.mockReturnValue({
|
||||||
|
cacheDir: "/Users/test/Library/Caches/opencode with spaces",
|
||||||
|
cachePackagePath: "/tmp/package.json",
|
||||||
|
installedPackagePath: "/tmp/node_modules/oh-my-opencode/package.json",
|
||||||
|
expectedVersion: "3.0.0",
|
||||||
|
loadedVersion: "3.1.0",
|
||||||
|
})
|
||||||
|
mockGetLatestPluginVersion.mockResolvedValue(null)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("#given cache directory contains spaces", () => {
|
||||||
|
it("uses a quoted cache directory in mismatch fix command", async () => {
|
||||||
|
//#when
|
||||||
|
const result = await checkSystem()
|
||||||
|
|
||||||
|
//#then
|
||||||
|
const mismatchIssue = result.issues.find((issue) => issue.title === "Loaded plugin version mismatch")
|
||||||
|
expect(mismatchIssue?.fix).toBe('Reinstall: cd "/Users/test/Library/Caches/opencode with spaces" && bun install')
|
||||||
|
})
|
||||||
|
|
||||||
|
it("uses the loaded version channel for update fix command", async () => {
|
||||||
|
//#given
|
||||||
|
mockGetLoadedPluginVersion.mockReturnValue({
|
||||||
|
cacheDir: "/Users/test/Library/Caches/opencode with spaces",
|
||||||
|
cachePackagePath: "/tmp/package.json",
|
||||||
|
installedPackagePath: "/tmp/node_modules/oh-my-opencode/package.json",
|
||||||
|
expectedVersion: "3.0.0-canary.1",
|
||||||
|
loadedVersion: "3.0.0-canary.1",
|
||||||
|
})
|
||||||
|
mockGetLatestPluginVersion.mockResolvedValue("3.0.0-canary.2")
|
||||||
|
mockCompareVersions.mockImplementation((leftVersion: string, rightVersion: string) => {
|
||||||
|
return !(leftVersion === "3.0.0-canary.1" && rightVersion === "3.0.0-canary.2")
|
||||||
|
})
|
||||||
|
|
||||||
|
//#when
|
||||||
|
const result = await checkSystem()
|
||||||
|
|
||||||
|
//#then
|
||||||
|
const outdatedIssue = result.issues.find((issue) => issue.title === "Loaded plugin is outdated")
|
||||||
|
expect(outdatedIssue?.fix).toBe(
|
||||||
|
'Update: cd "/Users/test/Library/Caches/opencode with spaces" && bun add oh-my-opencode@canary'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -4,7 +4,7 @@ import { MIN_OPENCODE_VERSION, CHECK_IDS, CHECK_NAMES } from "../constants"
|
|||||||
import type { CheckResult, DoctorIssue, SystemInfo } from "../types"
|
import type { CheckResult, DoctorIssue, SystemInfo } from "../types"
|
||||||
import { findOpenCodeBinary, getOpenCodeVersion, compareVersions } from "./system-binary"
|
import { findOpenCodeBinary, getOpenCodeVersion, compareVersions } from "./system-binary"
|
||||||
import { getPluginInfo } from "./system-plugin"
|
import { getPluginInfo } from "./system-plugin"
|
||||||
import { getLatestPluginVersion, getLoadedPluginVersion } from "./system-loaded-version"
|
import { getLatestPluginVersion, getLoadedPluginVersion, getSuggestedInstallTag } from "./system-loaded-version"
|
||||||
import { parseJsonc } from "../../../shared"
|
import { parseJsonc } from "../../../shared"
|
||||||
|
|
||||||
function isConfigValid(configPath: string | null): boolean {
|
function isConfigValid(configPath: string | null): boolean {
|
||||||
@ -54,6 +54,7 @@ export async function checkSystem(): Promise<CheckResult> {
|
|||||||
const [systemInfo, pluginInfo] = await Promise.all([gatherSystemInfo(), Promise.resolve(getPluginInfo())])
|
const [systemInfo, pluginInfo] = await Promise.all([gatherSystemInfo(), Promise.resolve(getPluginInfo())])
|
||||||
const loadedInfo = getLoadedPluginVersion()
|
const loadedInfo = getLoadedPluginVersion()
|
||||||
const latestVersion = await getLatestPluginVersion(systemInfo.loadedVersion)
|
const latestVersion = await getLatestPluginVersion(systemInfo.loadedVersion)
|
||||||
|
const installTag = getSuggestedInstallTag(systemInfo.loadedVersion)
|
||||||
const issues: DoctorIssue[] = []
|
const issues: DoctorIssue[] = []
|
||||||
|
|
||||||
if (!systemInfo.opencodePath) {
|
if (!systemInfo.opencodePath) {
|
||||||
@ -93,7 +94,7 @@ export async function checkSystem(): Promise<CheckResult> {
|
|||||||
issues.push({
|
issues.push({
|
||||||
title: "Loaded plugin version mismatch",
|
title: "Loaded plugin version mismatch",
|
||||||
description: `Cache expects ${loadedInfo.expectedVersion} but loaded ${loadedInfo.loadedVersion}.`,
|
description: `Cache expects ${loadedInfo.expectedVersion} but loaded ${loadedInfo.loadedVersion}.`,
|
||||||
fix: `Reinstall: cd ${loadedInfo.cacheDir} && bun install`,
|
fix: `Reinstall: cd "${loadedInfo.cacheDir}" && bun install`,
|
||||||
severity: "warning",
|
severity: "warning",
|
||||||
affects: ["plugin loading"],
|
affects: ["plugin loading"],
|
||||||
})
|
})
|
||||||
@ -107,7 +108,7 @@ export async function checkSystem(): Promise<CheckResult> {
|
|||||||
issues.push({
|
issues.push({
|
||||||
title: "Loaded plugin is outdated",
|
title: "Loaded plugin is outdated",
|
||||||
description: `Loaded ${systemInfo.loadedVersion}, latest ${latestVersion}.`,
|
description: `Loaded ${systemInfo.loadedVersion}, latest ${latestVersion}.`,
|
||||||
fix: `Update: cd ${loadedInfo.cacheDir} && bun add oh-my-opencode@latest`,
|
fix: `Update: cd "${loadedInfo.cacheDir}" && bun add oh-my-opencode@${installTag}`,
|
||||||
severity: "warning",
|
severity: "warning",
|
||||||
affects: ["plugin features"],
|
affects: ["plugin features"],
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user