Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions packages/opencode/src/cli/cmd/upgrade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,41 @@ export const UpgradeCommand = {
}
}
prompts.log.info("Using method: " + method)

if (method === "brew") {
const formula = await Installation.getBrewFormula()
const commands = Installation.getMigrationCommands(formula)

if (commands) {
const reason =
formula === "sst/tap/opencode"
? "You have the old sst/tap formula installed. The tap has been renamed to anomalyco/tap."
: "You are on the homebrew core formula, which updates every ~10 versions.\nThe anomalyco/tap formula updates on every release."

prompts.log.warn(`${reason}\n\nTo migrate: ${commands.join(" && ")}`)

const migrate = await prompts.confirm({
message: "Would you like to migrate to the anomalyco/tap? (You can run these commands manually later)",
initialValue: true,
})
if (migrate) {
for (const cmd of commands) {
const migrationSpinner = prompts.spinner()
migrationSpinner.start(cmd)
try {
await Installation.executeMigration([cmd])
migrationSpinner.stop(cmd)
} catch (err) {
migrationSpinner.stop(`Failed: ${cmd}`, 1)
if (err instanceof Error) prompts.log.error(err.message)
prompts.outro("Done")
return
}
}
}
}
}

const target = args.target ? args.target.replace(/^v/, "") : await Installation.latest()

if (Installation.VERSION === target) {
Expand Down
35 changes: 32 additions & 3 deletions packages/opencode/src/installation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,43 @@ export namespace Installation {
}),
)

async function getBrewFormula() {
const tapFormula = await $`brew list --formula anomalyco/tap/opencode`.throws(false).quiet().text()
if (tapFormula.includes("opencode")) return "anomalyco/tap/opencode"
export type BrewFormula = "anomalyco/tap/opencode" | "sst/tap/opencode" | "opencode"

export async function getBrewFormula(): Promise<BrewFormula> {
const anomalycoTap = await $`brew list --formula anomalyco/tap/opencode`.throws(false).quiet().text()
if (anomalycoTap.includes("opencode")) return "anomalyco/tap/opencode"

const sstTap = await $`brew list --formula sst/tap/opencode`.throws(false).quiet().text()
if (sstTap.includes("opencode")) return "sst/tap/opencode"

const coreFormula = await $`brew list --formula opencode`.throws(false).quiet().text()
if (coreFormula.includes("opencode")) return "opencode"

return "opencode"
}

export function getMigrationCommands(from: BrewFormula): string[] | null {
if (from === "anomalyco/tap/opencode") return null
if (from === "sst/tap/opencode") {
return ["brew uninstall sst/tap/opencode", "brew install anomalyco/tap/opencode"]
}
if (from === "opencode") {
return ["brew uninstall opencode", "brew install anomalyco/tap/opencode"]
}
return null
}

export async function executeMigration(commands: string[]) {
for (const cmd of commands) {
const parts = cmd.split(" ")
if (parts[0] === "brew" && parts[1] === "uninstall") {
await $`brew uninstall ${parts[2]}`.env({ HOMEBREW_NO_AUTO_UPDATE: "1", ...process.env }).quiet()
} else if (parts[0] === "brew" && parts[1] === "install") {
await $`brew install ${parts[2]}`.env({ HOMEBREW_NO_AUTO_UPDATE: "1", ...process.env }).quiet()
}
}
}

export async function upgrade(method: Method, target: string) {
let cmd
switch (method) {
Expand Down
22 changes: 22 additions & 0 deletions packages/opencode/test/installation/brew-migration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { describe, expect, test } from "bun:test"
import { Installation } from "../../src/installation"

describe("installation.brew migration", () => {
test("no migration when already on anomalyco tap", () => {
expect(Installation.getMigrationCommands("anomalyco/tap/opencode")).toBeNull()
})

test("sst tap suggests migrate to anomalyco tap", () => {
expect(Installation.getMigrationCommands("sst/tap/opencode")).toEqual([
"brew uninstall sst/tap/opencode",
"brew install anomalyco/tap/opencode",
])
})

test("core formula suggests migrate to anomalyco tap", () => {
expect(Installation.getMigrationCommands("opencode")).toEqual([
"brew uninstall opencode",
"brew install anomalyco/tap/opencode",
])
})
})