mirror of
https://github.com/stablyai/orca.git
synced 2026-11-15 02:17:31 +00:00
* ci: full checks on main pushes, changed-file lint on PRs, Slack alert when main breaks PR Checks now also runs on every push to main, with each commit in its own concurrency group so main runs never cancel one another. On a push the path router gets an empty diff, which already fails closed to every job, and the input-scoped steps (localization extraction, VM rollback replay, orcad smoke) run in full. Advisory E2E lanes stay PR-only. On PRs the per-file passes (root oxlint, JS-plugin oxlint, anti-slop, ast-grep and oxfmt) check only the changed paths. Everything is checked when the diff cannot be resolved, a lint toolchain input changes (oxlint/oxfmt/ast-grep configs and plugins, package.json, the lockfile, .gitignore, pr.yml), or more than 1500 paths change. Whole-program checks stay unscoped. A new workflow follows completed main runs and posts to the release Slack webhook only when main turns red, and once when it turns green again. * ci: alert once per main health streak and tolerate a malformed Slack mapping
40 lines
1.6 KiB
JavaScript
40 lines
1.6 KiB
JavaScript
import { readdirSync, readFileSync } from 'node:fs'
|
|
import { join } from 'node:path'
|
|
import { pathToFileURL } from 'node:url'
|
|
|
|
export function verifyRequiredPrContext(parseYaml) {
|
|
const directory = '.github/workflows'
|
|
const providers = readdirSync(directory)
|
|
.filter((file) => /\.ya?ml$/.test(file))
|
|
.flatMap((file) => {
|
|
const workflow = parseYaml(readFileSync(join(directory, file), 'utf8'))
|
|
return Object.entries(workflow.jobs)
|
|
.filter(([id, job]) => (job.name ?? id) === 'PR checks passed')
|
|
.map(([id, job]) => ({ owner: `${file}:${id}`, job }))
|
|
})
|
|
const owners = providers.map((provider) => provider.owner)
|
|
if (providers.length !== 1 || owners[0] !== 'pr.yml:verify') {
|
|
throw new Error(`Required PR context must belong only to pr.yml:verify; found ${owners}`)
|
|
}
|
|
const gate = providers[0].job
|
|
const condition = gate.if?.replace(/^\$\{\{\s*|\s*\}\}$/g, '').trim()
|
|
if (
|
|
condition !==
|
|
"!cancelled() && (github.event_name != 'pull_request' || github.event.pull_request.draft != true)"
|
|
) {
|
|
throw new Error('Required PR aggregate must run unless cancelled or the PR is a draft.')
|
|
}
|
|
if (gate['continue-on-error'] || gate.steps?.some((step) => step['continue-on-error'])) {
|
|
throw new Error('Required PR aggregate must not ignore failures.')
|
|
}
|
|
}
|
|
|
|
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
const yaml = globalThis.Bun?.YAML
|
|
if (!yaml) {
|
|
throw new Error('Run workflow context validation with the pinned Bun runtime.')
|
|
}
|
|
verifyRequiredPrContext(yaml.parse)
|
|
console.log('Required PR check context verified.')
|
|
}
|