mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
The desktop product needs a repeatable local gate that can prove the core Coding Agent loop still works after changes, not only that unit tests pass. This adds a quality-gate runner with PR, baseline, and release modes, structured reports, explicit quarantine metadata, and fixture-based live baseline cases that can run across provider/model targets. Constraint: Existing check:pr and CI policy behavior must remain usable while the stronger baseline grows around it Constraint: Default PR gates must not require real model credentials or provider quota Rejected: Build a standalone QA platform first | too heavy before the baseline task shape is proven Rejected: Keep unstable server exclusions hardcoded in run-server-tests | hides quarantine policy from reports and future review Confidence: medium Scope-risk: moderate Directive: Expand baseline cases by adding focused fixtures and verifiers; do not make normal PR checks depend on live providers Tested: bun test scripts/quality-gate/*.test.ts scripts/quality-gate/baseline/*.test.ts Tested: bun run check:server Tested: bun run quality:gate --mode baseline --allow-live --provider-model 2944f963-ce75-45b7-bac1-6e4f57df0970:kimi-k2.6:volc-kimi-k2.6 --provider-model 9c78d3df-7fb5-44c7-8436-3a41c3a59231:MiniMax-M2.7-highspeed:minimax-m2.7 Not-tested: desktop UI browser smoke and native release mode in this commit
60 lines
1.8 KiB
TypeScript
60 lines
1.8 KiB
TypeScript
import { mkdirSync, writeFileSync } from 'node:fs'
|
|
import { join } from 'node:path'
|
|
import type { QualityGateReport } from './types'
|
|
|
|
export function writeReport(report: QualityGateReport, outputDir: string) {
|
|
mkdirSync(outputDir, { recursive: true })
|
|
writeFileSync(join(outputDir, 'report.json'), JSON.stringify(report, null, 2) + '\n')
|
|
writeFileSync(join(outputDir, 'report.md'), renderMarkdownReport(report))
|
|
}
|
|
|
|
export function renderMarkdownReport(report: QualityGateReport) {
|
|
const lines = [
|
|
`# Quality Gate Report`,
|
|
'',
|
|
`- Run: ${report.runId}`,
|
|
`- Mode: ${report.mode}`,
|
|
`- Dry run: ${report.dryRun ? 'yes' : 'no'}`,
|
|
`- Live checks allowed: ${report.allowLive ? 'yes' : 'no'}`,
|
|
`- Git SHA: ${report.git.sha ?? 'unknown'}`,
|
|
`- Dirty worktree: ${report.git.dirty ? 'yes' : 'no'}`,
|
|
`- Started: ${report.startedAt}`,
|
|
`- Finished: ${report.finishedAt}`,
|
|
'',
|
|
`## Summary`,
|
|
'',
|
|
`- Passed: ${report.summary.passed}`,
|
|
`- Failed: ${report.summary.failed}`,
|
|
`- Skipped: ${report.summary.skipped}`,
|
|
'',
|
|
`## Lanes`,
|
|
'',
|
|
]
|
|
|
|
for (const result of report.results) {
|
|
lines.push(`### ${result.title}`)
|
|
lines.push('')
|
|
lines.push(`- ID: ${result.id}`)
|
|
lines.push(`- Status: ${result.status}`)
|
|
lines.push(`- Duration: ${result.durationMs}ms`)
|
|
if (result.command) {
|
|
lines.push(`- Command: \`${result.command.join(' ')}\``)
|
|
}
|
|
if (result.exitCode !== undefined) {
|
|
lines.push(`- Exit code: ${result.exitCode}`)
|
|
}
|
|
if (result.skipReason) {
|
|
lines.push(`- Skip reason: ${result.skipReason}`)
|
|
}
|
|
if (result.error) {
|
|
lines.push(`- Error: ${result.error}`)
|
|
}
|
|
if (result.artifactDir) {
|
|
lines.push(`- Artifacts: ${result.artifactDir}`)
|
|
}
|
|
lines.push('')
|
|
}
|
|
|
|
return lines.join('\n')
|
|
}
|