mirror of
https://github.com/stablyai/orca.git
synced 2026-10-01 00:02:10 +00:00
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:
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
@@ -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
@@ -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",
|
||||
|
||||
Generated
+11
-10
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user