Skip to content

fix: add release smoke tests to prevent broken binary publishes#463

Merged
anandgupta42 merged 2 commits intomainfrom
fix/release-smoke-test-guard
Mar 25, 2026
Merged

fix: add release smoke tests to prevent broken binary publishes#463
anandgupta42 merged 2 commits intomainfrom
fix/release-smoke-test-guard

Conversation

@anandgupta42
Copy link
Contributor

@anandgupta42 anandgupta42 commented Mar 25, 2026

What does this PR do?

Adds three-layer defense to prevent broken binary releases like v0.5.10, where @altimateai/altimate-core was marked as external but missing from standalone distributions:

  1. CI smoke test — runs the compiled linux-x64 binary after build AND before npm publish
  2. Build-time verification — validates all requiredExternals are in package.json dependencies
  3. Local pre-release scriptbun run pre-release builds + smoke-tests before tagging

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Issue for this PR

Closes #462

How did you verify your code works?

  • bun run typecheck — clean
  • bun test test/install/ — 123 tests pass (120 existing + 3 new smoke tests)
  • bun run pre-release — all 4 checks pass (deps in package.json, installed, build, smoke test)
  • Reviewed by 5 AI models (Claude, GPT 5.2 Codex, Gemini 3.1 Pro, Kimi K2.5, MiniMax M2.5)
  • Key fixes from review: workspace node_modules in NODE_PATH (Gemini), dependencies-only check (GPT/Gemini/Kimi), hard-fail pre-publish gate (Claude/GPT), exit code assertion tightening (MiniMax)

Checklist

  • I have performed a self-review of my own code
  • I have added tests that prove my fix is effective
  • New and existing unit tests pass locally with my changes

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores

    • Strengthened release process with multi-step validation to prevent broken npm binary publishes.
    • Added a pre-release actionable check that blocks tagging when validations fail.
  • Documentation

    • Updated release guide to require running the pre-release sanity check before tagging.
  • Tests

    • Added smoke tests for compiled binaries: version, standalone startup behavior, and help output.

Closes #462

v0.5.10 shipped with `@altimateai/altimate-core` missing from standalone
distributions, crashing on startup. Add three-layer defense:

- **CI smoke test**: run the compiled `linux-x64` binary after build and
  before npm publish — catches runtime crashes that compile fine
- **Build-time verification**: validate all `requiredExternals` are in
  `package.json` `dependencies` (not just `devDependencies`) so they
  ship in the npm wrapper package
- **Local pre-release script**: `bun run pre-release` builds + smoke-tests
  the binary before tagging — mandatory step in RELEASING.md

Also adds `smoke-test-binary.test.ts` with 3 tests: version check,
standalone graceful-failure, and `--help` output.

Reviewed by 5 AI models (Claude, GPT 5.2 Codex, Gemini 3.1 Pro,
Kimi K2.5, MiniMax M2.5). Key fixes from review:
- Include workspace `node_modules` in `NODE_PATH` (Gemini)
- Restrict dep check to `dependencies` only (GPT, Gemini, Kimi)
- Hard-fail pre-publish gate when binary not found (Claude, GPT)
- Tighten exit code assertion for signal safety (MiniMax)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai
Copy link

coderabbitai bot commented Mar 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 51a6144b-8332-40dc-9585-d487ab20122c

📥 Commits

Reviewing files that changed from the base of the PR and between b3baea0 and bbf7a23.

📒 Files selected for processing (3)
  • .github/workflows/release.yml
  • packages/opencode/script/pre-release-check.ts
  • packages/opencode/test/install/smoke-test-binary.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • .github/workflows/release.yml
  • packages/opencode/script/pre-release-check.ts
  • packages/opencode/test/install/smoke-test-binary.test.ts

📝 Walkthrough

Walkthrough

Adds multi-layer release validation: build-time verification of required externals, a pre-release sanity-check script, CI binary smoke tests, an npm pre-release script, and updated release docs to require the local sanity check before tagging. Tests exercise binary startup, standalone failure behavior, and help output.

Changes

Cohort / File(s) Summary
Release docs & meta
\.github/meta/commit.txt, docs/RELEASING.md
Updated release notes and process: added mandatory "Run pre-release sanity check" step and described three-layer defenses (CI smoke test, build-time verification, local pre-release step).
GitHub Actions (release workflow)
.github/workflows/release.yml
Added CI smoke-test steps in build and publish-npm jobs that locate the linux-x64 altimate binary, ensure executability, set NODE_PATH, and run --version before publishing.
Build config & package scripts
packages/opencode/script/build.ts, packages/opencode/package.json
Introduced requiredExternals / optionalExternals; external list used in Bun build; added build-time check ensuring required externals are in dependencies (fatal when releasing); added pre-release npm script.
Pre-release sanity script
packages/opencode/script/pre-release-check.ts
New Bun script performing ordered checks: required dependency present, module resolvable, local bun run build:local succeeds, compiled binary found and runs --version. Exits non-zero on any failure.
Binary smoke tests
packages/opencode/test/install/smoke-test-binary.test.ts
New test suite that discovers local binary (or skips), runs three checks: --version with constructed NODE_PATH, standalone behavior with cleared NODE_PATH (expects graceful failure mentioning altimate-core), and --help producing output.

Sequence Diagram(s)

sequenceDiagram
    actor Dev as Developer
    participant Pre as Pre-release Check
    participant Build as Local Build
    participant CI as CI Workflow
    participant Bin as Compiled Binary
    participant Pub as NPM Publish

    Dev->>Pre: bun run pre-release
    Pre->>Pre: verify required externals in dependencies
    Pre->>Pre: require.resolve checks
    Pre->>Build: bun run build:local (MODELS_DEV_API_JSON=fixture)
    Build->>Bin: produce platform binaries (dist/)
    Pre->>Bin: execute --version (NODE_PATH set)
    Bin-->>Pre: exit 0 / version output
    alt all checks pass
        Dev->>CI: push tag
        CI->>Build: build linux-x64
        CI->>Bin: execute --version (NODE_PATH set)
        Bin-->>CI: exit 0
        CI->>Bin: execute --version (publish-time check)
        Bin-->>CI: exit 0
        CI->>Pub: proceed to publish
        Pub-->>CI: npm package published
    else any check fails
        CI-->>CI: fail job, block publish
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 I hopped through builds and CI trees,
I sniffed the binaries for sneeze,
Pre-release checks and smoke in line,
No more broken starts at publish time.
thump-thump, happy release!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding smoke tests to prevent broken binary publishes, directly addressing the core objective.
Description check ✅ Passed The description covers all template sections: a detailed summary explaining the three-layer defense, type of change marked as bug fix, linked issue #462, verification details with test results, and all checklist items completed.
Linked Issues check ✅ Passed All coding requirements from issue #462 are met: CI smoke tests in workflows [.github/workflows/release.yml], build-time verification [packages/opencode/script/build.ts], local pre-release script [packages/opencode/script/pre-release-check.ts], and comprehensive test suite [smoke-test-binary.test.ts].
Out of Scope Changes check ✅ Passed All changes directly support the three-layer defense objective: CI workflows, build verification, pre-release script, documentation updates, and smoke tests—no extraneous or out-of-scope modifications present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/release-smoke-test-guard

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/opencode/script/pre-release-check.ts (1)

41-42: Keep requiredExternals in one place.

This redefines the list already introduced in packages/opencode/script/build.ts. If the build list grows and only that file is updated, bun run pre-release can still green-light the release because build:local only warns on missing dependencies outside release mode. Please move the list to a tiny shared module and import it from both scripts.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/script/pre-release-check.ts` around lines 41 - 42, The
duplicate requiredExternals array should be centralized: create a tiny shared
module that exports a named constant requiredExternals (e.g., export const
requiredExternals = ["@altimateai/altimate-core"]), then replace the local
declaration in pre-release-check.ts and the one in build.ts with imports from
that shared module (import { requiredExternals } from "./requiredExternals"),
removing the duplicated definition so both scripts use the single source of
truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/release.yml:
- Around line 193-202: The pre-publish smoke test's artifact lookup uses find
with pattern "*/linux-x64/*/altimate" which fails because the built binary
resides under
packages/opencode/dist/@altimateai/altimate-code-linux-x64/bin/altimate; update
the BINARY find pattern in the "Pre-publish smoke test" step to match the actual
output layout (e.g., search for paths containing
"altimate-code-linux-x64/bin/altimate" or a wildcard that covers
"*linux-x64*/bin/altimate") so BINARY picks the correct file, then keep the
chmod +x and version check logic as-is (refer to the BINARY assignment and the
subsequent chmod +x "$BINARY" and "$BINARY" --version lines).

In `@packages/opencode/script/pre-release-check.ts`:
- Around line 85-125: searchDist currently only looks for "bin/altimate" and the
smoke-test sets NODE_PATH using ":" which breaks on Windows; update searchDist
(and the equivalent logic in
packages/opencode/test/install/smoke-test-binary.test.ts) to consider both
"bin/altimate" and "bin/altimate.exe" (or use path.basename checks) when probing
dist directories (symbols: function searchDist, variable binaryPath) and replace
the hardcoded ":" with path.delimiter when building NODE_PATH (symbol: NODE_PATH
environment assignment / nodePaths.join(...)); keep behavior otherwise the same
so smokeResult/spawnSync continues to call binaryPath with ["--version"] and
other env vars intact.

---

Nitpick comments:
In `@packages/opencode/script/pre-release-check.ts`:
- Around line 41-42: The duplicate requiredExternals array should be
centralized: create a tiny shared module that exports a named constant
requiredExternals (e.g., export const requiredExternals =
["@altimateai/altimate-core"]), then replace the local declaration in
pre-release-check.ts and the one in build.ts with imports from that shared
module (import { requiredExternals } from "./requiredExternals"), removing the
duplicated definition so both scripts use the single source of truth.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 57482b16-8c9b-4937-ae53-012642c2eb93

📥 Commits

Reviewing files that changed from the base of the PR and between bbae377 and b3baea0.

📒 Files selected for processing (7)
  • .github/meta/commit.txt
  • .github/workflows/release.yml
  • docs/RELEASING.md
  • packages/opencode/package.json
  • packages/opencode/script/build.ts
  • packages/opencode/script/pre-release-check.ts
  • packages/opencode/test/install/smoke-test-binary.test.ts

….delimiter`, binary names

- Use `*altimate-code-linux-x64/bin/altimate` in pre-publish find pattern
  for clarity (old pattern worked but was ambiguous)
- Use `path.delimiter` instead of hardcoded `:` for NODE_PATH in both
  `pre-release-check.ts` and `smoke-test-binary.test.ts`
- Handle Windows `altimate.exe` binary name in `searchDist()` functions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@anandgupta42 anandgupta42 merged commit 9da78de into main Mar 25, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: add release smoke tests to prevent broken binary publishes

1 participant