guanghulab/scripts/generate-automation-map.js
Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

158 lines
4.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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();