mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
ci: skip redundant PR platform warmers (#28917)
This commit is contained in:
@@ -8,6 +8,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
warm-linux-arm:
|
||||
if: github.event_name != 'pull_request'
|
||||
concurrency:
|
||||
group: ci-cache-warmup-linux-arm-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name != 'schedule' }}
|
||||
@@ -85,6 +86,7 @@ jobs:
|
||||
arches: arm64
|
||||
|
||||
warm-linux-package-fixtures:
|
||||
if: github.event_name != 'pull_request'
|
||||
concurrency:
|
||||
group: ci-cache-warmup-linux-package-fixtures-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name != 'schedule' }}
|
||||
|
||||
@@ -45,7 +45,6 @@ on:
|
||||
- 'resources/build/icon.ico'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/ci-cache-warmup.yml'
|
||||
- '.github/workflows/ci-cache-warmup-platforms.yml'
|
||||
- '.github/workflows/ci-cache-warmup-platform-jobs.yml'
|
||||
|
||||
|
||||
@@ -50,8 +50,6 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/ci-cache-warmup.yml'
|
||||
- '.github/workflows/ci-cache-warmup-platform-jobs.yml'
|
||||
- '.github/workflows/ci-cache-warmup-platforms.yml'
|
||||
- '.github/actions/prepare-headless-compiler/**'
|
||||
- 'config/scripts/headless-detector-compiler-cache.mjs'
|
||||
- '.github/actions/prepare-wayland-clipboard/**'
|
||||
|
||||
@@ -2,6 +2,7 @@ import { readFileSync } from 'node:fs'
|
||||
import { runInNewContext } from 'node:vm'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { parse } from 'yaml'
|
||||
import { classifyPrJobs } from './pr-code-change-scope.mjs'
|
||||
|
||||
const read = (path) => parse(readFileSync(path, 'utf8'))
|
||||
const workflow = (name) => read(`.github/workflows/${name}.yml`)
|
||||
@@ -300,6 +301,116 @@ describe('CI dependency download caches', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('keeps PR warmer validation within the workflow family that runs it', () => {
|
||||
const shared = workflow('ci-cache-warmup')
|
||||
const platforms = workflow('ci-cache-warmup-platforms')
|
||||
expect(shared.on.pull_request.paths).toEqual([
|
||||
'.github/workflows/ci-cache-warmup.yml',
|
||||
'.github/actions/prepare-headless-compiler/**',
|
||||
'config/scripts/headless-detector-compiler-cache.mjs',
|
||||
'.github/actions/prepare-wayland-clipboard/**'
|
||||
])
|
||||
expect(platforms.on.pull_request.paths).toEqual([
|
||||
'.github/workflows/ci-cache-warmup-platforms.yml',
|
||||
'.github/workflows/ci-cache-warmup-platform-jobs.yml'
|
||||
])
|
||||
expect(shared.jobs['warm-platforms'].uses).toBe(platforms.jobs['warm-platforms'].uses)
|
||||
expect(shared.on.schedule).toEqual([{ cron: '41 */6 * * *' }])
|
||||
expect(shared.on).toHaveProperty('workflow_dispatch')
|
||||
for (const producer of [shared, platforms]) {
|
||||
expect(producer.on.push.branches).toEqual(['main'])
|
||||
expect(producer.on.push.paths).toEqual(
|
||||
expect.arrayContaining([
|
||||
'.github/workflows/ci-cache-warmup.yml',
|
||||
'.github/workflows/ci-cache-warmup-platforms.yml',
|
||||
'.github/workflows/ci-cache-warmup-platform-jobs.yml',
|
||||
'.github/actions/install-node-dependencies/**',
|
||||
'.github/actions/prepare-native-runtime/**',
|
||||
'pnpm-lock.yaml'
|
||||
])
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it.each([
|
||||
['pull_request', false, false],
|
||||
['push', true, false],
|
||||
['schedule', true, true],
|
||||
['workflow_dispatch', true, true]
|
||||
])('retains cache producers and Windows validation on %s', (event, armRuns, sharedPlatforms) => {
|
||||
const shared = workflow('ci-cache-warmup')
|
||||
const platforms = read(workflow('ci-cache-warmup-platforms').jobs['warm-platforms'].uses)
|
||||
const context = { github: { event_name: event } }
|
||||
expect(runInNewContext(platforms.jobs['warm-linux-arm'].if, context)).toBe(armRuns)
|
||||
expect(runInNewContext(shared.jobs['warm-platforms'].if, context)).toBe(sharedPlatforms)
|
||||
expect(shared.jobs.warm.if).toBeUndefined()
|
||||
expect(platforms.jobs['warm-windows'].if).toBeUndefined()
|
||||
expect(platforms.jobs['warm-windows'].strategy.matrix.os).toEqual([
|
||||
'windows-2022',
|
||||
'windows-11-arm'
|
||||
])
|
||||
})
|
||||
|
||||
it('validates the omitted ARM warmer preparation in the real PR consumers', () => {
|
||||
const platforms = read(workflow('ci-cache-warmup-platforms').jobs['warm-platforms'].uses)
|
||||
const warm = platforms.jobs['warm-linux-arm']
|
||||
const pr = workflow('pr')
|
||||
const units = workflow('unit-tests').jobs.test
|
||||
const installer = './.github/actions/install-node-dependencies'
|
||||
const warmInstall = warm.steps.find((step) => step.uses === installer)
|
||||
const unitInstall = units.steps.find((step) => step.uses === installer)
|
||||
expect(warm['runs-on']).toBe('ubuntu-24.04-arm')
|
||||
expect(pr.jobs.preflight['runs-on']).toBe(warm['runs-on'])
|
||||
expect(pr.jobs.test.with.runner).toBe(warm['runs-on'])
|
||||
expect(units['runs-on']).toBe('${{ inputs.runner }}')
|
||||
expect(JSON.parse(pr.jobs.test.with.node_versions)).toEqual(['24'])
|
||||
expect(warmInstall.if).toBeUndefined()
|
||||
expect(unitInstall.if).toBeUndefined()
|
||||
expect(warmInstall.with['native-runtime']).toBe('node')
|
||||
expect(unitInstall.with['native-runtime']).toBe(warmInstall.with['native-runtime'])
|
||||
expect(warmInstall.with['node-version']).toBe('24')
|
||||
expect(unitInstall.with['node-version']).toBe('${{ matrix.node }}')
|
||||
expect(unitInstall.with['cache-electron-package']).toBe(
|
||||
warmInstall.with['cache-electron-package']
|
||||
)
|
||||
const preflightInstalls = pr.jobs.preflight.steps.filter((step) => step.uses === installer)
|
||||
expect(preflightInstalls.map((step) => step.if)).toEqual([
|
||||
"needs.code_paths.outputs.mobile_dependencies != 'true'",
|
||||
"needs.code_paths.outputs.mobile_dependencies == 'true'"
|
||||
])
|
||||
for (const step of preflightInstalls) {
|
||||
expect(step.with['native-runtime']).toBe('node')
|
||||
expect(step.with['node-version']).toBe('24')
|
||||
}
|
||||
const populate = 'node config/scripts/install-electron-package-binary.mjs'
|
||||
const unitPopulate = units.steps.find((step) => step.run === populate)
|
||||
expect(unitPopulate.if).toBeUndefined()
|
||||
expect(warm.steps.map((step) => step.uses ?? step.run)).toEqual([
|
||||
'actions/checkout@v6',
|
||||
installer,
|
||||
populate,
|
||||
'node config/scripts/ensure-native-runtime.mjs --check-only'
|
||||
])
|
||||
const native = read('.github/actions/prepare-native-runtime/action.yml')
|
||||
const identity = native.runs.steps.find((step) => step.id === 'native-cache-scope')
|
||||
const inputs = [...identity.env.NATIVE_SOURCE_HASH.matchAll(/'([^']+)'/g)].map(
|
||||
(match) => match[1]
|
||||
)
|
||||
for (const path of [
|
||||
...inputs,
|
||||
'.github/actions/install-node-dependencies/action.yml',
|
||||
...workflow('ci-cache-warmup-platforms').on.pull_request.paths,
|
||||
'.github/workflows/ci-cache-warmup.yml'
|
||||
]) {
|
||||
expect(classifyPrJobs([path], { allowMobileCiTools: true }), path).toMatchObject({
|
||||
static_analysis: true,
|
||||
typecheck: true,
|
||||
test: true,
|
||||
mobile_ci_tools: false
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('restores Windows packaging downloads from the release cache without a PR upload', () => {
|
||||
const packaging = workflow('pr').jobs.package_windows
|
||||
const restore = packaging.steps.find((step) => step.name === 'Cache electron-builder downloads')
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { chmodSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { runInNewContext } from 'node:vm'
|
||||
import { delimiter, join } from 'node:path'
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import { parse } from 'yaml'
|
||||
import { runProcessSync } from '@orca/process-host'
|
||||
import { classifyPrJobs } from './pr-code-change-scope.mjs'
|
||||
|
||||
const action = parse(
|
||||
readFileSync('.github/actions/prepare-linux-package-fixture/action.yml', 'utf8')
|
||||
@@ -132,3 +134,45 @@ it('uses exact context/platform keys and the same restore-only action in package
|
||||
.every((step) => step.with['save-cache'] === "${{ github.event_name != 'pull_request' }}")
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
it.each([
|
||||
['pull_request', false],
|
||||
['push', true],
|
||||
['schedule', true],
|
||||
['workflow_dispatch', true]
|
||||
])('keeps fixture seeding available without a redundant PR runner on %s', (event, runs) => {
|
||||
const source = workflow('ci-cache-warmup-platforms').jobs['warm-platforms'].uses
|
||||
const warm = parse(readFileSync(source, 'utf8')).jobs['warm-linux-package-fixtures']
|
||||
const context = { github: { event_name: event } }
|
||||
expect(warm['runs-on']).toBe('ubuntu-latest')
|
||||
expect(warm.steps.map((step) => step.uses)).toEqual([
|
||||
'actions/checkout@v6',
|
||||
'./.github/actions/prepare-linux-package-fixture',
|
||||
'./.github/actions/prepare-linux-package-fixture',
|
||||
'./.github/actions/prepare-linux-package-fixture'
|
||||
])
|
||||
expect(runInNewContext(warm.if, context)).toBe(runs)
|
||||
for (const step of warm.steps.slice(1)) {
|
||||
expect(runInNewContext(step.with['save-cache'].slice(3, -2), context)).toBe(runs)
|
||||
}
|
||||
const consumers = workflow('pr').jobs.package.steps.filter((step) =>
|
||||
step.uses?.endsWith('/prepare-linux-package-fixture')
|
||||
)
|
||||
expect(consumers.every((step) => step.with['save-cache'] === undefined)).toBe(true)
|
||||
expect(consumers.map((step) => step.with.fixture)).toEqual(
|
||||
warm.steps.slice(1).map((step) => step.with.fixture)
|
||||
)
|
||||
})
|
||||
|
||||
it.each([
|
||||
'.github/actions/prepare-linux-package-fixture/action.yml',
|
||||
'config/docker/daemon-shutdown-descendants/Dockerfile',
|
||||
'config/docker/headless-serve-shutdown/Dockerfile',
|
||||
'config/docker/cli-launch-contract/Dockerfile'
|
||||
])('validates a changed fixture in Linux packaging: %s', (file) => {
|
||||
expect(classifyPrJobs([file])).toMatchObject({
|
||||
test: true,
|
||||
package: true,
|
||||
package_windows: false
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user