95 lines
3.2 KiB
JavaScript
95 lines
3.2 KiB
JavaScript
|
|
/**
|
|||
|
|
* buffer/scripts/quota-calculator.js
|
|||
|
|
*
|
|||
|
|
* 配额预算计算器
|
|||
|
|
* 计算当前月度 GitHub Actions 使用量预估
|
|||
|
|
*
|
|||
|
|
* 守护: PER-ZY001 铸渊
|
|||
|
|
* 系统: SYS-GLW-0001
|
|||
|
|
* 版权: 国作登字-2026-A-00037559
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
const fs = require('fs');
|
|||
|
|
const path = require('path');
|
|||
|
|
|
|||
|
|
const CONFIG_PATH = path.join(__dirname, '..', 'config', 'buffer-config.json');
|
|||
|
|
|
|||
|
|
function loadConfig() {
|
|||
|
|
if (!fs.existsSync(CONFIG_PATH)) {
|
|||
|
|
console.error('[quota] buffer-config.json not found');
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
return JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function calculateQuota() {
|
|||
|
|
const config = loadConfig();
|
|||
|
|
const budget = config.quota_budget;
|
|||
|
|
|
|||
|
|
const daysInMonth = 30;
|
|||
|
|
const dailyRuns = budget.max_workflow_runs_per_day;
|
|||
|
|
const minutesPerRun = budget.estimated_minutes_per_run;
|
|||
|
|
const freeLimit = budget.github_free_limit_minutes;
|
|||
|
|
|
|||
|
|
const dailyMinutes = dailyRuns * minutesPerRun;
|
|||
|
|
const monthlyMinutes = dailyMinutes * daysInMonth;
|
|||
|
|
const utilization = ((monthlyMinutes / freeLimit) * 100).toFixed(1);
|
|||
|
|
const remaining = freeLimit - monthlyMinutes;
|
|||
|
|
const emergencyFlushBudget = Math.floor(remaining / minutesPerRun);
|
|||
|
|
|
|||
|
|
const report = {
|
|||
|
|
generated_at: new Date().toISOString(),
|
|||
|
|
summary: {
|
|||
|
|
github_free_limit: `${freeLimit} minutes/month`,
|
|||
|
|
daily_scheduled_runs: dailyRuns,
|
|||
|
|
minutes_per_run: minutesPerRun,
|
|||
|
|
daily_consumption: `${dailyMinutes} minutes`,
|
|||
|
|
monthly_consumption: `${monthlyMinutes} minutes`,
|
|||
|
|
utilization_rate: `${utilization}%`,
|
|||
|
|
remaining_budget: `${remaining} minutes`,
|
|||
|
|
emergency_flush_capacity: `${emergencyFlushBudget} extra runs available`
|
|||
|
|
},
|
|||
|
|
breakdown: {
|
|||
|
|
collect_runs_per_day: 3,
|
|||
|
|
flush_runs_per_day: 1,
|
|||
|
|
total_scheduled: `${dailyRuns} runs/day × ${daysInMonth} days = ${dailyRuns * daysInMonth} runs/month`,
|
|||
|
|
total_minutes: `${dailyRuns * daysInMonth} runs × ${minutesPerRun} min = ${monthlyMinutes} min/month`
|
|||
|
|
},
|
|||
|
|
health: utilization <= 50 ? '🟢 HEALTHY' : utilization <= 80 ? '🟡 WARNING' : '🔴 CRITICAL'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return report;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function main() {
|
|||
|
|
const report = calculateQuota();
|
|||
|
|
|
|||
|
|
console.log('═══════════════════════════════════════');
|
|||
|
|
console.log('📊 GitHub Actions 配额预算报告');
|
|||
|
|
console.log('═══════════════════════════════════════');
|
|||
|
|
console.log(`📅 生成时间: ${report.generated_at}`);
|
|||
|
|
console.log(`📈 健康状态: ${report.health}`);
|
|||
|
|
console.log('');
|
|||
|
|
console.log('─── 概要 ───');
|
|||
|
|
for (const [key, value] of Object.entries(report.summary)) {
|
|||
|
|
console.log(` ${key}: ${value}`);
|
|||
|
|
}
|
|||
|
|
console.log('');
|
|||
|
|
console.log('─── 明细 ───');
|
|||
|
|
for (const [key, value] of Object.entries(report.breakdown)) {
|
|||
|
|
console.log(` ${key}: ${value}`);
|
|||
|
|
}
|
|||
|
|
console.log('═══════════════════════════════════════');
|
|||
|
|
|
|||
|
|
// 输出 JSON 到标准输出(方便其他脚本读取)
|
|||
|
|
if (process.argv.includes('--json')) {
|
|||
|
|
console.log(JSON.stringify(report, null, 2));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
module.exports = { calculateQuota };
|
|||
|
|
|
|||
|
|
if (require.main === module) {
|
|||
|
|
main();
|
|||
|
|
}
|