/** * ONES 测试计划结果同步脚本 * * 用法: * npx ts-node scripts/sync-ones-results.ts --plan [--dry-run] * * 流程: * 1. 读取 reports/.results.json (自动化执行后的结果) * 2. 从 ONES 拉取测试计划用例列表 * 3. 按用例名称匹配 * 4. 反写匹配成功的结果到 ONES */ import * as fs from 'fs'; import * as path from 'path'; import { TestResult } from '../utils/test-reporter'; import { fetchPlanCases, matchResults, syncResultsToOnes } from '../utils/ones-sync'; import { execSync } from 'child_process'; const ONES_CLI = '/Users/woan/local/bin/ones'; const RESULTS_FILE = path.resolve(__dirname, '../reports/.results.json'); function parseArgs() { const args = process.argv.slice(2); let planUUID = ''; let dryRun = false; for (let i = 0; i < args.length; i++) { if (args[i] === '--plan' && args[i + 1]) { planUUID = args[i + 1]; i++; } else if (args[i] === '--dry-run') { dryRun = true; } } if (!planUUID) { console.error('Usage: npx ts-node scripts/sync-ones-results.ts --plan [--dry-run]'); process.exit(1); } return { planUUID, dryRun }; } function loadResults(): TestResult[] { if (!fs.existsSync(RESULTS_FILE)) { console.error(`结果文件不存在: ${RESULTS_FILE}`); console.error('请先运行自动化测试以生成结果文件'); process.exit(1); } const data = JSON.parse(fs.readFileSync(RESULTS_FILE, 'utf-8')); return data.results || []; } function main() { const { planUUID, dryRun } = parseArgs(); console.log('='.repeat(60)); console.log(' ONES 测试计划结果同步'); console.log('='.repeat(60)); console.log(` 计划UUID: ${planUUID}`); console.log(` 模式: ${dryRun ? '预览 (dry-run)' : '实际写入'}`); console.log('-'.repeat(60)); // 1. 加载自动化结果 const testResults = loadResults(); console.log(`\n[1/4] 加载自动化结果: ${testResults.length} 条`); const passed = testResults.filter(r => r.status === 'PASS').length; const failed = testResults.filter(r => r.status === 'FAIL').length; const skipped = testResults.filter(r => r.status === 'SKIP').length; console.log(` PASS: ${passed} | FAIL: ${failed} | SKIP: ${skipped}`); // 2. 从 ONES 拉取计划用例 console.log(`\n[2/4] 从 ONES 拉取测试计划用例 ...`); const planCases = fetchPlanCases(planUUID); console.log(` 计划共 ${planCases.length} 条用例`); // 3. 匹配 console.log(`\n[3/4] 匹配自动化结果到 ONES 用例 ...`); const matched = matchResults(planCases, testResults); console.log(` 匹配成功: ${matched.size} / ${testResults.length}`); if (matched.size > 0) { console.log('\n 匹配详情:'); for (const [caseUUID, { result }] of matched) { const pc = planCases.find(c => c.caseUUID === caseUUID); const icon = result === 'passed' ? '✓' : result === 'failed' ? '✗' : '○'; console.log(` ${icon} [${result}] ${pc?.caseName || caseUUID}`); } } // 4. 反写 if (dryRun) { console.log(`\n[4/4] DRY-RUN 模式,跳过实际写入`); console.log(` 将会更新 ${matched.size} 条用例结果`); } else { console.log(`\n[4/4] 反写结果到 ONES ...`); const configStr = execSync(`${ONES_CLI} config show`, { encoding: 'utf-8' }); const config = JSON.parse(configStr); const { success, failed: failCount } = syncResultsToOnes(planUUID, matched, config.user_id); console.log(` 成功: ${success} | 失败: ${failCount}`); } console.log('\n' + '='.repeat(60)); console.log(' 同步完成'); console.log('='.repeat(60)); } main();