172 lines
6.0 KiB
JavaScript
172 lines
6.0 KiB
JavaScript
// scripts/push-broadcast-to-github.js
|
||
// 铸渊 · Phase B4 · 广播文件推送到 GitHub 仓库
|
||
//
|
||
// 人格体生成广播后,通过 GitHub API 将广播 .md 文件推送到仓库。
|
||
// 路径规范:broadcasts/{developer_id}/{taskId}.md
|
||
// 提交信息:[AutoBroadcast] {taskId} · {developer} · {描述}
|
||
//
|
||
// 环境变量:
|
||
// GITHUB_TOKEN GitHub API token(推送用)
|
||
// BROADCAST_ID 广播编号(如 BC-M23-001-AW)
|
||
// DEVELOPER_ID 开发者编号(如 DEV-012)
|
||
// DEVELOPER_NAME 开发者名字(如 Awen)
|
||
// BROADCAST_CONTENT 广播全文内容(Markdown)
|
||
// MODULE_NAME 模块名(可选,如 M23)
|
||
// PHASE_NUMBER 环节号(可选,如 1)
|
||
|
||
'use strict';
|
||
|
||
var https = require('https');
|
||
var fs = require('fs');
|
||
var devSuffixMap = require('./utils/dev-suffix-map');
|
||
|
||
var GITHUB_TOKEN = process.env.GITHUB_TOKEN || '';
|
||
var BROADCAST_ID = process.env.BROADCAST_ID || '';
|
||
var DEVELOPER_ID = process.env.DEVELOPER_ID || '';
|
||
var DEVELOPER_NAME = process.env.DEVELOPER_NAME || '';
|
||
var BROADCAST_CONTENT = process.env.BROADCAST_CONTENT || '';
|
||
var MODULE_NAME = process.env.MODULE_NAME || '';
|
||
var PHASE_NUMBER = process.env.PHASE_NUMBER || '';
|
||
|
||
var REPO_OWNER = 'qinfendebingshuo';
|
||
var REPO_NAME = 'guanghulab';
|
||
|
||
// ══════════════════════════════════════════════════════════
|
||
// GitHub API 工具
|
||
// ══════════════════════════════════════════════════════════
|
||
|
||
function githubRequest(method, apiPath, body) {
|
||
return new Promise(function (resolve, reject) {
|
||
var payload = body ? JSON.stringify(body) : '';
|
||
var opts = {
|
||
hostname: 'api.github.com',
|
||
port: 443,
|
||
path: apiPath,
|
||
method: method,
|
||
headers: {
|
||
'User-Agent': 'ZhuyuanBroadcast/1.0',
|
||
'Accept': 'application/vnd.github+json',
|
||
'Content-Type': 'application/json',
|
||
'X-GitHub-Api-Version': '2022-11-28',
|
||
},
|
||
};
|
||
|
||
if (GITHUB_TOKEN) {
|
||
opts.headers['Authorization'] = 'Bearer ' + GITHUB_TOKEN;
|
||
}
|
||
|
||
if (payload) {
|
||
opts.headers['Content-Length'] = Buffer.byteLength(payload);
|
||
}
|
||
|
||
var req = https.request(opts, function (res) {
|
||
var data = '';
|
||
res.on('data', function (chunk) { data += chunk; });
|
||
res.on('end', function () {
|
||
try {
|
||
resolve({ status: res.statusCode, data: JSON.parse(data) });
|
||
} catch (e) {
|
||
resolve({ status: res.statusCode, data: data });
|
||
}
|
||
});
|
||
});
|
||
|
||
req.on('error', reject);
|
||
if (payload) req.write(payload);
|
||
req.end();
|
||
});
|
||
}
|
||
|
||
// ══════════════════════════════════════════════════════════
|
||
// 广播推送
|
||
// ══════════════════════════════════════════════════════════
|
||
|
||
async function pushBroadcast() {
|
||
if (!GITHUB_TOKEN) {
|
||
console.log('⚠️ 缺少 GITHUB_TOKEN,无法推送广播');
|
||
process.exit(1);
|
||
}
|
||
|
||
if (!BROADCAST_ID || !BROADCAST_CONTENT) {
|
||
console.log('⚠️ 缺少 BROADCAST_ID 或 BROADCAST_CONTENT');
|
||
process.exit(1);
|
||
}
|
||
|
||
// 确定开发者 ID(从广播编号提取或使用环境变量)
|
||
var devId = DEVELOPER_ID;
|
||
if (!devId) {
|
||
devId = devSuffixMap.getDevIdFromBroadcast(BROADCAST_ID) || 'UNKNOWN';
|
||
}
|
||
|
||
// 构建路径和提交信息
|
||
var filePath = 'broadcasts/' + devId + '/' + BROADCAST_ID + '.md';
|
||
var moduleLabel = MODULE_NAME || BROADCAST_ID.match(/BC-([A-Z0-9-]+)-/i)?.[1] || '';
|
||
var phaseLabel = PHASE_NUMBER ? '环节' + PHASE_NUMBER : '';
|
||
var devLabel = DEVELOPER_NAME || devId;
|
||
var commitMessage = '[AutoBroadcast] ' + BROADCAST_ID + ' · ' + devLabel + ' · ' + moduleLabel + phaseLabel;
|
||
|
||
console.log('📡 推送广播到 GitHub...');
|
||
console.log(' 路径: ' + filePath);
|
||
console.log(' 提交: ' + commitMessage);
|
||
|
||
// 检查文件是否已存在(获取 SHA)
|
||
var existingRes = await githubRequest('GET',
|
||
'/repos/' + REPO_OWNER + '/' + REPO_NAME + '/contents/' + filePath);
|
||
|
||
var sha = null;
|
||
if (existingRes.status === 200 && existingRes.data && existingRes.data.sha) {
|
||
sha = existingRes.data.sha;
|
||
console.log(' → 文件已存在,将覆盖更新 (sha: ' + sha.slice(0, 8) + ')');
|
||
}
|
||
|
||
// Base64 编码广播内容
|
||
var contentBase64 = Buffer.from(BROADCAST_CONTENT, 'utf8').toString('base64');
|
||
|
||
// 创建或更新文件
|
||
var putBody = {
|
||
message: commitMessage,
|
||
content: contentBase64,
|
||
committer: {
|
||
name: 'zhuyuan-agent[bot]',
|
||
email: 'zhuyuan-agent[bot]@users.noreply.github.com',
|
||
},
|
||
};
|
||
|
||
if (sha) {
|
||
putBody.sha = sha;
|
||
}
|
||
|
||
var putRes = await githubRequest('PUT',
|
||
'/repos/' + REPO_OWNER + '/' + REPO_NAME + '/contents/' + filePath,
|
||
putBody);
|
||
|
||
if (putRes.status === 200 || putRes.status === 201) {
|
||
console.log('✅ 广播已推送: ' + filePath);
|
||
console.log(' → commit: ' + (putRes.data.commit ? putRes.data.commit.sha.slice(0, 8) : 'unknown'));
|
||
|
||
// 输出到 GITHUB_OUTPUT
|
||
var outputFile = process.env.GITHUB_OUTPUT;
|
||
if (outputFile) {
|
||
fs.appendFileSync(outputFile, 'broadcast_pushed=true\n');
|
||
fs.appendFileSync(outputFile, 'broadcast_path=' + filePath + '\n');
|
||
fs.appendFileSync(outputFile, 'broadcast_commit=' + (putRes.data.commit ? putRes.data.commit.sha : '') + '\n');
|
||
}
|
||
} else {
|
||
console.error('❌ 广播推送失败: HTTP ' + putRes.status);
|
||
console.error(' → ' + JSON.stringify(putRes.data));
|
||
|
||
// 输出失败状态
|
||
var outputFile = process.env.GITHUB_OUTPUT;
|
||
if (outputFile) {
|
||
fs.appendFileSync(outputFile, 'broadcast_pushed=false\n');
|
||
}
|
||
|
||
process.exit(1);
|
||
}
|
||
}
|
||
|
||
pushBroadcast().catch(function (err) {
|
||
console.error('❌ 广播推送异常: ' + err.message);
|
||
process.exit(1);
|
||
});
|