@amiable-dev/docusaurus-plugin-stentorosaur 0.16.0 → 0.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/data-source-resolver.client.d.ts +23 -0
- package/lib/data-source-resolver.client.d.ts.map +1 -0
- package/lib/data-source-resolver.client.js +63 -0
- package/lib/hooks/useStatusData.js +2 -2
- package/lib/theme/StatusPage/index.js +2 -2
- package/lib/theme/UptimeStatusPage/index.js +2 -2
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
- package/scripts/calculate-actions-minutes.js +276 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR-001: Client-Safe Data Source Resolver
|
|
3
|
+
*
|
|
4
|
+
* This module provides URL building utilities that can be safely imported
|
|
5
|
+
* in browser/client contexts. It does NOT import any Node.js-only modules
|
|
6
|
+
* like @docusaurus/utils-validation.
|
|
7
|
+
*
|
|
8
|
+
* For server-side validation and resolution, use data-source-resolver.ts.
|
|
9
|
+
*
|
|
10
|
+
* @see docs/adrs/ADR-001-configurable-data-fetching-strategies.md
|
|
11
|
+
*/
|
|
12
|
+
import type { DataSource } from './types';
|
|
13
|
+
/**
|
|
14
|
+
* Build the fetch URL for a given DataSource configuration.
|
|
15
|
+
*
|
|
16
|
+
* This is the client-safe version that can be used in browser contexts.
|
|
17
|
+
* It assumes the DataSource has already been validated.
|
|
18
|
+
*
|
|
19
|
+
* @param dataSource - Validated DataSource configuration
|
|
20
|
+
* @returns URL string for fetching, or null for build-only strategy
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildFetchUrl(dataSource: DataSource): string | null;
|
|
23
|
+
//# sourceMappingURL=data-source-resolver.client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-source-resolver.client.d.ts","sourceRoot":"","sources":["../src/data-source-resolver.client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAU1C;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAsCnE"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ADR-001: Client-Safe Data Source Resolver
|
|
4
|
+
*
|
|
5
|
+
* This module provides URL building utilities that can be safely imported
|
|
6
|
+
* in browser/client contexts. It does NOT import any Node.js-only modules
|
|
7
|
+
* like @docusaurus/utils-validation.
|
|
8
|
+
*
|
|
9
|
+
* For server-side validation and resolution, use data-source-resolver.ts.
|
|
10
|
+
*
|
|
11
|
+
* @see docs/adrs/ADR-001-configurable-data-fetching-strategies.md
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.buildFetchUrl = buildFetchUrl;
|
|
15
|
+
/**
|
|
16
|
+
* Default values for GitHub strategy
|
|
17
|
+
*/
|
|
18
|
+
const GITHUB_DEFAULTS = {
|
|
19
|
+
branch: 'status-data',
|
|
20
|
+
path: 'current.json',
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Build the fetch URL for a given DataSource configuration.
|
|
24
|
+
*
|
|
25
|
+
* This is the client-safe version that can be used in browser contexts.
|
|
26
|
+
* It assumes the DataSource has already been validated.
|
|
27
|
+
*
|
|
28
|
+
* @param dataSource - Validated DataSource configuration
|
|
29
|
+
* @returns URL string for fetching, or null for build-only strategy
|
|
30
|
+
*/
|
|
31
|
+
function buildFetchUrl(dataSource) {
|
|
32
|
+
switch (dataSource.strategy) {
|
|
33
|
+
case 'github': {
|
|
34
|
+
const { owner, repo, branch = GITHUB_DEFAULTS.branch, path = GITHUB_DEFAULTS.path } = dataSource;
|
|
35
|
+
return `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/${path}`;
|
|
36
|
+
}
|
|
37
|
+
case 'http': {
|
|
38
|
+
let url = dataSource.url;
|
|
39
|
+
// Append cache-busting parameter if enabled
|
|
40
|
+
if (dataSource.cacheBust) {
|
|
41
|
+
const timestamp = Date.now();
|
|
42
|
+
const separator = url.includes('?') ? '&' : '?';
|
|
43
|
+
url = `${url}${separator}t=${timestamp}`;
|
|
44
|
+
}
|
|
45
|
+
return url;
|
|
46
|
+
}
|
|
47
|
+
case 'static': {
|
|
48
|
+
// Use file:// protocol for local files
|
|
49
|
+
const path = dataSource.path;
|
|
50
|
+
if (path.startsWith('/')) {
|
|
51
|
+
return `file://${path}`;
|
|
52
|
+
}
|
|
53
|
+
return `file://${path}`;
|
|
54
|
+
}
|
|
55
|
+
case 'build-only':
|
|
56
|
+
return null;
|
|
57
|
+
default: {
|
|
58
|
+
// Exhaustive check
|
|
59
|
+
const _exhaustive = dataSource;
|
|
60
|
+
throw new Error(`Unknown strategy: ${_exhaustive.strategy}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
16
|
exports.useStatusData = useStatusData;
|
|
17
17
|
const react_1 = require("react");
|
|
18
|
-
const
|
|
18
|
+
const data_source_resolver_client_1 = require("../data-source-resolver.client");
|
|
19
19
|
const data_source_validator_1 = require("../data-source-validator");
|
|
20
20
|
/**
|
|
21
21
|
* Custom hook for fetching status data based on DataSource configuration.
|
|
@@ -45,7 +45,7 @@ function useStatusData(options) {
|
|
|
45
45
|
*/
|
|
46
46
|
const fetchData = (0, react_1.useCallback)(async () => {
|
|
47
47
|
// Build fetch URL based on strategy
|
|
48
|
-
let url = (0,
|
|
48
|
+
let url = (0, data_source_resolver_client_1.buildFetchUrl)(dataSource);
|
|
49
49
|
// Build-only strategy doesn't fetch
|
|
50
50
|
if (url === null) {
|
|
51
51
|
setLoading(false);
|
|
@@ -18,7 +18,7 @@ const IncidentHistory_1 = __importDefault(require("../IncidentHistory"));
|
|
|
18
18
|
const MaintenanceList_1 = __importDefault(require("../Maintenance/MaintenanceList"));
|
|
19
19
|
const PerformanceMetrics_1 = __importDefault(require("../PerformanceMetrics"));
|
|
20
20
|
const version_1 = require("../../version");
|
|
21
|
-
const
|
|
21
|
+
const data_source_resolver_client_1 = require("../../data-source-resolver.client");
|
|
22
22
|
const styles_module_css_1 = __importDefault(require("./styles.module.css"));
|
|
23
23
|
function StatusPage({ statusData }) {
|
|
24
24
|
const { items = [], incidents = [], maintenance = [], lastUpdated, showServices = true, showIncidents = true, showPerformanceMetrics = true, useDemoData = false, fetchUrl, dataSource, } = statusData || {};
|
|
@@ -31,7 +31,7 @@ function StatusPage({ statusData }) {
|
|
|
31
31
|
const dataBaseUrl = (0, react_1.useMemo)(() => {
|
|
32
32
|
if (dataSource) {
|
|
33
33
|
// Build URL from dataSource, stripping the file part to get base URL
|
|
34
|
-
const url = (0,
|
|
34
|
+
const url = (0, data_source_resolver_client_1.buildFetchUrl)(dataSource);
|
|
35
35
|
if (url) {
|
|
36
36
|
// Remove file:// prefix for browser context
|
|
37
37
|
const cleanUrl = url.startsWith('file://') ? url.replace('file://', '') : url;
|
|
@@ -17,7 +17,7 @@ const IncidentHistory_1 = __importDefault(require("../IncidentHistory"));
|
|
|
17
17
|
const MaintenanceList_1 = __importDefault(require("../Maintenance/MaintenanceList"));
|
|
18
18
|
const StatusBoard_1 = __importDefault(require("../StatusBoard"));
|
|
19
19
|
const PerformanceMetrics_1 = __importDefault(require("../PerformanceMetrics"));
|
|
20
|
-
const
|
|
20
|
+
const data_source_resolver_client_1 = require("../../data-source-resolver.client");
|
|
21
21
|
const styles_module_css_1 = __importDefault(require("./styles.module.css"));
|
|
22
22
|
// Default configuration with all sections enabled
|
|
23
23
|
const DEFAULT_CONFIG = {
|
|
@@ -42,7 +42,7 @@ function UptimeStatusPage({ statusData }) {
|
|
|
42
42
|
const dataBaseUrl = (0, react_1.useMemo)(() => {
|
|
43
43
|
if (dataSource) {
|
|
44
44
|
// Build URL from dataSource, stripping the file part to get base URL
|
|
45
|
-
const url = (0,
|
|
45
|
+
const url = (0, data_source_resolver_client_1.buildFetchUrl)(dataSource);
|
|
46
46
|
if (url) {
|
|
47
47
|
// Remove file:// prefix for browser context
|
|
48
48
|
const cleanUrl = url.startsWith('file://') ? url.replace('file://', '') : url;
|
package/lib/version.d.ts
CHANGED
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amiable-dev/docusaurus-plugin-stentorosaur",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.2",
|
|
4
4
|
"description": "A Docusaurus plugin for displaying status monitoring dashboard powered by GitHub Issues and Actions, similar to Upptime",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "src/plugin-status.d.ts",
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Calculate GitHub Actions minutes used per month for amiable-dev/amiable-docusaurus
|
|
5
|
+
*
|
|
6
|
+
* This script fetches workflow run data and calculates billable minutes.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* GITHUB_TOKEN=your_token node scripts/calculate-actions-minutes.js
|
|
10
|
+
*
|
|
11
|
+
* Options:
|
|
12
|
+
* --months N Number of months to analyze (default: 3)
|
|
13
|
+
* --verbose Show detailed output
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const { Octokit } = require('@octokit/rest');
|
|
17
|
+
|
|
18
|
+
const OWNER = 'amiable-dev';
|
|
19
|
+
const REPO = 'amiable-docusaurus';
|
|
20
|
+
|
|
21
|
+
// GitHub Actions billing multipliers (for private repos)
|
|
22
|
+
// Public repos have unlimited free minutes
|
|
23
|
+
const BILLING_MULTIPLIERS = {
|
|
24
|
+
'ubuntu-latest': 1, // Linux: 1x
|
|
25
|
+
'ubuntu-20.04': 1,
|
|
26
|
+
'ubuntu-22.04': 1,
|
|
27
|
+
'windows-latest': 2, // Windows: 2x
|
|
28
|
+
'windows-2019': 2,
|
|
29
|
+
'windows-2022': 2,
|
|
30
|
+
'macos-latest': 10, // macOS: 10x
|
|
31
|
+
'macos-11': 10,
|
|
32
|
+
'macos-12': 10,
|
|
33
|
+
'macos-13': 10,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
async function getWorkflowRuns(octokit, startDate, endDate) {
|
|
37
|
+
const runs = [];
|
|
38
|
+
let page = 1;
|
|
39
|
+
const perPage = 100;
|
|
40
|
+
|
|
41
|
+
console.log(`Fetching workflow runs from ${startDate.toISOString()} to ${endDate.toISOString()}...`);
|
|
42
|
+
|
|
43
|
+
while (true) {
|
|
44
|
+
const response = await octokit.actions.listWorkflowRunsForRepo({
|
|
45
|
+
owner: OWNER,
|
|
46
|
+
repo: REPO,
|
|
47
|
+
per_page: perPage,
|
|
48
|
+
page,
|
|
49
|
+
created: `${startDate.toISOString().split('T')[0]}..${endDate.toISOString().split('T')[0]}`,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
runs.push(...response.data.workflow_runs);
|
|
53
|
+
|
|
54
|
+
if (response.data.workflow_runs.length < perPage) {
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
page++;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return runs;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function getJobsForRun(octokit, runId) {
|
|
65
|
+
const response = await octokit.actions.listJobsForWorkflowRun({
|
|
66
|
+
owner: OWNER,
|
|
67
|
+
repo: REPO,
|
|
68
|
+
run_id: runId,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return response.data.jobs;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function calculateJobDuration(job) {
|
|
75
|
+
if (!job.started_at || !job.completed_at) {
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const start = new Date(job.started_at);
|
|
80
|
+
const end = new Date(job.completed_at);
|
|
81
|
+
const durationMs = end - start;
|
|
82
|
+
const durationMinutes = Math.ceil(durationMs / 1000 / 60); // Round up to nearest minute
|
|
83
|
+
|
|
84
|
+
return durationMinutes;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function getRunnerMultiplier(runnerName) {
|
|
88
|
+
if (!runnerName) return 1;
|
|
89
|
+
|
|
90
|
+
for (const [key, multiplier] of Object.entries(BILLING_MULTIPLIERS)) {
|
|
91
|
+
if (runnerName.toLowerCase().includes(key.toLowerCase())) {
|
|
92
|
+
return multiplier;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return 1; // Default to Linux multiplier
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function analyzeMonthlyUsage(octokit, months = 3, verbose = false) {
|
|
100
|
+
const now = new Date();
|
|
101
|
+
const monthlyData = {};
|
|
102
|
+
|
|
103
|
+
// Initialize monthly buckets
|
|
104
|
+
for (let i = 0; i < months; i++) {
|
|
105
|
+
const date = new Date(now.getFullYear(), now.getMonth() - i, 1);
|
|
106
|
+
const monthKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
|
|
107
|
+
monthlyData[monthKey] = {
|
|
108
|
+
runs: 0,
|
|
109
|
+
jobs: 0,
|
|
110
|
+
totalMinutes: 0,
|
|
111
|
+
billableMinutes: 0,
|
|
112
|
+
workflows: {},
|
|
113
|
+
runners: {},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Fetch workflow runs for the entire period
|
|
118
|
+
const startDate = new Date(now.getFullYear(), now.getMonth() - months + 1, 1);
|
|
119
|
+
const endDate = now;
|
|
120
|
+
|
|
121
|
+
const runs = await getWorkflowRuns(octokit, startDate, endDate);
|
|
122
|
+
|
|
123
|
+
console.log(`\nFound ${runs.length} workflow runs in the last ${months} months\n`);
|
|
124
|
+
|
|
125
|
+
// Process each run
|
|
126
|
+
for (const run of runs) {
|
|
127
|
+
const runDate = new Date(run.created_at);
|
|
128
|
+
const monthKey = `${runDate.getFullYear()}-${String(runDate.getMonth() + 1).padStart(2, '0')}`;
|
|
129
|
+
|
|
130
|
+
if (!monthlyData[monthKey]) continue;
|
|
131
|
+
|
|
132
|
+
monthlyData[monthKey].runs++;
|
|
133
|
+
|
|
134
|
+
// Get jobs for this run
|
|
135
|
+
const jobs = await getJobsForRun(octokit, run.id);
|
|
136
|
+
|
|
137
|
+
for (const job of jobs) {
|
|
138
|
+
const duration = calculateJobDuration(job);
|
|
139
|
+
const multiplier = getRunnerMultiplier(job.runner_name);
|
|
140
|
+
const billableMinutes = duration * multiplier;
|
|
141
|
+
|
|
142
|
+
monthlyData[monthKey].jobs++;
|
|
143
|
+
monthlyData[monthKey].totalMinutes += duration;
|
|
144
|
+
monthlyData[monthKey].billableMinutes += billableMinutes;
|
|
145
|
+
|
|
146
|
+
// Track by workflow
|
|
147
|
+
const workflowName = run.name || run.path;
|
|
148
|
+
if (!monthlyData[monthKey].workflows[workflowName]) {
|
|
149
|
+
monthlyData[monthKey].workflows[workflowName] = {
|
|
150
|
+
runs: 0,
|
|
151
|
+
minutes: 0,
|
|
152
|
+
billableMinutes: 0,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
monthlyData[monthKey].workflows[workflowName].runs++;
|
|
156
|
+
monthlyData[monthKey].workflows[workflowName].minutes += duration;
|
|
157
|
+
monthlyData[monthKey].workflows[workflowName].billableMinutes += billableMinutes;
|
|
158
|
+
|
|
159
|
+
// Track by runner
|
|
160
|
+
const runnerType = job.runner_name || 'unknown';
|
|
161
|
+
if (!monthlyData[monthKey].runners[runnerType]) {
|
|
162
|
+
monthlyData[monthKey].runners[runnerType] = {
|
|
163
|
+
jobs: 0,
|
|
164
|
+
minutes: 0,
|
|
165
|
+
billableMinutes: 0,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
monthlyData[monthKey].runners[runnerType].jobs++;
|
|
169
|
+
monthlyData[monthKey].runners[runnerType].minutes += duration;
|
|
170
|
+
monthlyData[monthKey].runners[runnerType].billableMinutes += billableMinutes;
|
|
171
|
+
|
|
172
|
+
if (verbose) {
|
|
173
|
+
console.log(` [${monthKey}] ${workflowName}: ${duration}min (${billableMinutes} billable) on ${runnerType}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Add small delay to avoid rate limiting
|
|
178
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return monthlyData;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function printReport(monthlyData) {
|
|
185
|
+
console.log('\n=== GitHub Actions Usage Report ===\n');
|
|
186
|
+
console.log(`Repository: ${OWNER}/${REPO}\n`);
|
|
187
|
+
|
|
188
|
+
const sortedMonths = Object.keys(monthlyData).sort().reverse();
|
|
189
|
+
|
|
190
|
+
let totalRuns = 0;
|
|
191
|
+
let totalJobs = 0;
|
|
192
|
+
let totalMinutes = 0;
|
|
193
|
+
let totalBillableMinutes = 0;
|
|
194
|
+
|
|
195
|
+
for (const month of sortedMonths) {
|
|
196
|
+
const data = monthlyData[month];
|
|
197
|
+
totalRuns += data.runs;
|
|
198
|
+
totalJobs += data.jobs;
|
|
199
|
+
totalMinutes += data.totalMinutes;
|
|
200
|
+
totalBillableMinutes += data.billableMinutes;
|
|
201
|
+
|
|
202
|
+
console.log(`Month: ${month}`);
|
|
203
|
+
console.log(` Workflow Runs: ${data.runs}`);
|
|
204
|
+
console.log(` Total Jobs: ${data.jobs}`);
|
|
205
|
+
console.log(` Actual Minutes: ${data.totalMinutes.toLocaleString()}`);
|
|
206
|
+
console.log(` Billable Minutes: ${data.billableMinutes.toLocaleString()}`);
|
|
207
|
+
|
|
208
|
+
// Top workflows
|
|
209
|
+
const topWorkflows = Object.entries(data.workflows)
|
|
210
|
+
.sort((a, b) => b[1].billableMinutes - a[1].billableMinutes)
|
|
211
|
+
.slice(0, 5);
|
|
212
|
+
|
|
213
|
+
if (topWorkflows.length > 0) {
|
|
214
|
+
console.log('\n Top Workflows:');
|
|
215
|
+
for (const [name, stats] of topWorkflows) {
|
|
216
|
+
console.log(` - ${name}: ${stats.runs} runs, ${stats.billableMinutes} billable minutes`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Runner breakdown
|
|
221
|
+
console.log('\n By Runner Type:');
|
|
222
|
+
for (const [runner, stats] of Object.entries(data.runners)) {
|
|
223
|
+
console.log(` - ${runner}: ${stats.jobs} jobs, ${stats.minutes} min (${stats.billableMinutes} billable)`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
console.log('\n');
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
console.log('=== Overall Totals ===');
|
|
230
|
+
console.log(`Total Runs: ${totalRuns}`);
|
|
231
|
+
console.log(`Total Jobs: ${totalJobs}`);
|
|
232
|
+
console.log(`Total Actual Minutes: ${totalMinutes.toLocaleString()}`);
|
|
233
|
+
console.log(`Total Billable Minutes: ${totalBillableMinutes.toLocaleString()}`);
|
|
234
|
+
|
|
235
|
+
if (totalRuns > 0) {
|
|
236
|
+
console.log(`\nAverage per Run: ${Math.round(totalMinutes / totalRuns)} minutes (${Math.round(totalBillableMinutes / totalRuns)} billable)`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async function main() {
|
|
241
|
+
const token = process.env.GITHUB_TOKEN;
|
|
242
|
+
if (!token) {
|
|
243
|
+
console.error('Error: GITHUB_TOKEN environment variable is required');
|
|
244
|
+
console.error('Usage: GITHUB_TOKEN=your_token node scripts/calculate-actions-minutes.js');
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Parse command line arguments
|
|
249
|
+
const args = process.argv.slice(2);
|
|
250
|
+
let months = 3;
|
|
251
|
+
let verbose = false;
|
|
252
|
+
|
|
253
|
+
for (let i = 0; i < args.length; i++) {
|
|
254
|
+
if (args[i] === '--months' && args[i + 1]) {
|
|
255
|
+
months = parseInt(args[i + 1], 10);
|
|
256
|
+
i++;
|
|
257
|
+
} else if (args[i] === '--verbose') {
|
|
258
|
+
verbose = true;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const octokit = new Octokit({ auth: token });
|
|
263
|
+
|
|
264
|
+
try {
|
|
265
|
+
const monthlyData = await analyzeMonthlyUsage(octokit, months, verbose);
|
|
266
|
+
printReport(monthlyData);
|
|
267
|
+
} catch (error) {
|
|
268
|
+
console.error('Error:', error.message);
|
|
269
|
+
if (error.response) {
|
|
270
|
+
console.error('Response:', error.response.data);
|
|
271
|
+
}
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
main();
|
package/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["./src/annotation-utils.ts","./src/data-source-resolver.ts","./src/data-source-validator.ts","./src/demo-data.ts","./src/github-service.ts","./src/historical-data.ts","./src/index.ts","./src/label-utils.ts","./src/maintenance-utils.ts","./src/options.ts","./src/plugin-status.d.ts","./src/time-utils.ts","./src/types.ts","./src/version.ts","./src/hooks/index.ts","./src/hooks/useStatusData.ts","./src/notifications/simple-index.ts","./src/notifications/simple-notification-service.ts","./src/notifications/types.ts","./src/notifications/providers/discord-provider.ts","./src/notifications/providers/email-provider.ts","./src/notifications/providers/slack-provider.ts","./src/notifications/providers/telegram-provider.ts","./src/theme/css-modules.d.ts","./src/theme/theme-layout.d.ts","./src/theme/ChartPanel/index.tsx","./src/theme/IncidentHistory/index.tsx","./src/theme/Maintenance/MaintenanceItem/index.tsx","./src/theme/Maintenance/MaintenanceList/index.tsx","./src/theme/PerformanceMetrics/index.tsx","./src/theme/ResponseTimeChart/index.tsx","./src/theme/SLIChart/index.tsx","./src/theme/StatusBoard/index.tsx","./src/theme/StatusHistory/index.tsx","./src/theme/StatusItem/MiniHeatmap.tsx","./src/theme/StatusItem/index.tsx","./src/theme/StatusPage/index.tsx","./src/theme/UptimeChart/index.tsx","./src/theme/UptimeStatusPage/index.tsx","./src/theme/components/ExportButton.tsx","./src/theme/hooks/useChartExport.ts","./src/theme/hooks/useDataExport.ts","./src/utils/csv.ts","./src/utils/markdown.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["./src/annotation-utils.ts","./src/data-source-resolver.client.ts","./src/data-source-resolver.ts","./src/data-source-validator.ts","./src/demo-data.ts","./src/github-service.ts","./src/historical-data.ts","./src/index.ts","./src/label-utils.ts","./src/maintenance-utils.ts","./src/options.ts","./src/plugin-status.d.ts","./src/time-utils.ts","./src/types.ts","./src/version.ts","./src/hooks/index.ts","./src/hooks/useStatusData.ts","./src/notifications/simple-index.ts","./src/notifications/simple-notification-service.ts","./src/notifications/types.ts","./src/notifications/providers/discord-provider.ts","./src/notifications/providers/email-provider.ts","./src/notifications/providers/slack-provider.ts","./src/notifications/providers/telegram-provider.ts","./src/theme/css-modules.d.ts","./src/theme/theme-layout.d.ts","./src/theme/ChartPanel/index.tsx","./src/theme/IncidentHistory/index.tsx","./src/theme/Maintenance/MaintenanceItem/index.tsx","./src/theme/Maintenance/MaintenanceList/index.tsx","./src/theme/PerformanceMetrics/index.tsx","./src/theme/ResponseTimeChart/index.tsx","./src/theme/SLIChart/index.tsx","./src/theme/StatusBoard/index.tsx","./src/theme/StatusHistory/index.tsx","./src/theme/StatusItem/MiniHeatmap.tsx","./src/theme/StatusItem/index.tsx","./src/theme/StatusPage/index.tsx","./src/theme/UptimeChart/index.tsx","./src/theme/UptimeStatusPage/index.tsx","./src/theme/components/ExportButton.tsx","./src/theme/hooks/useChartExport.ts","./src/theme/hooks/useDataExport.ts","./src/utils/csv.ts","./src/utils/markdown.ts"],"version":"5.9.3"}
|