Files
orca/config/scripts/ci-dependency-download-cache.test.mjs
T
Neil e86cba888b build: reduce native dependency installs to the host platform (#20420)
* Reduce native dependency installs to the host platform

* Remove install policy documentation

* Guard cross-arch packaging and scope release installs to the runner

electron-builder only logs a warning for a missing extraResources source,
so a host-only install silently shipped a foreign-arch slice without its
natives — `pnpm build:mac` on Apple Silicon produced an x64 DMG with no
sherpa-onnx-darwin-x64 and no @parcel/watcher-darwin-x64. The previous
beforePack hook covered only win32.

- Add assertPackagedNativeVariantsInstalled, an arch-aware check over the
  target's sherpa-onnx, @parcel/watcher, and (on Windows) node-gyp addons.
  beforePack now runs it for every platform, with remedies split: another
  architecture comes from install:release, the os:win32 addons need a
  Windows host.
- Drop --os from the release installs. Every packaging job already runs on
  a runner whose OS matches its target, so only the macOS lanes need extra
  breadth, and only on CPU for their x64+arm64 config. Windows and Linux
  packaging return to a plain host-only install.
- Add --frozen-lockfile to install:release so a bare run cannot rewrite
  the lockfile.
- Restore the install policy reference doc and the CONTRIBUTING note, plus
  the rationale comments dropped from the runtime contract test.
- Gate the packaging-closure assertions on whether the Windows addons are
  installed rather than on the host OS, so a cross-arch install exercises
  them off Windows too.
- Make the workflow contract test read `run:` steps as well as retry-action
  commands, and enforce host-only scoping on the non-macOS packaging lanes.
- Remove the unreferenced install measurement script; its numbers live in
  the policy doc.

* Track the install policy doc and index it from AGENTS.md

docs/** is ignored behind a per-file allow-list, so the new reference doc
was only committed via git add -f and future edits would be skipped. Add
it to the allow-list and give it an AGENTS.md entry like every other
tracked reference doc, so the host-only install rule is discoverable
before someone packages a second architecture.

* Route Windows-lane removals through the retrying helper

Adding these four specs to the PR Windows lane pulled them into the
windows-lane-tree-removal-boundary ratchet, which failed on 20 raw
recursive removals. On Windows a bare rmSync races a handle the OS has
not released, throwing EPERM after the assertions already passed and
reporting a green test as a lane failure.

* Adapt the packaging guard to the vendored Windows registry addon

main vendored windows-native-registry as the workspace package
@orca/windows-registry (#20438). A workspace link resolves on every
host, so including it in the installed-Windows-addons checks proved
nothing. @vscode/windows-process-tree is the only os: win32 npm addon
left, so it alone decides whether the win32 resource plan resolves.
2026-09-12 21:25:03 -07:00

77 lines
3.4 KiB
JavaScript

import { readFileSync } from 'node:fs'
import { describe, expect, it } from 'vitest'
import { parse } from 'yaml'
const read = (path) => parse(readFileSync(path, 'utf8'))
const workflow = (name) => read(`.github/workflows/${name}.yml`)
const action = read('.github/actions/install-node-dependencies/action.yml')
describe('CI dependency download caches', () => {
it('scopes desktop stores to the root lockfile and lets mixed installs opt in', () => {
expect(action.inputs['cache-dependency-path'].default).toBe('pnpm-lock.yaml')
for (const step of action.runs.steps.filter((step) => step.uses === 'actions/setup-node@v6')) {
expect(step.with.cache).toBe('pnpm')
expect(step.with['cache-dependency-path']).toBe('${{ inputs.cache-dependency-path }}')
}
const install = action.runs.steps.find((step) => step.name === 'Install dependencies')
expect(install.if).toBeUndefined()
expect(install.run).toContain('pnpm install --frozen-lockfile --ignore-scripts')
expect(install.run).toContain(
'diff --exit-code -- package.json pnpm-lock.yaml pnpm-workspace.yaml'
)
const mobile = workflow('mobile').jobs.verify.steps.find((step) =>
step.uses?.includes('install-node-dependencies')
)
expect(mobile.with['cache-dependency-path'].trim().split('\n')).toEqual([
'pnpm-lock.yaml',
'mobile/pnpm-lock.yaml'
])
})
})
describe('release install targets', () => {
const macCpuFlag = '--cpu=current,x64,arm64'
// Both shapes: `run:` steps and steps wrapped in nick-fields/retry (`with.command`).
const installSteps = (name) =>
Object.values(workflow(name).jobs)
.flatMap((job) => job.steps ?? [])
.map((step) => step.with?.command ?? step.run)
.filter((command) => typeof command === 'string' && command.includes('pnpm install '))
it.each(['adhoc-mac-build', 'daily-mac-build', 'hourly-mac-build', 'release-mac-build'])(
'%s installs both mac CPU variants for the x64+arm64 package config',
(name) => {
const installs = installSteps(name)
expect(installs.length).toBeGreaterThan(0)
expect(installs.some((command) => command.includes(macCpuFlag))).toBe(true)
}
)
it.each(['release-cut', 'dev-channel-win-build', 'windows-signing-rehearsal'])(
'%s keeps installs scoped to the runner host',
(name) => {
const installs = installSteps(name)
expect(installs.length).toBeGreaterThan(0)
for (const command of installs) {
expect(command).not.toContain('--os=')
expect(command).not.toContain('--cpu=')
}
}
)
it('offers the mac CPU targets for local packaging without touching the lockfile', () => {
const script = JSON.parse(readFileSync('package.json', 'utf8')).scripts['install:release']
expect(script).toContain('--frozen-lockfile')
expect(script).toContain(macCpuFlag)
})
it('keeps installed Windows addon checks in the Windows CI lane', () => {
const steps = Object.values(workflow('pr').jobs).flatMap((job) => job.steps ?? [])
const test = steps.find((step) => step.name === 'Test Windows-specific boundaries')
expect(test.run).toContain('config/scripts/windows-process-tree-gyp-path.test.mjs')
expect(test.run).toContain('config/scripts/windows-process-tree-gyp-rebuild.test.mjs')
expect(test.run).toContain('config/scripts/package-electron-runtime-contract.test.mjs')
expect(test.run).toContain('config/scripts/electron-builder-runtime-resources.test.mjs')
})
})