Skip to content

chore(ci): build each CLI target in its own job and sign macOS and Windows in parallel - #56070

Open
neriousy wants to merge 1 commit into
release-runner-movesfrom
cli-target-jobs
Open

neriousy wants to merge 1 commit into
release-runner-movesfrom
cli-target-jobs

Conversation

@neriousy

@neriousy neriousy commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

Stacked on #55987 (release-runner-moves).

Summary

Today one build-cli job produces a 1.4 GB artifact of all 12 CLIs, which both signers (in sequence) and every desktop leg download in full. This PR:

  • Makes build-cli a 12-target matrix (fail-fast: false). Each leg uploads cli-unsigned-<target>; "Check CLI output" requires packages/cli/dist to hold exactly cli-<target>. GH_TOKEN is now github.token, as on beta.
  • Runs the macOS and Windows signers in parallel, each on its three targets only. Signing steps are unchanged.
  • Has each desktop leg download only its own cli-unsigned-<cli>.
  • Adds "Check CLI packages" to publish: exactly 12 cli-* packages with package.json and a non-empty binary, and every macOS binary must contain Developer ID Application: Anomaly Innovations, Inc. (5NZ4Q7NXJ4).
  • Authenticates the Bun release lookup in build.ts (as chore(ci): speed up the beta desktop publish #55919 on beta) to avoid rate limits from 12 parallel jobs.
  • Removes the legacy packages/opencode steps, which could only fail.

Job graph

Before: one job builds all 12 CLIs into a 1.4 GB artifact, which every later job downloads in full, and Windows signing waits for macOS.

flowchart LR
  B["build-cli<br/>all 12 CLIs, 1.4 GB"] --> M["sign-cli-macos<br/>downloads 1.4 GB"]
  M --> W["sign-cli-windows<br/>waits for macOS"]
  W --> P[publish]
  B --> D["6 desktop legs<br/>each downloads 1.4 GB"]
Loading

After: 12 legs each upload cli-unsigned-<target> (~100 MB). The two signers run in parallel on their own 3 targets, Linux goes straight to publish, and each desktop leg downloads only its CLI.

flowchart LR
  subgraph build-cli matrix
    BD["darwin x3"]
    BW["windows x3"]
    BL["linux x6"]
  end
  BD --> M["sign-cli-macos"]
  BW --> W["sign-cli-windows"]
  M --> P["publish<br/>Check CLI packages"]
  W --> P
  BL --> P
  BD & BW & BL -. one cli-unsigned-target each .-> D["6 desktop legs"]
Loading

Expected effect

Estimates from reference runs, not measured.

Job Today After (estimate)
build-cli 2.7–4.4 min ~1.3–2.1 min per leg, parallel
sign-cli-macos 2.3–4.3 min ~0.7–1.4 min
sign-cli-windows 1.6–4.8 min, after macOS ~0.7–2 min, alongside macOS
Desktop CLI download 11–167 s 5–9 s
  • Dev push: publish is now bound by build-node-cli; roughly 4–4.5 min off a 16–21 min run (38856436871, 38814116264).
  • Dev release: ~2–2.5 min saved in 38536124977, ~5 min in 38785024495.
  • Cost: build-cli uses ~16–25 Blacksmith 4-vCPU minutes instead of 2.7–4.4 (every leg builds the web UI). Signer minutes drop by half to two thirds; artifact storage per dev push drops from ~4.3 GB to ~2.2 GB.

Evidence

  • A real local --target=opencode-darwin-arm64 build passes "Check CLI output"; another target fails it.
  • A local simulation of the pinned artifact actions runs the real check scripts. "Check CLI packages" passes on a real signed npm dev binary and fails on missing/extra packages, empty binaries, missing package.json, and unsigned or wrongly signed macOS binaries.
  • Why the full certificate name: cross-compiled macOS output keeps Bun's own Jarred Sumner (7FRXF46ZSN) Developer ID signature, so a generic grep would pass an unsigned binary.
  • A parsed-YAML diff shows other steps unchanged. actionlint and bun run check pass.

Things to know

  • Next dev → beta merge (against origin/beta 8d5e6e2):
    • build-cli if:: keep beta's github.ref_name != 'beta' line and comment, take this PR's strategy, or beta runs these 12 legs on top of build-cli-beta.
    • Two electron matrix hunks: resolve as chore(ci): build macOS x64 and Windows arm64 desktop apps on faster runners #55987 says.
    • build.ts: one comment line conflicts; code is identical.
    • Keep one artifact name and layout end to end. Beta's artifact lacks the cli-<target>/ prefix; mixing layouts fails Desktop Prepare with ENOENT (loud, not a wrong CLI). Unifying names is a possible follow-up.
  • Signature checks: the macOS check fails closed if the Apple team or legal name changes. Windows only checks for a non-empty opencode.exe; sign-cli-windows uploads only after Get-AuthenticodeSignature reports Valid.
  • One failing leg blocks the dev publish. "Re-run failed jobs" rebuilds only that leg and keeps the version. None of the last 60 dev publish runs failed.
  • Concurrency: a dev push requests 13 Blacksmith Linux VMs at once. Near the org's cap, queueing eats into the gain but nothing breaks.
  • GH_TOKEN: 24 API calls per run against github.token's shared 1,000/hour, as on beta. It keeps contents: write and packages: write, no wider than before; narrowing is a possible follow-up.
  • Other push branches (ci, snapshot-*, etc.): now run build-cli and sign-cli-macos, and publish stops at "Check CLI packages" before publishing anything. Cost: ~12 Blacksmith legs plus a macos-26 job per push, and a production-signed cli-signed-darwin artifact from that branch. A separate PR should drop these triggers or limit these jobs to dev and beta.
  • The three opencode-preview-cli* artifacts are gone; nothing references them.
  • Possible follow-up: build the app archive once to recover most extra runner minutes.

Verification

publish.yml doesn't run on PRs, so the first dev push after merge is the first real run. Check:

  • 12 build-cli (<target>) legs pass "Check CLI output" and each uploads one ~100–120 MB cli-unsigned-<target>.
  • Both signers start together. sign-cli-macos logs "replacing existing signature" then "satisfies its Designated Requirement" for exactly 3 binaries; sign-cli-windows signs and verifies 3.
  • publish: "Check CLI packages" passes, publish.ts logs @opencode/cli binaries with 12 entries at the run's version, and @dev npm packages and R2 artifacts appear as before.

On the first dev release, check each desktop leg downloads a single ~100 MB cli-unsigned-<cli> and Prepare, Package and notarization pass.

Rollback is a revert of this commit.

…ndows in parallel

build-cli becomes a 12-target matrix that uploads one cli-unsigned-<target>
artifact per target. sign-cli-macos and sign-cli-windows both start after
build-cli and move only their own three targets, each desktop leg downloads
only the CLI it bundles, and publish checks that dist holds exactly the 12
packages with signed macOS binaries before it publishes.

The Bun release lookup in packages/cli/script/build.ts now authenticates, as
on beta, so the parallel jobs do not hit the per-IP API limit. The legacy
packages/opencode steps, which could only fail, are removed.

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.

1 participant