mirror of
https://github.com/stablyai/orca.git
synced 2026-11-02 10:08:13 +00:00
71 lines
2.5 KiB
JavaScript
71 lines
2.5 KiB
JavaScript
import { readFileSync, readdirSync } from 'node:fs'
|
|
import { expect, it } from 'vitest'
|
|
import { parse } from 'yaml'
|
|
import { compileAggregateExpression } from './pr-aggregate-gate-context.mjs'
|
|
|
|
const workflows = readdirSync('.github/workflows').flatMap((file) => {
|
|
const workflow = parse(readFileSync(`.github/workflows/${file}`, 'utf8'))
|
|
// The LoC reporter updates PR metadata rather than running CI.
|
|
return Object.hasOwn(workflow.on ?? {}, 'pull_request') && file !== 'pr-test-loc.yml'
|
|
? [{ file, workflow }]
|
|
: []
|
|
})
|
|
|
|
function admitted(condition, draft, needs = {}, eventName = 'pull_request') {
|
|
return (
|
|
compileAggregateExpression(condition ?? 'true', ['github', 'needs', 'inputs'])({
|
|
github: {
|
|
event_name: eventName,
|
|
repository: 'stablyai/orca',
|
|
event: { pull_request: { draft } }
|
|
},
|
|
needs,
|
|
inputs: {}
|
|
}).coerceString() === 'true'
|
|
)
|
|
}
|
|
|
|
it.each(workflows)('$file starts no CI jobs for a draft PR', ({ workflow }) => {
|
|
const needs = Object.fromEntries(
|
|
Object.keys(workflow.jobs).map((id) => [id, { result: 'skipped', outputs: {} }])
|
|
)
|
|
for (const [id, job] of Object.entries(workflow.jobs)) {
|
|
// Jobs without a status function inherit success(), so skipped parents block them.
|
|
if (job.needs && !/\b(?:cancelled|always|success|failure)\(/.test(job.if ?? '')) {
|
|
continue
|
|
}
|
|
expect(admitted(job.if, true, needs), id).toBe(false)
|
|
}
|
|
})
|
|
|
|
it.each(workflows)('$file starts CI when ready and cancels it when drafted', ({ workflow }) => {
|
|
const types = workflow.on.pull_request.types
|
|
expect(types).toEqual(
|
|
expect.arrayContaining([
|
|
'opened',
|
|
'synchronize',
|
|
'reopened',
|
|
'ready_for_review',
|
|
'converted_to_draft'
|
|
])
|
|
)
|
|
expect(Object.values(workflow.jobs).some((job) => !job.needs && admitted(job.if, false))).toBe(
|
|
true
|
|
)
|
|
const concurrency = workflow.concurrency['cancel-in-progress']
|
|
expect(typeof concurrency === 'boolean' ? concurrency : admitted(concurrency, true)).toBe(true)
|
|
})
|
|
|
|
it.each(workflows)('$file keeps its non-PR entry points eligible', ({ workflow }) => {
|
|
const needs = Object.fromEntries(
|
|
Object.keys(workflow.jobs).map((id) => [id, { result: 'success', outputs: {} }])
|
|
)
|
|
for (const event of Object.keys(workflow.on).filter((name) => name !== 'pull_request')) {
|
|
for (const [id, job] of Object.entries(workflow.jobs)) {
|
|
expect(admitted(job.if, true, needs, event), `${event}/${id}`).toBe(
|
|
admitted(job.if, false, needs, event)
|
|
)
|
|
}
|
|
}
|
|
})
|