guanghulab/scripts/pipeline-reporter.js

141 lines
4.7 KiB
JavaScript
Raw Normal View History

/**
* 实时进度上报模块
* 文件位置scripts/pipeline-reporter.js
*
* 每完成一步 Issue 评论区发一条新评论开发者刷新即可看到实时进度
*
* 使用方式CLI
* ISSUE_NUMBER=92 STEP_NUM=2 STEP_NAME="解析内容" STEP_STATUS=ok \
* STEP_DETAIL="广播编号: BC-M22-007-AW" GITHUB_TOKEN=xxx \
* node scripts/pipeline-reporter.js
*
* 或在 Node.js require
* const { reportStep, reportComplete } = require('./pipeline-reporter');
*/
const https = require('https');
const OWNER = process.env.GITHUB_REPOSITORY
? process.env.GITHUB_REPOSITORY.split('/')[0]
: 'qinfendebingshuo';
const REPO = process.env.GITHUB_REPOSITORY
? process.env.GITHUB_REPOSITORY.split('/')[1]
: 'guanghulab';
/**
* 发送 GitHub API 请求
*/
function githubAPI(method, path, data) {
return new Promise((resolve, reject) => {
const body = data ? JSON.stringify(data) : null;
const req = https.request({
hostname: 'api.github.com',
path: path,
method: method,
headers: {
'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`,
'Accept': 'application/vnd.github.v3+json',
'User-Agent': 'Zhuyuan-Pipeline-Reporter',
'Content-Type': 'application/json',
...(body ? { 'Content-Length': Buffer.byteLength(body) } : {})
}
}, (res) => {
let responseBody = '';
res.on('data', chunk => { responseBody += chunk; });
res.on('end', () => {
if (res.statusCode >= 200 && res.statusCode < 300) {
try { resolve(JSON.parse(responseBody)); }
catch (e) { console.error('⚠️ JSON parse error:', e.message); resolve(responseBody); }
} else {
reject(new Error(`GitHub API ${res.statusCode}: ${responseBody.slice(0, 200)}`));
}
});
});
req.on('error', reject);
if (body) req.write(body);
req.end();
});
}
/**
* 每完成一步 Issue 评论区发一条新评论
* @param {number} issueNumber - Issue 编号
* @param {number} stepNum - 步骤编号1-8
* @param {string} stepName - 步骤名称
* @param {'ok'|'error'|'skip'} status - 步骤状态
* @param {string} detail - 详情说明
*/
async function reportStep(issueNumber, stepNum, stepName, status, detail) {
const icon = status === 'ok' ? '✅' : status === 'error' ? '❌' : '⏭️';
const statusText = status === 'ok' ? '已完成' : status === 'error' ? '失败' : '跳过';
const body = [
`${icon} **步骤 ${stepNum}/8 · ${stepName}** · ${statusText}`,
'',
detail,
'',
`——铸渊ICE-GL-ZY001· ${new Date().toISOString()}`
].join('\n');
await githubAPI('POST', `/repos/${OWNER}/${REPO}/issues/${issueNumber}/comments`, { body });
}
/**
* 闭环完成时发最终汇总
* @param {number} issueNumber - Issue 编号
* @param {boolean} success - 是否全部成功
* @param {string} summary - 汇总内容
*/
async function reportComplete(issueNumber, success, summary) {
const icon = success ? '🎉' : '⚠️';
const title = success ? '闭环处理完成' : '闭环处理异常';
const body = [
`## ${icon} ${title}`,
'',
summary,
'',
success
? '> 新广播已生成,结果将发送到您的邮箱。'
: '> 部分步骤异常,已记录日志。冰朔会在下次巡检时处理。',
'',
`——铸渊ICE-GL-ZY001· ${new Date().toISOString()}`
].join('\n');
await githubAPI('POST', `/repos/${OWNER}/${REPO}/issues/${issueNumber}/comments`, { body });
}
// ━━━ CLI 模式:直接 node scripts/pipeline-reporter.js ━━━
if (require.main === module) {
const issueNumber = parseInt(process.env.ISSUE_NUMBER);
const stepNum = parseInt(process.env.STEP_NUM);
const stepName = process.env.STEP_NAME || '';
const status = process.env.STEP_STATUS || 'ok';
const detail = process.env.STEP_DETAIL || '';
const isComplete = process.env.REPORT_COMPLETE === 'true';
const isSuccess = process.env.REPORT_SUCCESS !== 'false';
if (!issueNumber) {
console.error('❌ 缺少 ISSUE_NUMBER');
process.exit(1);
}
(async () => {
try {
if (isComplete) {
await reportComplete(issueNumber, isSuccess, detail);
console.log(`📋 闭环汇总已发送 · Issue #${issueNumber}`);
} else {
await reportStep(issueNumber, stepNum, stepName, status, detail);
console.log(`📋 步骤 ${stepNum}/8 · ${stepName} · ${status} 已上报 · Issue #${issueNumber}`);
}
} catch (err) {
console.error(`⚠️ 进度上报失败: ${err.message}`);
// 上报失败不应阻断管道
process.exit(0);
}
})();
}
module.exports = { reportStep, reportComplete };