158 lines
4.4 KiB
JavaScript
158 lines
4.4 KiB
JavaScript
// 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();
|