mirror of
https://github.com/stablyai/orca.git
synced 2026-10-03 16:02:11 +00:00
Skip slower Windows root package-store restores in CI (#24885)
* Skip slower Windows root package-store restores in CI * Update reviewed mobile dependency-store cache expression
This commit is contained in:
@@ -2,6 +2,10 @@ name: Install Node dependencies
|
||||
description: Installs the Node toolchain and repository dependencies for CI jobs, with optional Electron archive caching.
|
||||
|
||||
inputs:
|
||||
cache-pnpm-store:
|
||||
description: Restore or save the pnpm download store; verification and native caches are independent.
|
||||
required: false
|
||||
default: 'true'
|
||||
cache-pnpm-verification:
|
||||
description: Restore pnpm's policy-checked lockfile verification record.
|
||||
required: false
|
||||
@@ -69,7 +73,7 @@ runs:
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: package.json
|
||||
cache: ${{ github.event_name != 'pull_request' && 'pnpm' || '' }}
|
||||
cache: ${{ github.event_name != 'pull_request' && inputs.cache-pnpm-store != 'false' && 'pnpm' || '' }}
|
||||
cache-dependency-path: ${{ inputs.cache-dependency-path }}
|
||||
package-manager-cache: false
|
||||
|
||||
@@ -79,7 +83,7 @@ runs:
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
cache: ${{ github.event_name != 'pull_request' && 'pnpm' || '' }}
|
||||
cache: ${{ github.event_name != 'pull_request' && inputs.cache-pnpm-store != 'false' && 'pnpm' || '' }}
|
||||
cache-dependency-path: ${{ inputs.cache-dependency-path }}
|
||||
package-manager-cache: false
|
||||
|
||||
@@ -87,8 +91,10 @@ runs:
|
||||
- name: Resolve pnpm download store
|
||||
id: pnpm-store
|
||||
if: >-
|
||||
github.event_name == 'pull_request' &&
|
||||
(runner.os != 'Windows' || runner.arch != 'X64' || !contains(inputs.cache-dependency-path, 'mobile/pnpm-lock.yaml'))
|
||||
github.event_name == 'pull_request' && inputs.cache-pnpm-store != 'false' &&
|
||||
(runner.os != 'Windows' ||
|
||||
!(runner.arch == 'X64' && contains(inputs.cache-dependency-path, 'mobile/pnpm-lock.yaml')) &&
|
||||
!((runner.arch == 'X64' || runner.arch == 'ARM64') && inputs.cache-dependency-path == 'pnpm-lock.yaml'))
|
||||
shell: bash
|
||||
env:
|
||||
LOCKFILE_HASH: ${{ hashFiles(inputs.cache-dependency-path) }}
|
||||
@@ -100,11 +106,13 @@ runs:
|
||||
printf 'arch=%s\n' "$(node -p 'require("node:os").arch()')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Match setup-node's key and path so existing default-branch stores remain reusable.
|
||||
# Hosted Windows x64 mixed installs cost less than restoring their root/mobile store.
|
||||
# Measured Windows installs cost less than unpacking their download store.
|
||||
- name: Restore pnpm download store without saving
|
||||
if: >-
|
||||
github.event_name == 'pull_request' &&
|
||||
(runner.os != 'Windows' || runner.arch != 'X64' || !contains(inputs.cache-dependency-path, 'mobile/pnpm-lock.yaml'))
|
||||
github.event_name == 'pull_request' && inputs.cache-pnpm-store != 'false' &&
|
||||
(runner.os != 'Windows' ||
|
||||
!(runner.arch == 'X64' && contains(inputs.cache-dependency-path, 'mobile/pnpm-lock.yaml')) &&
|
||||
!((runner.arch == 'X64' || runner.arch == 'ARM64') && inputs.cache-dependency-path == 'pnpm-lock.yaml'))
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: ${{ steps.pnpm-store.outputs.path }}
|
||||
|
||||
@@ -154,6 +154,7 @@ jobs:
|
||||
- uses: ./.github/actions/install-node-dependencies
|
||||
with:
|
||||
native-runtime: ${{ runner.os == 'Windows' && 'node' || 'none' }}
|
||||
cache-pnpm-store: ${{ runner.os != 'Windows' }}
|
||||
# Linux release slots come from the floor and Alpine lanes; this slot serves local tests.
|
||||
- uses: ./.github/actions/prepare-orcad-prebuilds
|
||||
id: orcad-prebuild
|
||||
|
||||
@@ -109,6 +109,7 @@ jobs:
|
||||
id: dependencies
|
||||
with:
|
||||
native-runtime: node
|
||||
cache-pnpm-store: 'false'
|
||||
# The deploy materializes rung A from this template; only this runner's slot exists here.
|
||||
# The process-tree addon carries the launcher that starts the relay outside sshd's job; the
|
||||
# orcad slot and the relay both stage it, and a standard-user host has no other launch route.
|
||||
|
||||
@@ -11,7 +11,9 @@ 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("${{ github.event_name != 'pull_request' && 'pnpm' || '' }}")
|
||||
expect(step.with.cache).toBe(
|
||||
"${{ github.event_name != 'pull_request' && inputs.cache-pnpm-store != 'false' && 'pnpm' || '' }}"
|
||||
)
|
||||
expect(step.with['cache-dependency-path']).toBe('${{ inputs.cache-dependency-path }}')
|
||||
expect(step.with['package-manager-cache']).toBe(false)
|
||||
}
|
||||
@@ -30,13 +32,13 @@ describe('CI dependency download caches', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('restores PR stores except measured Windows mixed installs, without a post-job save', () => {
|
||||
it('restores PR stores except measured Windows installs, without a post-job save', () => {
|
||||
const resolve = action.runs.steps.find((step) => step.id === 'pnpm-store')
|
||||
const restore = action.runs.steps.find(
|
||||
(step) => step.name === 'Restore pnpm download store without saving'
|
||||
)
|
||||
expect(resolve.if).toBe(
|
||||
"github.event_name == 'pull_request' && (runner.os != 'Windows' || runner.arch != 'X64' || !contains(inputs.cache-dependency-path, 'mobile/pnpm-lock.yaml'))"
|
||||
"github.event_name == 'pull_request' && inputs.cache-pnpm-store != 'false' && (runner.os != 'Windows' || !(runner.arch == 'X64' && contains(inputs.cache-dependency-path, 'mobile/pnpm-lock.yaml')) && !((runner.arch == 'X64' || runner.arch == 'ARM64') && inputs.cache-dependency-path == 'pnpm-lock.yaml'))"
|
||||
)
|
||||
expect(restore.if).toBe(resolve.if)
|
||||
expect(restore.uses).toBe('actions/cache/restore@v5')
|
||||
@@ -69,36 +71,111 @@ describe('CI dependency download caches', () => {
|
||||
['Windows x64 mixed PR', 'pull_request', 'Windows', 'X64', true, false, ''],
|
||||
['Windows ARM64 mixed PR', 'pull_request', 'Windows', 'ARM64', true, true, ''],
|
||||
['Windows x86 mixed PR', 'pull_request', 'Windows', 'X86', true, true, ''],
|
||||
['Windows x64 root-only PR', 'pull_request', 'Windows', 'X64', false, true, ''],
|
||||
['Windows x64 root-only PR', 'pull_request', 'Windows', 'X64', false, false, ''],
|
||||
['Windows ARM64 root-only PR', 'pull_request', 'Windows', 'ARM64', false, false, ''],
|
||||
['Windows x86 root-only PR', 'pull_request', 'Windows', 'X86', false, true, ''],
|
||||
['Windows x64 custom PR', 'pull_request', 'Windows', 'X64', 'cloud/pnpm-lock.yaml', true, ''],
|
||||
[
|
||||
'Windows ARM64 custom PR',
|
||||
'pull_request',
|
||||
'Windows',
|
||||
'ARM64',
|
||||
'cloud/pnpm-lock.yaml',
|
||||
true,
|
||||
''
|
||||
],
|
||||
['Windows ARM64 root-only push', 'push', 'Windows', 'ARM64', false, false, 'pnpm'],
|
||||
[
|
||||
'Windows ARM64 root-only manual run',
|
||||
'workflow_dispatch',
|
||||
'Windows',
|
||||
'ARM64',
|
||||
false,
|
||||
false,
|
||||
'pnpm'
|
||||
],
|
||||
['Explicit Linux PR opt-out', 'pull_request', 'Linux', 'X64', false, false, '', 'false'],
|
||||
['Explicit Windows push opt-out', 'push', 'Windows', 'ARM64', false, false, '', 'false'],
|
||||
[
|
||||
'Explicit Windows manual opt-out',
|
||||
'workflow_dispatch',
|
||||
'Windows',
|
||||
'X64',
|
||||
false,
|
||||
false,
|
||||
'',
|
||||
'false'
|
||||
],
|
||||
[
|
||||
'Explicit custom-store opt-out',
|
||||
'pull_request',
|
||||
'Windows',
|
||||
'X64',
|
||||
'cloud/pnpm-lock.yaml',
|
||||
false,
|
||||
'',
|
||||
'false'
|
||||
],
|
||||
['Windows x64 root-only push', 'push', 'Windows', 'X64', false, false, 'pnpm'],
|
||||
['Linux x64 mixed PR', 'pull_request', 'Linux', 'X64', true, true, ''],
|
||||
['Linux ARM64 mixed PR', 'pull_request', 'Linux', 'ARM64', true, true, ''],
|
||||
['macOS ARM64 mixed PR', 'pull_request', 'macOS', 'ARM64', true, true, ''],
|
||||
['Windows x64 mixed push', 'push', 'Windows', 'X64', true, false, 'pnpm'],
|
||||
['Windows x64 mixed manual run', 'workflow_dispatch', 'Windows', 'X64', true, false, 'pnpm']
|
||||
])('%s keeps its scoped store policy', (_name, event, os, arch, mixed, restore, cache) => {
|
||||
const context = {
|
||||
github: { event_name: event },
|
||||
runner: { os, arch },
|
||||
inputs: {
|
||||
'cache-dependency-path': mixed ? 'pnpm-lock.yaml\nmobile/pnpm-lock.yaml' : 'pnpm-lock.yaml'
|
||||
},
|
||||
contains: (value, search) => value.toLowerCase().includes(search.toLowerCase())
|
||||
}
|
||||
const evaluate = (expression) =>
|
||||
runInNewContext(
|
||||
expression.replaceAll('inputs.cache-dependency-path', 'inputs["cache-dependency-path"]'),
|
||||
context
|
||||
)
|
||||
for (const step of action.runs.steps.filter(
|
||||
(step) =>
|
||||
step.id === 'pnpm-store' || step.name === 'Restore pnpm download store without saving'
|
||||
)) {
|
||||
expect(evaluate(step.if)).toBe(restore)
|
||||
}
|
||||
for (const step of action.runs.steps.filter((step) => step.uses === 'actions/setup-node@v6')) {
|
||||
expect(evaluate(step.with.cache.slice(3, -2))).toBe(cache)
|
||||
expect(step.with['package-manager-cache']).toBe(false)
|
||||
])(
|
||||
'%s keeps its scoped store policy',
|
||||
(_name, event, os, arch, mixed, restore, cache, storeCache = 'true') => {
|
||||
const context = {
|
||||
github: { event_name: event },
|
||||
runner: { os, arch },
|
||||
inputs: {
|
||||
'cache-pnpm-store': storeCache,
|
||||
'cache-dependency-path':
|
||||
typeof mixed === 'string'
|
||||
? mixed
|
||||
: mixed
|
||||
? 'pnpm-lock.yaml\nmobile/pnpm-lock.yaml'
|
||||
: 'pnpm-lock.yaml'
|
||||
},
|
||||
contains: (value, search) => value.toLowerCase().includes(search.toLowerCase())
|
||||
}
|
||||
const evaluate = (expression) =>
|
||||
runInNewContext(
|
||||
expression
|
||||
.replaceAll('inputs.cache-dependency-path', 'inputs["cache-dependency-path"]')
|
||||
.replaceAll('inputs.cache-pnpm-store', 'inputs["cache-pnpm-store"]'),
|
||||
context
|
||||
)
|
||||
for (const step of action.runs.steps.filter(
|
||||
(step) =>
|
||||
step.id === 'pnpm-store' || step.name === 'Restore pnpm download store without saving'
|
||||
)) {
|
||||
expect(evaluate(step.if)).toBe(restore)
|
||||
}
|
||||
for (const step of action.runs.steps.filter(
|
||||
(step) => step.uses === 'actions/setup-node@v6'
|
||||
)) {
|
||||
expect(evaluate(step.with.cache.slice(3, -2))).toBe(cache)
|
||||
expect(step.with['package-manager-cache']).toBe(false)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
it('opts Windows server consumers out while preserving the main warmer store writer', () => {
|
||||
const installer = './.github/actions/install-node-dependencies'
|
||||
const persistence = workflow('node-server-tests').jobs.persistence.steps.find(
|
||||
(step) => step.uses === installer
|
||||
)
|
||||
const ssh = workflow('ssh-windows-hosts').jobs.hosts.steps.find(
|
||||
(step) => step.uses === installer
|
||||
)
|
||||
const warmer = workflow('ci-cache-warmup').jobs['warm-windows'].steps.find(
|
||||
(step) => step.uses === installer
|
||||
)
|
||||
expect(action.inputs['cache-pnpm-store'].default).toBe('true')
|
||||
expect(persistence.with['cache-pnpm-store']).toBe("${{ runner.os != 'Windows' }}")
|
||||
expect(ssh.with['cache-pnpm-store']).toBe('false')
|
||||
expect(warmer.with['cache-pnpm-store']).toBeUndefined()
|
||||
})
|
||||
|
||||
it('restores Windows packaging downloads from the release cache without a PR upload', () => {
|
||||
|
||||
@@ -122,7 +122,7 @@ const REVIEWED_COMPUTED_PATHS = [
|
||||
'${{ steps.pnpm-store.outputs.path }}',
|
||||
// Only pnpm's lockfile-verified.jsonl record, never Metro transforms.
|
||||
'${{ steps.verification-cache.outputs.path }}',
|
||||
"${{ github.event_name != 'pull_request' && 'pnpm' || '' }} store"
|
||||
"${{ github.event_name != 'pull_request' && inputs.cache-pnpm-store != 'false' && 'pnpm' || '' }} store"
|
||||
]
|
||||
|
||||
/** Every step a workflow runs, descending into the repository's own composite actions. */
|
||||
|
||||
@@ -289,7 +289,8 @@ describe('PR workflow parallelism', () => {
|
||||
expect(steps[pnpmIndex].uses).toBe('pnpm/setup@v2')
|
||||
expect(steps[pnpmIndex].with.version).toBeUndefined()
|
||||
expect(steps[pnpmIndex].with.install).toBe(false)
|
||||
const saveOutsidePrs = "${{ github.event_name != 'pull_request' && 'pnpm' || '' }}"
|
||||
const saveOutsidePrs =
|
||||
"${{ github.event_name != 'pull_request' && inputs.cache-pnpm-store != 'false' && 'pnpm' || '' }}"
|
||||
expect(steps[nodeIndex].with.cache).toBe(saveOutsidePrs)
|
||||
expect(steps[nodeIndex].if).toBe("inputs.node-version == ''")
|
||||
expect(steps[requestedNodeIndex].if).toBe("inputs.node-version != ''")
|
||||
@@ -304,7 +305,7 @@ describe('PR workflow parallelism', () => {
|
||||
)
|
||||
expect(steps[restoreIndex].uses).toBe('actions/cache/restore@v5')
|
||||
expect(steps[restoreIndex].if).toBe(
|
||||
"github.event_name == 'pull_request' && (runner.os != 'Windows' || runner.arch != 'X64' || !contains(inputs.cache-dependency-path, 'mobile/pnpm-lock.yaml'))"
|
||||
"github.event_name == 'pull_request' && inputs.cache-pnpm-store != 'false' && (runner.os != 'Windows' || !(runner.arch == 'X64' && contains(inputs.cache-dependency-path, 'mobile/pnpm-lock.yaml')) && !((runner.arch == 'X64' || runner.arch == 'ARM64') && inputs.cache-dependency-path == 'pnpm-lock.yaml'))"
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -76,6 +76,41 @@ request reuse only following an exact prepared native-cache hit; manual SSH and
|
||||
all release builders retain fresh compilation. Subsequent staging checks still
|
||||
run. Hosted validation and the reuse interval remain to be measured.
|
||||
|
||||
## Windows root download stores: registry installs finish sooner
|
||||
|
||||
Three paired samples on each Windows architecture compared the existing exact
|
||||
main download-store restore with a fresh registry install. Each treatment used a
|
||||
fresh dependency tree, store and pnpm metadata, with registry-first ordering in
|
||||
sample 2. Both restored the same policy-checked verification record before timing.
|
||||
All six pairs used Node 24.21.0 and pnpm 12.8.1; manifest digests and installed
|
||||
lockfile digests matched, and both retained frozen, script-free installation.
|
||||
|
||||
| Runner | Cached totals (seconds) | Registry totals (seconds) | Paired median saving |
|
||||
| ------------- | --------------------------- | --------------------------- | -------------------- |
|
||||
| Windows x64 | 26.820 / 28.885 / 27.751 | 13.644 / 14.126 / 12.908 | 14.759 seconds |
|
||||
| Windows ARM64 | 216.540 / 288.492 / 189.342 | 119.856 / 238.562 / 115.611 | 73.731 seconds |
|
||||
|
||||
The x64 samples are the three successful Windows 2022 jobs in
|
||||
[run 37064549378](https://github.com/stablyai/orca/actions/runs/37064549378).
|
||||
Its ARM cleanup guard rejected pnpm's setup-owned store path before measurement;
|
||||
those incomplete ARM jobs are excluded. The corrected
|
||||
[ARM-only run](https://github.com/stablyai/orca/actions/runs/37065220916) passed all
|
||||
three samples. Earlier rejected measurements also stopped before installation
|
||||
because an optional config file was absent; none count toward these timings.
|
||||
|
||||
Intervals include actual store lookup/restore, inter-step overhead and root
|
||||
installation. Checkout, toolchain setup, tree/store reset, verification-record
|
||||
restoration and native preparation are excluded. ARM variation is substantial;
|
||||
these samples do not measure whole-workflow, queue or billing savings.
|
||||
|
||||
Root-only Windows x64/ARM64 PR installs now skip the download-store restore.
|
||||
The existing x64 mixed-install exception remains. An explicit store opt-out also
|
||||
lets Windows headless persistence and SSH jobs avoid the archive on main or
|
||||
manual runs. Frozen installs, verification records, native caches and every
|
||||
qualification check remain. Other lockfile sets and platforms keep their
|
||||
existing policy. Default non-PR writers, including the warmer, still seed stores
|
||||
for direct setup-node consumers and workflows that run package scripts.
|
||||
|
||||
## October 1 Windows and dependency cache follow-up
|
||||
|
||||
[PR #24355](https://github.com/stablyai/orca/pull/24355) merged at `197ea3a3`.
|
||||
|
||||
Reference in New Issue
Block a user