发布

  • fix(ci): make CLI releases reliably ship binary assets (#3515)

    frostbyte_neo 发布于 2026-06-16 11:07:23 +00:00

    Summary

    Permanently stops the recurring "release published with zero assets →
    install/upgrade 404s"
    outage
    (https://github.com/ComposioHQ/composio/issues/3408,
    https://github.com/ComposioHQ/composio/issues/3269; regressions of
    https://github.com/ComposioHQ/composio/issues/2625 and
    https://github.com/ComposioHQ/composio/issues/1820 — 3 of the last 5
    stable releases shipped empty).

    Root cause: a concurrent-writer race. On a CLI version bump,
    changesets/action creates an empty @composio/cli@x.y.z GitHub
    Release in seconds, then the slower build-cli-binaries.yml fails its
    gh release create because the release already exists — so binaries
    never attach.

    🥞 Stacked on #3415 (pi/exclude-cli-ts-release-42161920), which
    removes the second writer (changesets no longer creates CLI releases).
    Review/merge #3415 first; this PR targets that branch. This PR hardens
    the now-sole writer so a partial build can't publish either, and fixes
    the monitoring that hid the failure.

    What changed (build-cli-binaries.yml + canary)

    • Draft → verify → publish. The release is built as a draft,
      then a gate asserts all 6 canonical assets are present and state == "uploaded" (loud ::error:: + fail otherwise), and only the final step
      flips it to published. Drafts fire no release: published event and are
      excluded from /releases/latest, so no install.sh / Homebrew / redirect
      consumer can observe an incomplete release.
    • fail-fast: false on the build matrix → a single platform failure
      can never publish a partial set (needs.build.result is success only
      if all legs pass).
    • Per-tag job-level concurrency so re-runs / quick pushes can't
      interleave uploads on the same tag, without serializing unrelated betas.
    • Beta-safe: --prerelease is set on the draft so betas stay
      prereleases through the publish flip.
    • promote-stable guard uses gh release view --json isDraft (the
      REST tags endpoint 404s on drafts) to resume an existing draft but
      refuse an already-published tag.
    • Least privilege: workflow defaults to contents: read; only the
      release job opts up to contents: write.
    • Canary fix (cli.install-health-check.yml): install the newest
      stable pinned tag (npm view @composio/cli version) instead of the
      asset-aware no-arg flow, which self-heals to the last good release and
      kept the canary green through every outage.

    Idempotency note

    Re-running a run that failed before publish is safe (reuse draft +
    --clobber). An already-published tag is refused, not mutated — by
    design.

    Testing

    • Extended test/release-workflow.test.ts (run via pnpm test:release-workflow) to lock in: draft→verify→publish ordering,
      fail-fast: false, per-tag concurrency, preserved --prerelease, and
      the pinned-tag canary. passes.
    • shellcheck clean on the new run: scripts; YAML validated.
      actionlint runs in CI.
    • Runtime verification of the full green path happens on the next
      release CI run.

    Out of scope (deferred to their own PRs)

    Per reviewer consensus, these are real but not this bug: a per-release
    npm↔GitHub asset auditor (needs a grace window), the Homebrew trigger
    constraint (folds into #3355), composio upgrade missing-asset back-off
    (https://github.com/ComposioHQ/composio/issues/3269), and a rollback
    runbook.


    Co-authored-by: Rahul Tarak cryogenicplanet@gmail.com

    下载附件