diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 13a2b90ec12..1136927d201 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -52,6 +52,7 @@ jobs: cross-version-wire: ${{ steps.readiness.outputs.reused != 'true' && steps.filter.outputs.cross-version-wire }} managed_hook_node18: ${{ steps.readiness.outputs.reused != 'true' && steps.filter.outputs.managed_hook_node18 }} package: ${{ steps.readiness.outputs.reused != 'true' && steps.filter.outputs.package }} + windows_process_probe: ${{ steps.filter.outputs.windows_process_probe }} package_windows: ${{ steps.readiness.outputs.reused != 'true' && steps.filter.outputs.package_windows }} layout_oracle: ${{ steps.readiness.outputs.reused != 'true' && steps.filter.outputs.layout_oracle }} dependency_isolation: ${{ steps.readiness.outputs.reused != 'true' && steps.filter.outputs.dependency_isolation }} @@ -1341,6 +1342,9 @@ jobs: # vitest runs here directly rather than through `pnpm test`, so the addon # assertions only hold once install-node-dependencies has rebuilt natives. - name: Test Windows installer process probe + if: needs.code_paths.outputs.windows_process_probe != 'false' + env: + ORCA_BACKGROUND_LAUNCH: '1' # Serialize the two suites so their cold PowerShell/CIM starts cannot contend. run: >- pnpm exec vitest run --config config/vitest.config.ts diff --git a/config/scripts/pr-code-change-scope-windows-process-probe.test.mjs b/config/scripts/pr-code-change-scope-windows-process-probe.test.mjs new file mode 100644 index 00000000000..2ee86621d31 --- /dev/null +++ b/config/scripts/pr-code-change-scope-windows-process-probe.test.mjs @@ -0,0 +1,53 @@ +import { readFileSync } from 'node:fs' +import { describe, expect, it } from 'vitest' +import { parse } from 'yaml' +import { classifyPrJobs } from './pr-code-change-scope.mjs' + +const prWorkflow = parse( + readFileSync(new URL('../../.github/workflows/pr.yml', import.meta.url), 'utf8') +) + +describe('Windows installer process probe routing', () => { + it.each([ + [], + ['config/nsis/orca-process-check.nsh'], + ['config/nsis/orca-installer-hooks.nsh'], + ['config/scripts/nsis-process-check.test.mjs'], + ['config/scripts/idle-cpu-process-sampling.mjs'], + ['config/scripts/idle-cpu-process-sampling.test.mjs'], + ['src/packages/process-host/src/run-process.ts'], + ['config/vitest.config.ts'], + ['config/scripts/vitest-host-ports-setup.ts'], + ['config/scripts/ci-unit-files.mjs'], + ['.github/actions/install-node-dependencies/action.yml'], + ['.github/workflows/pr.yml'], + ['package.json'], + ['pnpm-lock.yaml'], + ['src/renderer/src/App.tsx', 'config/nsis/orca-process-check.nsh'] + ])('runs real Windows probes and their containing job for %j', (...files) => { + expect(classifyPrJobs(files)).toMatchObject({ + windows_process_probe: true, + package_windows: true + }) + }) + + it('keeps packaging and full unit tests for unrelated application changes', () => { + expect(classifyPrJobs(['src/renderer/src/App.tsx'])).toMatchObject({ + windows_process_probe: false, + package_windows: true, + test: true + }) + expect(classifyPrJobs(['docs/README.md']).windows_process_probe).toBe(false) + }) + + it('connects the router output to a fail-closed probe step', () => { + expect(prWorkflow.jobs.code_paths.outputs.windows_process_probe).toBe( + '${{ steps.filter.outputs.windows_process_probe }}' + ) + const step = prWorkflow.jobs.package_windows.steps.find( + (candidate) => candidate.name === 'Test Windows installer process probe' + ) + expect(step.if).toBe("needs.code_paths.outputs.windows_process_probe != 'false'") + expect(step.env.ORCA_BACKGROUND_LAUNCH).toBe('1') + }) +}) diff --git a/config/scripts/pr-code-change-scope.mjs b/config/scripts/pr-code-change-scope.mjs index f9840d5de37..a456f8a4688 100644 --- a/config/scripts/pr-code-change-scope.mjs +++ b/config/scripts/pr-code-change-scope.mjs @@ -1,9 +1,12 @@ import { readFileSync } from 'node:fs' import { join } from 'node:path' -import process from 'node:process' import { pathToFileURL } from 'node:url' import { isLayoutOracleSource } from './pr-layout-oracle-route.mjs' -import { LINUX_PACKAGE_TESTS, WINDOWS_PACKAGE_TESTS } from './pr-package-test-paths.mjs' +import { + isWindowsProcessProbePath, + LINUX_PACKAGE_TESTS, + WINDOWS_PACKAGE_TESTS +} from './pr-package-test-paths.mjs' const DOCS_ONLY_FILES = new Set([ 'README.md', @@ -476,13 +479,11 @@ function readFormatIgnoredPrefixes() { const FORMAT_IGNORED_PREFIXES = readFormatIgnoredPrefixes() export function isDocsOnlyPath(file) { - if (DOCS_ONLY_FILES.has(file)) { - return true - } - if (DOCS_ONLY_PREFIXES.some((prefix) => file.startsWith(prefix))) { - return true - } - return /^README\.[^/]+\.md$/.test(file) + return ( + DOCS_ONLY_FILES.has(file) || + DOCS_ONLY_PREFIXES.some((prefix) => file.startsWith(prefix)) || + /^README\.[^/]+\.md$/.test(file) + ) } export function shouldRunPrChecks(changedFiles) { @@ -562,6 +563,7 @@ export function classifyPrJobs( return { should_run: shouldRun, mobile_ci_tools: mobileCiTools, + windows_process_probe: shouldRun && (forceAll || changedFiles.some(isWindowsProcessProbePath)), // Relay contracts exercise host/cloud code; any input outside the renderer keeps them. relay_integration: shouldRun && @@ -617,7 +619,11 @@ function isLinuxPackagePath(file) { } function isWindowsPackagePath(file) { - return WINDOWS_PACKAGE_TESTS.includes(file) || isProductBundlePath(file, WINDOWS_PACKAGE_PREFIXES) + return ( + WINDOWS_PACKAGE_TESTS.includes(file) || + isWindowsProcessProbePath(file) || + isProductBundlePath(file, WINDOWS_PACKAGE_PREFIXES) + ) } function isProductBundlePath(file, extraPrefixes) { diff --git a/config/scripts/pr-package-test-paths.mjs b/config/scripts/pr-package-test-paths.mjs index bf745618567..6d79edf5850 100644 --- a/config/scripts/pr-package-test-paths.mjs +++ b/config/scripts/pr-package-test-paths.mjs @@ -99,6 +99,22 @@ export const WINDOWS_BOUNDARY_TESTS = [ 'src/main/skills/bundled-skill-install/plan-selection.test.ts' ] +const WINDOWS_PROCESS_PROBE_PREFIXES = [ + 'config/nsis/', + 'config/scripts/nsis-process-check', + 'config/scripts/idle-cpu-process-sampling', + 'config/vitest.config.', + 'config/scripts/vitest-', + 'config/scripts/ci-unit-', + 'config/scripts/workspace-source-exports', + 'config/dark-build-switches.', + 'src/packages/process-host/' +] + +export function isWindowsProcessProbePath(file) { + return WINDOWS_PROCESS_PROBE_PREFIXES.some((prefix) => file.startsWith(prefix)) +} + export const WINDOWS_PACKAGE_TESTS = [ ...WINDOWS_BOUNDARY_TESTS, ...LINUX_PACKAGE_TESTS,