Skip to content

feat(release): publish OpenCode 2 GitHub Releases without taking Latest - #54903

Open
thdxr wants to merge 2 commits into
devfrom
v2-github-releases
Open

thdxr wants to merge 2 commits into
devfrom
v2-github-releases

Conversation

@thdxr

@thdxr thdxr commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

Issue for this PR

Closes #

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

This lets OpenCode 2 publish GitHub Releases while OpenCode 1 clients stay on 1.x. It's paired with the v1 PR: #54904.

Every shipped OpenCode 1 update path reads GitHub's Latest release, not the newest one. That covers the CLI for curl/yarn installs, opencode.ai/install, electron-updater, the old Tauri feed, the GitHub Action and Scoop. So OpenCode 2 releases must never take Latest.

  • script/publish.ts: for stable releases, creates the GitHub Release for the tag with --verify-tag --latest=false and the reviewed release_notes as the body.
    • If the release already exists, it's edited instead, still with --latest=false.
    • No assets are attached.
    • Gated by the repo variable OPENCODE_V2_GITHUB_RELEASES=true, so merging this doesn't start publishing releases.
  • verify-github-latest job and script/check-github-latest.ts: after a stable release, fails loudly if Latest isn't a v1. tag. It prints the exact gh release edit <newest v1 tag> --latest command and doesn't fix anything itself.
  • Discord: notify-discord.yml now only announces v1. releases, so OpenCode 2 is announced once, by notify-discord-v2. That job links the release page when releases are enabled.
  • Update service: channelsForRef("refs/heads/v1") returns ["v1"]. V1 can't publish to latest/dev, and no V2 ref can publish to v1. Tests are added.
    • I left the refs/heads/v2 mapping in place, because the v2 branch still exists and its publish.yml still triggers on pushes.
    • No v1-dev channel: V1 previews keep using the opencode-ai@dev npm tag.
  • Docs: docs/release/v1-v2-isolation.md covers the rollout order, the flip criteria and commands, the Homebrew Core and Chocolatey caveats, and rollback.

Why --latest=false is needed: gh release create without --latest uses "automatic", and publishing a draft defaults make_latest to true. Both moved Latest to 2.x in a scratch-repo test; the results are in the doc.

How did you verify your code works?

  • Ran the release block against a private scratch repo (thdxr/latest-flag-test), covering create, re-run without notes, and re-run with new notes. Latest stayed on v1 every time.
  • check-github-latest.ts passes against anomalyco/opencode (v1.19.0). When the scratch repo's Latest was moved to v2, it failed with the remediation command.
  • bun test in services/update (7 pass) and bun typecheck.
  • bun run check passes; actionlint reports nothing new.

Screenshots / recordings

N/A

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

— from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊


Added by the opencode bot (AI-generated).

Related: #52184, #54813, #54066

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The release changes work as described, and I found nothing that should block a merge. In services/update, bun test passes 7/7 and typecheck passes. On the base branch, the two v1 tests (channelsForRef and validGitHubClaims) fail, as they should. I ran script/check-github-latest.ts with a stand-in gh. It passes when Latest is v1.19.0. When Latest is a 2.x tag it fails and points at the right command, gh release edit v1.19.0 … --latest, skipping prereleases and ordering versions correctly. I couldn't run the gh release create/edit step without credentials. Reading it, --verify-tag holds because the tag is pushed earlier in the script, and the step only runs for stable releases when the variable is set.

Public API: unchanged. The update service now also accepts publishes from refs/heads/v1, only to the v1 channel. The response shape and existing refs are unchanged, and the new variables are internal to the release workflow.

One small test cleanup is noted inline.

Related: #52184, #54813, #54066

})
})

const rows = [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The v1 channel block (this fake D1 and the two worker.fetch tests) also passes on the base branch. Serving a channel by name already worked; the change is only in channelsForRef. The mock also does its own channel filtering, so these tests mostly check the mock. They could be dropped, leaving the channelsForRef and validGitHubClaims tests to cover the change.

@hussain

hussain commented Oct 21, 2026

Copy link
Copy Markdown

How the ACP registry, which IntelliJ, Zed and ACP Patchbay install OpenCode from, updates its two OpenCode entries today:

So once OPENCODE_V2_GITHUB_RELEASES=true, the opencode entry would target the newest v2 tag whether or not it's Latest. With no assets on that release, the update fails validation, and the V1 entry stops receiving 1.x updates in every registry client.

If V1 is to be retired, the registry needs a decision too: either let opencode follow GitHub Releases on to V2, or keep both entries until things settle, with opencode held on 1.x.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants