guanghulab/scripts/skyeye/asop-submit.js

137 lines
4.0 KiB
JavaScript
Raw Permalink Normal View History

// scripts/skyeye/asop-submit.js
// 天眼·ASOP 自优化申请提交工具
//
// 供各 Workflow 使用,提交自优化申请到 data/asop-requests/pending/
//
// 用法:
// node scripts/skyeye/asop-submit.js --workflow "xxx.yml" --level GL2 \
// --problem "描述" --proposal "方案" --evidence "证据" \
// --affected-workflows "a.yml,b.yml" --affected-files "f1,f2" --risk "低"
//
// 或在其他脚本中引入:
// const { submitASOPRequest } = require('./asop-submit');
'use strict';
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '../..');
const PENDING_DIR = path.join(ROOT, 'data/asop-requests/pending');
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
// ━━━ 生成申请 ID ━━━
function generateRequestId() {
const now = new Date();
const bjDate = new Date(now.getTime() + BEIJING_OFFSET_MS);
const dateStr = bjDate.toISOString().split('T')[0].replace(/-/g, '');
const seq = String(Math.floor(Math.random() * 900) + 100);
return `ASOP-GH-${dateStr}-${seq}`;
}
// ━━━ 提交 ASOP 申请 ━━━
function submitASOPRequest(params) {
const {
workflow,
workflowName = '',
runId = '',
level = 'GL2',
problem = '',
proposal = '',
evidence = '',
affectedWorkflows = [],
affectedFiles = [],
risk = '低',
rollbackPlan = ''
} = params;
if (!workflow) {
console.error('❌ ASOP: workflow 参数必填');
return null;
}
if (!['GL1', 'GL2', 'GL3'].includes(level)) {
console.error('❌ ASOP: level 必须是 GL1/GL2/GL3');
return null;
}
if (!problem || !proposal) {
console.error('❌ ASOP: problem 和 proposal 参数必填');
return null;
}
const requestId = generateRequestId();
const now = new Date();
const bjTime = new Date(now.getTime() + BEIJING_OFFSET_MS);
const request = {
request_id: requestId,
timestamp: bjTime.toISOString().replace('T', ' ').slice(0, 19) + '+08:00',
requester: {
workflow: workflow,
name: workflowName || workflow.replace('.yml', ''),
run_id: runId || process.env.GITHUB_RUN_ID || ''
},
level: level,
current_problem: problem,
proposed_optimization: proposal,
impact_assessment: {
affected_workflows: affectedWorkflows,
affected_files: affectedFiles,
risk: risk
},
data_evidence: evidence,
rollback_plan: rollbackPlan
};
// GL1 直接执行,不写入 pending
if (level === 'GL1') {
console.log(`🔄 ASOP GL1 · ${requestId} · 自主执行,不需审批`);
console.log(` 问题: ${problem}`);
console.log(` 方案: ${proposal}`);
return request;
}
// GL2/GL3 写入 pending/
fs.mkdirSync(PENDING_DIR, { recursive: true });
const filePath = path.join(PENDING_DIR, `${requestId}.json`);
fs.writeFileSync(filePath, JSON.stringify(request, null, 2) + '\n');
console.log(`🔄 ASOP ${level} · ${requestId} · 已提交到 pending/`);
console.log(` 问题: ${problem}`);
console.log(` 方案: ${proposal}`);
if (level === 'GL3') {
console.log(` ⬆️ GL3 级别,需冰朔审批`);
}
return request;
}
// ━━━ 导出 ━━━
module.exports = { submitASOPRequest };
// ━━━ CLI 入口 ━━━
if (require.main === module) {
const args = process.argv.slice(2);
function getArg(name) {
const idx = args.indexOf('--' + name);
return idx >= 0 && idx + 1 < args.length ? args[idx + 1] : '';
}
const result = submitASOPRequest({
workflow: getArg('workflow'),
workflowName: getArg('name'),
runId: getArg('run-id'),
level: getArg('level') || 'GL2',
problem: getArg('problem'),
proposal: getArg('proposal'),
evidence: getArg('evidence'),
affectedWorkflows: getArg('affected-workflows') ? getArg('affected-workflows').split(',') : [],
affectedFiles: getArg('affected-files') ? getArg('affected-files').split(',') : [],
risk: getArg('risk') || '低',
rollbackPlan: getArg('rollback-plan')
});
if (result) {
console.log(JSON.stringify(result, null, 2));
}
}