Files
hermes-agent/apps/desktop/scripts/build.mjs
Siddharth Balyan 86f54bfdaa Flavored desktop builds no longer stamp themselves dirty (#129540)
* fix(bundles): write the build stamp before flavored icons land

A flavored build (commit, canary, preview channel) copies its icons over the
committed apps/desktop/assets before packaging. write-build-stamp ran after
that copy, so its git check saw modified tracked files and stamped the
bundle dirty, and the Windows smoke refused it (stamp.dirty: true != false),
which keeps a channel from promoting the build. Stamp first, in both the CI
driver (scripts/bundles/desktop.py) and the source build (build.mjs). The
stamp reads no artwork, so its content is unchanged.

* test(bundles): pin the build stamp ahead of the flavored icon copy

buildSourceDesktop copies flavored icons over committed files in
apps/desktop/assets. write-build-stamp asks git whether tracked files
changed, so it has to run while the committed bytes are still there. The
test records what the stamp step sees through the injectable run seam.
It fails on the old order (sees the flavored icon) and passes on the new one.
2026-10-01 01:30:18 +05:30

34 lines
1.8 KiB
JavaScript

// npm's source-development composition; the compiler consumes prepared inputs.
import { execFileSync } from 'node:child_process'
import { cpSync } from 'node:fs'
import { join, resolve } from 'node:path'
import { parseArgs } from 'node:util'
import { isMain, repoRoot } from '../../../scripts/build/frontend-common.mjs'
export function buildSourceDesktop({ source = repoRoot, icons, run = execFileSync } = {}) {
source = resolve(source)
const app = join(source, 'apps/desktop')
const step = (script, args = []) => run(process.execPath, [join(source, script), ...args], { cwd: app, stdio: 'inherit' })
step('apps/desktop/scripts/assert-root-install.mjs')
// Stamp before the flavored icons land: they overwrite committed files, and
// the stamp's git check would then call the checkout dirty.
step('apps/desktop/scripts/write-build-stamp.mjs')
// Default-brand icons are committed; only flavored release builds pass --icons.
icons = resolve(icons ?? source)
if (icons !== source) {
// electron-builder consumes packaging artwork in the workspace. Copy the
// prepared pixels; do not create another Python environment to redraw them.
cpSync(join(icons, 'apps/desktop/assets'), join(app, 'assets'), { recursive: true })
}
// locales/_keys.desktop.json is a committed artifact (i18n-keys.test.mjs pins it to en.ts);
// the build must not write into the checkout — a dirty tree breaks `hermes update`.
step('apps/desktop/scripts/stage-native-deps.mjs')
step('scripts/build/desktop.mjs', ['--source', source, '--icons', icons,
'--stamp', join(app, 'build/install-stamp.json'), '--native-deps', join(app, 'build/native-deps'), '--out', join(app, 'dist')])
}
if (isMain(import.meta.url)) {
const { values } = parseArgs({ options: { icons: { type: 'string' } } })
buildSourceDesktop(values)
}