cc-haha/scripts/pr/check-pr.ts
程序员阿江(Relakkes) 435e4ccc9f ci: harden deterministic PR quality gates
Route required checks by changed surface, add offline provider and chat contracts, and keep fork PRs independent of live credentials. Layer agent guidance by subtree and enforce a compact instruction budget.

Tested: bun run check:policy
Confidence: high
Scope-risk: broad
2026-07-10 20:29:01 +08:00

90 lines
2.4 KiB
TypeScript

#!/usr/bin/env bun
import { evaluateChangePolicy } from './change-policy'
import { changedFilesForLocalPrCheck } from './changed-files'
async function run(cmd: string[], options: { optional?: boolean } = {}) {
console.log(`\n$ ${cmd.join(' ')}`)
const proc = Bun.spawn(cmd, {
stdout: 'inherit',
stderr: 'inherit',
})
const code = await proc.exited
if (code !== 0 && !options.optional) {
process.exit(code)
}
return code
}
async function changedFiles() {
const explicit = process.argv.slice(2).filter((arg) => !arg.startsWith('--'))
return changedFilesForLocalPrCheck(explicit)
}
const files = await changedFiles()
const labels = process.env.PR_LABELS?.split(',').map((label) => label.trim()).filter(Boolean) ?? []
if (process.env.ALLOW_CLI_CORE_CHANGE === '1' && !labels.includes('allow-cli-core-change')) {
labels.push('allow-cli-core-change')
}
if (process.env.ALLOW_MISSING_TESTS === '1' && !labels.includes('allow-missing-tests')) {
labels.push('allow-missing-tests')
}
if (process.env.ALLOW_COVERAGE_BASELINE_CHANGE === '1' && !labels.includes('allow-coverage-baseline-change')) {
labels.push('allow-coverage-baseline-change')
}
const result = evaluateChangePolicy(files, labels)
console.log('PR local check plan')
console.log(` Files: ${files.length}`)
console.log(` Areas: ${result.areas.length ? result.areas.join(', ') : 'none'}`)
if (result.blockingReason) {
console.error('\nBlocked:')
for (const reason of result.blockingReasons) {
console.error(`- ${reason}`)
}
console.error('Use ALLOW_CLI_CORE_CHANGE=1, ALLOW_MISSING_TESTS=1, or ALLOW_COVERAGE_BASELINE_CHANGE=1 only after maintainer approval.')
process.exit(1)
}
if (result.checks.policy) {
await run(['bun', 'run', 'check:policy'])
}
if (result.checks.desktop) {
await run(['bun', 'run', 'check:desktop'])
}
if (result.checks.server) {
await run(['bun', 'run', 'check:server'])
}
if (result.checks.providerContract) {
await run(['bun', 'run', 'check:provider-contract'])
}
if (result.checks.chatContract) {
await run(['bun', 'run', 'check:chat-contract'])
}
if (result.checks.adapters) {
await run(['bun', 'run', 'check:adapters'])
}
if (result.checks.desktopNative) {
await run(['bun', 'run', 'check:native'])
}
if (result.checks.persistence) {
await run(['bun', 'run', 'check:persistence-upgrade'])
}
if (result.checks.docs) {
await run(['bun', 'run', 'check:docs'])
}
console.log('\nPR local checks completed.')