perf(ci): use four ARM test workers and remove repeated compilation (#23685)

* ci: benchmark per-job Node compile caching on full unit shards

* ci: measure unit shards with three and four workers

* ci: benchmark localization extraction CLI patch

* perf(build): reuse identical relay bundles across platforms

* ci: compare Vitest 4 and 5 on complete ARM shards

* perf(ci): upgrade localization extraction to skip irrelevant syntax walks

* perf(ci): use all four ARM cores and remove benchmark workflows

* ci: preserve failures while capturing unit source revision

* fix(ci): preserve commented and escaped localization calls

* ci: remove corrected localization benchmark harness
This commit is contained in:
Neil
2026-09-28 14:05:30 -07:00
committed by GitHub
parent fe34acda3b
commit 0f52bb8be5
8 changed files with 172 additions and 37 deletions
+4 -2
View File
@@ -83,9 +83,11 @@ jobs:
ORCA_BALANCE_UNIT_SHARDS: '1'
ORCA_BACKGROUND_LAUNCH: '1'
run: |
export ORCA_SHARD_SOURCE_SHA="$(git rev-parse HEAD)"
ORCA_SHARD_SOURCE_SHA="$(git rev-parse HEAD)"
export ORCA_SHARD_SOURCE_SHA
pnpm exec vitest run --config config/vitest.config.ts \
--shard=${{ matrix.shard.index }}/${{ matrix.shard.count }}
--shard=${{ matrix.shard.index }}/${{ matrix.shard.count }} \
${{ inputs.runner == 'ubuntu-24.04-arm' && '--maxWorkers=4' || '' }}
- name: Upload unit shard assignment
if: always()
+44
View File
@@ -0,0 +1,44 @@
diff --git a/dist/cjs/extractor/core/extractor.js b/dist/cjs/extractor/core/extractor.js
index 6d61ade2471c20bf1a253e3784bfadcb01440545..c1b001e78a215f89a8d4da1756a87562a5a6e723 100644
--- a/dist/cjs/extractor/core/extractor.js
+++ b/dist/cjs/extractor/core/extractor.js
@@ -143,6 +143,8 @@ const extractionSiteRegexes = new WeakMap();
* @internal
*/
function mayContainExtractionSite(code, config) {
+ // Escaped identifiers need the parser; comments can separate a name from its call.
+ if (code.includes('\\u')) return true;
let re = extractionSiteRegexes.get(config);
if (!re) {
const calls = new Set(['t']);
@@ -160,7 +162,7 @@ function mayContainExtractionSite(code, config) {
for (const component of config.extract.transComponents || ['Trans'])
names.add(component.split('.').pop());
const alt = (set) => [...set].map(s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
- re = new RegExp(`(?<!\\w)(?:(?:${alt(calls)})\\s*(?:\\?\\.\\s*)?[(<]|(?:${alt(names)})(?![\\w$]))`);
+ re = new RegExp(`(?<![\\w$])(?:${alt(calls)}|${alt(names)})(?![\\w$])`);
extractionSiteRegexes.set(config, re);
}
return re.test(code);
diff --git a/dist/esm/extractor/core/extractor.js b/dist/esm/extractor/core/extractor.js
index 910bdb6e25e26c01ea6127191f1a00c7089693c1..00da4a6a7acb6c3da8d4b6fe7be106c409542f8d 100644
--- a/dist/esm/extractor/core/extractor.js
+++ b/dist/esm/extractor/core/extractor.js
@@ -141,6 +141,8 @@ const extractionSiteRegexes = new WeakMap();
* @internal
*/
function mayContainExtractionSite(code, config) {
+ // Escaped identifiers need the parser; comments can separate a name from its call.
+ if (code.includes('\\u')) return true;
let re = extractionSiteRegexes.get(config);
if (!re) {
const calls = new Set(['t']);
@@ -158,7 +160,7 @@ function mayContainExtractionSite(code, config) {
for (const component of config.extract.transComponents || ['Trans'])
names.add(component.split('.').pop());
const alt = (set) => [...set].map(s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
- re = new RegExp(`(?<!\\w)(?:(?:${alt(calls)})\\s*(?:\\?\\.\\s*)?[(<]|(?:${alt(names)})(?![\\w$]))`);
+ re = new RegExp(`(?<![\\w$])(?:${alt(calls)}|${alt(names)})(?![\\w$])`);
extractionSiteRegexes.set(config, re);
}
return re.test(code);
+39 -23
View File
@@ -118,13 +118,7 @@ const OUT_ROOT = process.env.ORCA_RELAY_OUT_ROOT ?? join(ROOT, 'out', 'relay')
const RELAY_VERSION = '0.1.0'
for (const platform of RELAY_BUILD_PLATFORMS) {
const outDir = join(OUT_ROOT, platform)
// Why: a stale companion left by an earlier build would otherwise satisfy the
// manifest check and be hashed into .version, shipping mixed-generation bytes.
rmSync(outDir, { recursive: true, force: true })
mkdirSync(outDir, { recursive: true })
async function buildRelayBundles(outDir) {
await build({
entryPoints: [RELAY_ENTRY],
bundle: true,
@@ -142,22 +136,6 @@ for (const platform of RELAY_BUILD_PLATFORMS) {
}
})
if (isWindowsRelayPlatform(platform)) {
copyFileSync(
NODE_PTY_CONSOLE_LIST_PATCH_SOURCE,
join(outDir, NODE_PTY_CONSOLE_LIST_PATCH_FILENAME)
)
copyFileSync(
NODE_PTY_WINDOWS_TEARDOWN_PATCH_SOURCE,
join(outDir, NODE_PTY_WINDOWS_TEARDOWN_PATCH_FILENAME)
)
}
copyFileSync(
NODE_PTY_MASTER_CLOEXEC_PATCH_SOURCE,
join(outDir, NODE_PTY_MASTER_CLOEXEC_PATCH_FILENAME)
)
stageWindowsProcessTreeAddon(platform, outDir)
await build({
entryPoints: [WATCHER_ENTRY],
bundle: true,
@@ -234,6 +212,44 @@ for (const platform of RELAY_BUILD_PLATFORMS) {
'process.env.NODE_ENV': '"production"'
}
})
}
let bundledSourceDir
let bundledFilenames = []
for (const platform of RELAY_BUILD_PLATFORMS) {
const outDir = join(OUT_ROOT, platform)
// Why: a stale companion left by an earlier build would otherwise satisfy the
// manifest check and be hashed into .version, shipping mixed-generation bytes.
rmSync(outDir, { recursive: true, force: true })
mkdirSync(outDir, { recursive: true })
// The JavaScript selects its host at runtime; only native addons and patches vary.
if (bundledSourceDir) {
for (const filename of bundledFilenames) {
copyFileSync(join(bundledSourceDir, filename), join(outDir, filename))
}
} else {
await buildRelayBundles(outDir)
bundledSourceDir = outDir
bundledFilenames = readdirSync(outDir)
}
if (isWindowsRelayPlatform(platform)) {
copyFileSync(
NODE_PTY_CONSOLE_LIST_PATCH_SOURCE,
join(outDir, NODE_PTY_CONSOLE_LIST_PATCH_FILENAME)
)
copyFileSync(
NODE_PTY_WINDOWS_TEARDOWN_PATCH_SOURCE,
join(outDir, NODE_PTY_WINDOWS_TEARDOWN_PATCH_FILENAME)
)
}
copyFileSync(
NODE_PTY_MASTER_CLOEXEC_PATCH_SOURCE,
join(outDir, NODE_PTY_MASTER_CLOEXEC_PATCH_FILENAME)
)
stageWindowsProcessTreeAddon(platform, outDir)
// Why: include a content hash so the deploy check detects code changes even
// when RELAY_VERSION hasn't been bumped. Hashing the whole manifest means a
@@ -0,0 +1,56 @@
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { createRequire } from 'node:module'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { findKeys } from 'i18next-cli'
import { describe, expect, it } from 'vitest'
const require = createRequire(import.meta.url)
const commonJsFindKeys = require('i18next-cli').findKeys
const calls = {
normal: "translate('probe.normal', 'Normal')",
block: "translate /* comment */ ('probe.block', 'Block')",
line: "translate\n// comment\n('probe.line', 'Line')",
member: "i18n./* member */t /* call */ ('probe.member', 'Member')",
optional: "translate?. /* optional */ ('probe.optional', 'Optional')",
generic: "translate /* generic */ <string>('probe.generic', 'Generic')",
dollar: "$api.t /* member */ ('probe.dollar', 'Dollar')",
unicode: "transl\\u0061te('probe.unicode', 'Unicode')"
}
describe.each([
['ES module', findKeys],
['CommonJS', commonJsFindKeys]
])('localization extraction through %s', (_name, extractKeys) => {
it('keeps keys in calls containing comments or escaped identifiers', async () => {
const directory = mkdtempSync(join(tmpdir(), 'orca-extraction-syntax-'))
try {
for (const [name, source] of Object.entries(calls)) {
writeFileSync(join(directory, `${name}.ts`), source)
}
const errors = []
const result = await extractKeys(
{
locales: ['en'],
extract: {
input: [join(directory, '*.ts').replaceAll('\\', '/')],
defaultNS: false,
functions: ['t', '*.t', 'translate'],
disablePlurals: true
}
},
undefined,
errors
)
expect(errors).toEqual([])
expect([...result.allKeys.values()].map((entry) => entry.key).sort()).toEqual(
Object.keys(calls)
.map((name) => `probe.${name}`)
.sort()
)
} finally {
rmSync(directory, { recursive: true, force: true })
}
})
})
@@ -5,7 +5,15 @@
// and never forks.
import { execFileSync } from 'node:child_process'
import { createHash } from 'node:crypto'
import { existsSync, mkdtempSync, readdirSync, readFileSync, rmSync } from 'node:fs'
import {
existsSync,
mkdirSync,
mkdtempSync,
readdirSync,
readFileSync,
rmSync,
writeFileSync
} from 'node:fs'
import { tmpdir } from 'node:os'
import { join, resolve } from 'node:path'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
@@ -23,6 +31,12 @@ const projectDir = resolve(import.meta.dirname, '../..')
const relayOutDir = mkdtempSync(join(tmpdir(), 'orca-relay-contract-'))
beforeAll(() => {
// A repeated build must not copy stale companions into the other platform bundles.
for (const platform of RELAY_BUILD_PLATFORMS) {
const outDir = join(relayOutDir, platform)
mkdirSync(outDir, { recursive: true })
writeFileSync(join(outDir, 'stale-companion.js'), 'throw new Error("stale")')
}
execFileSync('node', [join(projectDir, 'config', 'scripts', 'build-relay.mjs')], {
cwd: projectDir,
stdio: 'pipe',
+1 -1
View File
@@ -266,7 +266,7 @@
"happy-dom": "^20.11.8",
"html-to-image": "^1.11.13",
"husky": "^9.1.7",
"i18next-cli": "1.74.1",
"i18next-cli": "1.74.2",
"katex": "^0.16.45",
"lint-staged": "^16.4.0",
"lowlight": "^3.3.0",
+11 -10
View File
@@ -109,6 +109,7 @@ overrides:
monaco-editor>dompurify: 3.4.15
patchedDependencies:
i18next-cli@1.74.2: 7955b89d3aa229f477408608d331f78c85148a85a85913729f89fac65ad8b207
'@vscode/windows-process-tree@0.8.0': b4be93859cefb159949d9cf05f97fa91a221dff0f793a6f03d02d78ae5b32035
'@xterm/addon-image@0.10.0-beta.300': 5fc280019957573eefe8daa2969534d6090ddb29c6b5842b8f22e99dc1ce3146
'@xterm/addon-ligatures@0.11.0-beta.300': 47405b9994b5acf1b4e90b49250358c1ca03649854d59560e7732b72fe336920
@@ -395,8 +396,8 @@ importers:
specifier: ^9.1.7
version: 9.1.7
i18next-cli:
specifier: 1.74.1
version: 1.74.1(@types/node@25.9.5)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(typescript@7.0.2)
specifier: 1.74.2
version: 1.74.2(patch_hash=7955b89d3aa229f477408608d331f78c85148a85a85913729f89fac65ad8b207)(@types/node@25.9.5)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(typescript@7.0.2)
katex:
specifier: ^0.16.45
version: 0.16.45
@@ -5339,13 +5340,13 @@ packages:
engines: {node: '>=18'}
hasBin: true
i18next-cli@1.74.1:
resolution: {integrity: sha512-8OEbo4jfn4r4/QwieyAvoLWV/rJW2OR6SG09I12jA6kffyhUNsyrH6OaA4bumLIWkdBaGySbiFm0wj1k19N/jA==}
i18next-cli@1.74.2:
resolution: {integrity: sha512-y32hOiVNLs85f+TKCl4XqERjD0dFy274IOEXe7/Zyp+WMaQC9VhF33JLO0hQZZKK4PUmYwbRDXaSObeE3PbsmA==}
engines: {node: '>=22'}
hasBin: true
i18next-resources-for-ts@2.1.0:
resolution: {integrity: sha512-n5UexwEVt0OoIAhG2MWpSnAVJW1U8mQrQTmXyxc5DMAx+NLhcLZhSMJo/FnUsA5JQ3obTYqTgB7YIuZKWpDgow==}
i18next-resources-for-ts@2.1.1:
resolution: {integrity: sha512-Xhz8S8dtNIPawzeWdmssnsII1JYsbvPWOLmstJakNcgKSFLCneA+xN7qajj/zlk5nf9sx1KGDTx8RNZ73h68tw==}
hasBin: true
i18next@26.3.1:
@@ -12377,7 +12378,7 @@ snapshots:
husky@9.1.7: {}
i18next-cli@1.74.1(@types/node@25.9.5)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(typescript@7.0.2):
i18next-cli@1.74.2(patch_hash=7955b89d3aa229f477408608d331f78c85148a85a85913729f89fac65ad8b207)(@types/node@25.9.5)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(typescript@7.0.2):
dependencies:
'@croct/json5-parser': 0.2.2
'@swc/core': 1.16.2
@@ -12386,7 +12387,7 @@ snapshots:
execa: 10.0.1
glob: 13.0.6
i18next: 26.4.2(typescript@7.0.2)
i18next-resources-for-ts: 2.1.0
i18next-resources-for-ts: 2.1.1
inquirer: 14.2.2(@types/node@25.9.5)
jiti: 2.7.0
jsonc-parser: 3.3.1
@@ -12403,10 +12404,10 @@ snapshots:
- react-native
- typescript
i18next-resources-for-ts@2.1.0:
i18next-resources-for-ts@2.1.1:
dependencies:
'@babel/runtime': 7.29.7
'@swc/core': 1.15.46
'@swc/core': 1.16.2
chokidar: 5.0.0
yaml: 2.9.1
transitivePeerDependencies:
+2
View File
@@ -17,6 +17,7 @@ minimumReleaseAgeExclude:
- pdfjs-dist@6.3.289
- zod@4.5.4
- '@shadcn/lint@0.1.0'
- i18next-cli@1.74.2
shamefullyHoist: true
# Orca always launches the user's own resolved Claude CLI via
@@ -68,3 +69,4 @@ patchedDependencies:
'@xterm/xterm@6.1.0-beta.303': config/patches/@xterm__xterm@6.1.0-beta.303.patch
lint-staged@16.4.0: config/patches/lint-staged@16.4.0.patch
'@vscode/windows-process-tree@0.8.0': config/patches/@vscode__windows-process-tree@0.8.0.patch
i18next-cli@1.74.2: config/patches/i18next-cli@1.74.2.patch