fix(release): publish binaries — checkout CHANGELOG + externalize @fusion/engine (#1753)
## Problem
The latest release **v0.47.0 published 0 binaries**, and every desktop
build leg has been failing.
Two independent bugs in the release pipeline:
### 1. `github-release` job crashed → no binaries published
The job downloads artifacts but never checks out the repo. A step added
2026-06-24 (`Extract release notes from CHANGELOG`) does
`fs.readFileSync('CHANGELOG.md')`, which threw `ENOENT: no such file or
directory` and failed the whole job — so v0.47.0 shipped **0 assets**
even though every bun build leg succeeded. (v0.45/v0.46 predated this
step and still published 21 assets each.)
### 2. Desktop Windows EXE / macOS DMG legs failing
`packages/desktop/src/local-runtime.ts` dynamically imports
`@fusion/engine`, but engine was missing from the esbuild externals list
(only `@fusion/core` and `@fusion/dashboard` were there). esbuild
followed the import and tried to bundle engine's transitive `node-pty`
native binaries:
```
X [ERROR] No loader is configured for ".node" files:
.../@homebridge/node-pty-prebuilt-multiarch/build/Release/pty.node
```
## Fix
- **`.github/workflows/release.yml`** — sparse-checkout `CHANGELOG.md`
in the `github-release` job, and harden the notes script to fall back to
a plain `Release vX.Y.Z` body instead of crashing the publish.
- **`packages/desktop/scripts/build.ts`** — externalize `@fusion/engine`
alongside the other workspace packages; it resolves from `node_modules`
at runtime, same as `core`/`dashboard`.
## Verification
- `pnpm build` runs clean locally — `dist/main.js` (623 kB) builds with
no `.node` loader error.
- YAML validated; `pnpm check:changesets` passes.
## Changeset
`"@runfusion/fusion": patch` (category `fix`) — restores
binary/installer publishing.
## Follow-up
These take effect on the next release. To backfill v0.47.0's missing
binaries, after merge delete + re-push the `v0.47.0` tag (the
tag-triggered run uses the workflow file at the tag).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Fixed release publishing so binary and desktop installer artifacts are
published correctly again.
* Improved release note generation to fall back gracefully when
changelog details aren’t available, preventing failed releases.
* Updated desktop app bundling to avoid packaging native dependencies
incorrectly, reducing build and packaging issues.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
7
.changeset/fix-release-binary-publish.md
Normal file
7
.changeset/fix-release-binary-publish.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@runfusion/fusion": patch
|
||||
---
|
||||
|
||||
summary: Fix release pipeline so binaries and desktop installers publish again.
|
||||
category: fix
|
||||
dev: github-release job sparse-checks-out CHANGELOG.md (was missing a checkout, so the release-notes step threw ENOENT and published 0 assets on v0.47.0); desktop esbuild build externalizes @fusion/engine so it no longer tries to bundle node-pty's native .node binaries.
|
||||
25
.github/workflows/release.yml
vendored
25
.github/workflows/release.yml
vendored
@@ -373,6 +373,18 @@ jobs:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
# FNXC:Changelog 2026-06-25-09:30:
|
||||
# The release-notes step reads root CHANGELOG.md, so this job needs the repo
|
||||
# tree — not just downloaded artifacts. Without this checkout the notes step
|
||||
# threw `ENOENT: CHANGELOG.md` and failed the whole job, publishing zero
|
||||
# binaries on v0.47.0 even though every bun build leg succeeded. Sparse-checkout
|
||||
# only CHANGELOG.md to keep the job lean; no submodules or full history needed.
|
||||
- name: Checkout CHANGELOG for release notes
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: CHANGELOG.md
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -401,18 +413,25 @@ jobs:
|
||||
id: notes
|
||||
run: |
|
||||
VERSION="${GITHUB_REF#refs/tags/v}"
|
||||
# FNXC:Changelog 2026-06-25-09:30:
|
||||
# Never let release-note extraction fail the publish. A missing/unreadable
|
||||
# CHANGELOG or absent version section falls back to a plain "Release vX.Y.Z"
|
||||
# body so binaries still ship — matching the job's "partial over none" intent.
|
||||
NOTES=$(node -e "
|
||||
const fs = require('fs');
|
||||
const content = fs.readFileSync('CHANGELOG.md', 'utf8');
|
||||
const fallback = 'Release v${VERSION}';
|
||||
let content = '';
|
||||
try { content = fs.readFileSync('CHANGELOG.md', 'utf8'); }
|
||||
catch (e) { console.log(fallback); process.exit(0); }
|
||||
const lines = content.split(/\r?\n/);
|
||||
const header = '## ' + '${VERSION}';
|
||||
const start = lines.findIndex(l => l.trim() === header);
|
||||
if (start === -1) { console.log('Release v${VERSION}'); process.exit(0); }
|
||||
if (start === -1) { console.log(fallback); process.exit(0); }
|
||||
let end = lines.length;
|
||||
for (let i = start + 1; i < lines.length; i++) {
|
||||
if (lines[i].startsWith('## ')) { end = i; break; }
|
||||
}
|
||||
console.log(lines.slice(start + 1, end).join('\n').trim() || 'Release v${VERSION}');
|
||||
console.log(lines.slice(start + 1, end).join('\n').trim() || fallback);
|
||||
")
|
||||
echo "$NOTES" > /tmp/release-notes.md
|
||||
|
||||
|
||||
@@ -5,10 +5,18 @@ import { buildDashboardClient, packageRoot, workspaceRoot } from "./workspace-to
|
||||
const dashboardClientDir = join(workspaceRoot, "packages", "dashboard", "dist", "client");
|
||||
const desktopDistDir = join(packageRoot, "dist");
|
||||
const desktopClientDistDir = join(desktopDistDir, "client");
|
||||
// FNXC:DesktopBuild 2026-06-25-09:45:
|
||||
// Every workspace @fusion/* package and native (.node) module must stay external
|
||||
// to the Electron main/preload bundles — they resolve from node_modules at runtime.
|
||||
// @fusion/engine was missing here, so esbuild followed local-runtime.ts's dynamic
|
||||
// `import("@fusion/engine")` and tried to bundle engine's transitive node-pty
|
||||
// (@homebridge/node-pty-prebuilt-multiarch) native binaries, failing with
|
||||
// "No loader is configured for .node files" and breaking every desktop release build.
|
||||
const sharedExternals = [
|
||||
"electron",
|
||||
"@fusion/core",
|
||||
"@fusion/dashboard",
|
||||
"@fusion/engine",
|
||||
"better-sqlite3",
|
||||
];
|
||||
const mainExternals = sharedExternals;
|
||||
|
||||
Reference in New Issue
Block a user