mirror of
https://github.com/stablyai/orca.git
synced 2026-11-14 18:07:45 +00:00
* refactor(tooling): organize test runtime and maintenance owners * test(tooling): preserve relocated runtime fixture dependency edges * refactor(tooling): preserve xterm routing owner checks * ci(tooling): include routing owner in sparse checkout * test(tooling): preserve copied workflow dependency closures * fix(tooling): normalize hashed JSON assets in release parity * fix(tooling): distinguish asset aliases from literal references * fix(tooling): frame normalized asset reference payloads * fix(tooling): normalize decoded JSON asset references * refactor(tooling): organize build, CI and release owners * fix(tooling): align moved generator and workflow path contracts * fix(tooling): update generated plugin bundle owner banners * test(tooling): create relocated mobile verifier fixture directories * test(tooling): copy headless detector dependency closure * test(tooling): align native batch policy fixtures with owner path * fix(tooling): link moved reliability command to historical evidence * fix(tooling): preserve nested sandbox owners and canonical guide source * fix(tooling): target release version owners in checkout fixture
89 lines
3.6 KiB
JavaScript
89 lines
3.6 KiB
JavaScript
import { globSync, readFileSync } from 'node:fs'
|
|
import { parse } from 'yaml'
|
|
import { defaultExclude } from 'vitest/config'
|
|
import { describe, expect, it } from 'vitest'
|
|
import { CROSS_VERSION_WIRE_DIR, UNIT_INCLUDE, discoverUnitFiles } from './ci-unit-files.mjs'
|
|
import { classifyPrJobs } from '../../../workflow/source-routing/pr-code-change-scope.mjs'
|
|
|
|
function posixPaths(files) {
|
|
return files.map((file) => file.replaceAll('\\', '/'))
|
|
}
|
|
|
|
function workflowJobs(path) {
|
|
return parse(readFileSync(path, 'utf8')).jobs
|
|
}
|
|
|
|
// Gating jobs must reach verify.needs or failures/skips cannot block merge; each needs code_paths selection, inherited by called workflows.
|
|
function gatingJobs() {
|
|
const jobs = workflowJobs('.github/workflows/pr.yml')
|
|
return jobs.verify.needs.flatMap((name) => {
|
|
const { if: condition = '', uses } = jobs[name]
|
|
const gate = /needs\.code_paths\.outputs\.([\w-]+) == 'true'/.exec(condition)?.[1]
|
|
const called = uses?.startsWith('./.github/workflows/')
|
|
? Object.values(workflowJobs(uses.slice(2)))
|
|
: [jobs[name]]
|
|
return called.map((job) => ({ gate, pathArguments: vitestPathArguments(job) }))
|
|
})
|
|
}
|
|
|
|
// Path arguments of every step in the job that runs vitest; a trailing slash means a directory.
|
|
function vitestPathArguments(job) {
|
|
return (job.steps ?? [])
|
|
.map((step) => step.run)
|
|
.filter((run) => typeof run === 'string' && /\bvitest\b/.test(run))
|
|
.flatMap((run) => run.replaceAll('\\\n', ' ').split(/\s+/))
|
|
.map((token) => token.replace(/^['"]|['"]$/g, ''))
|
|
.filter((token) => /^(?:src|config|tests|mobile)\//.test(token))
|
|
}
|
|
|
|
function runByVitestStep(file, pathArguments) {
|
|
return pathArguments.some(
|
|
(path) => path === file || (path.endsWith('/') && file.startsWith(path))
|
|
)
|
|
}
|
|
|
|
// Why module scope: globbing the unit tree costs seconds, and every test reads the same result.
|
|
const UNIT_FILES = posixPaths(globSync(UNIT_INCLUDE, { exclude: defaultExclude }))
|
|
const SHARDED_UNIT_FILES = new Set(discoverUnitFiles())
|
|
const EXCLUDED_UNIT_FILES = UNIT_FILES.filter((file) => !SHARDED_UNIT_FILES.has(file))
|
|
const GATING_JOBS = gatingJobs()
|
|
|
|
describe('unit files kept out of the sharded test job', () => {
|
|
it('each still runs in a job that gates the PR', () => {
|
|
expect(EXCLUDED_UNIT_FILES.length).toBeGreaterThan(0)
|
|
// Why: an excluded file no gating step names guards nothing, and nothing else reports it.
|
|
expect(
|
|
EXCLUDED_UNIT_FILES.filter(
|
|
(file) => !GATING_JOBS.some((job) => runByVitestStep(file, job.pathArguments))
|
|
)
|
|
).toEqual([])
|
|
})
|
|
|
|
it('a change to each runs a gating job that names it', () => {
|
|
// Why: otherwise a PR editing only the file skips the one job that runs it.
|
|
expect(
|
|
EXCLUDED_UNIT_FILES.filter(
|
|
(file) =>
|
|
!GATING_JOBS.some(
|
|
({ gate, pathArguments }) =>
|
|
runByVitestStep(file, pathArguments) && (!gate || classifyPrJobs([file])[gate])
|
|
)
|
|
)
|
|
).toEqual([])
|
|
})
|
|
|
|
it('runs the whole cross-version-wire directory, not a list of its files', () => {
|
|
expect(GATING_JOBS.flatMap((job) => job.pathArguments)).toContain(CROSS_VERSION_WIRE_DIR)
|
|
})
|
|
|
|
it('names every cross-version-wire test so the unit include picks it up', () => {
|
|
// Why: a directory argument only reaches files the vitest include matches; any other name is silently skipped.
|
|
const tests = posixPaths(
|
|
globSync(`${CROSS_VERSION_WIRE_DIR}**/*.{test,spec}.{js,cjs,mjs,ts,tsx}`)
|
|
)
|
|
const included = new Set(UNIT_FILES)
|
|
expect(tests.length).toBeGreaterThan(0)
|
|
expect(tests.filter((file) => !included.has(file))).toEqual([])
|
|
})
|
|
})
|