guanghulab/scripts/generate-automation-map.js

158 lines
4.4 KiB
JavaScript
Raw Normal View History

// scripts/generate-automation-map.js
// 自动化地图生成器 · Automation Map Generator
//
// 功能:扫描 .github/workflows/ 和自动化脚本,生成 brain/automation-map.json
// 触发方式:
// - GitHub Actions: daily-maintenance.yml
// - 本地node scripts/generate-automation-map.js
'use strict';
const fs = require('fs');
const path = require('path');
const ROOT = path.join(__dirname, '..');
const BRAIN_DIR = path.join(ROOT, 'brain');
const OUT_PATH = path.join(BRAIN_DIR, 'automation-map.json');
const now = new Date();
const nowISO = now.toISOString();
// ── 工具函数 ──
function safeRead(filePath) {
try { return fs.readFileSync(filePath, 'utf8'); } catch { return ''; }
}
function listFiles(dirPath, ext) {
try {
return fs.readdirSync(dirPath)
.filter(f => !ext || f.endsWith(ext))
.filter(f => !f.startsWith('.'));
} catch { return []; }
}
// ── 解析单个 workflow ──
function parseWorkflow(file, content) {
const nameMatch = content.match(/^name:\s*(.+)/m);
const name = nameMatch ? nameMatch[1].trim().replace(/^["']|["']$/g, '') : file;
const triggers = [];
if (/^\s{2,4}push:/m.test(content)) triggers.push('push');
if (/^\s{2,4}pull_request:/m.test(content)) triggers.push('pull_request');
if (/^\s{2,4}issues:/m.test(content)) triggers.push('issues');
if (/^\s{2,4}issue_comment:/m.test(content)) triggers.push('issue_comment');
if (/workflow_dispatch/m.test(content)) triggers.push('workflow_dispatch');
if (/workflow_call/m.test(content)) triggers.push('workflow_call');
const cronMatch = content.match(/cron:\s*['"]?([^'"#\n]+)/);
const cron = cronMatch ? cronMatch[1].trim() : null;
if (cron) triggers.push('schedule');
// Detect scripts used
const scriptRefs = [];
const scriptMatches = content.matchAll(/node\s+scripts\/([^\s'"]+)/g);
for (const m of scriptMatches) {
scriptRefs.push('scripts/' + m[1]);
}
const result = {
file,
name,
triggers: triggers.length ? triggers : ['unknown']
};
if (cron) result.cron = cron;
if (scriptRefs.length) result.scripts = scriptRefs;
return result;
}
// ── 扫描所有 workflow ──
function scanWorkflows() {
const wfDir = path.join(ROOT, '.github/workflows');
const files = listFiles(wfDir, '.yml');
return files.map(f => {
const content = safeRead(path.join(wfDir, f));
return parseWorkflow(f, content);
});
}
// ── 提取 cron jobs ──
function extractCronJobs(workflows) {
return workflows
.filter(w => w.cron)
.map(w => ({
cron: w.cron,
workflow: w.file,
name: w.name
}))
.sort((a, b) => a.cron.localeCompare(b.cron));
}
// ── 扫描部署脚本 ──
function scanDeployScripts(workflows) {
return workflows
.filter(w => /deploy/i.test(w.file) || /deploy/i.test(w.name))
.map(w => ({
workflow: w.file,
name: w.name,
triggers: w.triggers
}));
}
// ── 扫描同步脚本 ──
function scanSyncScripts() {
const scriptDir = path.join(ROOT, 'scripts');
const files = listFiles(scriptDir, '.js');
const syncScripts = [];
for (const file of files) {
const content = safeRead(path.join(scriptDir, file));
if (/sync|bridge|push-broadcast|receive|process-broadcast/i.test(file) ||
/notion.*api|@notionhq/i.test(content)) {
syncScripts.push({
script: 'scripts/' + file,
type: /sync/i.test(file) ? 'sync' :
/bridge/i.test(file) ? 'bridge' :
/broadcast/i.test(file) ? 'broadcast' : 'other'
});
}
}
return syncScripts;
}
// ── 主生成 ──
function generate() {
if (!fs.existsSync(BRAIN_DIR)) fs.mkdirSync(BRAIN_DIR, { recursive: true });
const workflows = scanWorkflows();
const cronJobs = extractCronJobs(workflows);
const deployScripts = scanDeployScripts(workflows);
const syncScripts = scanSyncScripts();
const map = {
version: '4.0',
generated_at: nowISO,
generated_by: 'scripts/generate-automation-map.js',
description: '数字地球系统自动化地图 · 所有工作流与自动化脚本',
workflows,
cron_jobs: cronJobs,
deploy_scripts: deployScripts,
data_sync_scripts: syncScripts,
status: 'stable'
};
fs.writeFileSync(OUT_PATH, JSON.stringify(map, null, 2));
console.log(`✅ automation-map.json 已生成 · ${workflows.length} 个工作流 · ${cronJobs.length} 个定时任务`);
}
generate();