mediumroast_api
Version:
Mediumroast for Git(Hub) SDK covering all categories of function.
204 lines (180 loc) • 6.07 kB
JavaScript
/**
* @fileoverview Billing operations for GitHub
* @license Apache-2.0
* @version 3.0.0
* @author Michael Hay <michael.hay@mediumroast.io>
* @copyright 2025 Mediumroast, Inc. All rights reserved.
*/
import ResponseFactory from './response.js';
/**
* Manages GitHub billing operations
*/
class BillingManager {
/**
* @constructor
* @param {Object} octokit - Octokit instance
* @param {String} orgName - GitHub organization name
*/
constructor(octokit, orgName) {
this.octokit = octokit;
this.orgName = orgName;
this.repoName = `${orgName}_discovery`; // Default repo name, can be overridden
}
/**
* Gets GitHub Actions billing information for the organization
* @returns {Promise<Array>} ResponseFactory result
*/
async getActionsBillings() {
try {
const response = await this.octokit.rest.billing.getGithubActionsBillingOrg({
org: this.orgName,
});
return ResponseFactory.success(
`Successfully retrieved Actions billing information for organization ${this.orgName}`,
response.data
);
} catch (err) {
return ResponseFactory.error(
`Failed to retrieve Actions billing information: ${err.message}`,
err,
err.status || 500
);
}
}
/**
* Gets GitHub Packages storage billing information for the organization
* @returns {Promise<Array>} ResponseFactory result
*/
async getStorageBillings() {
try {
const response = await this.octokit.rest.billing.getSharedStorageBillingOrg({
org: this.orgName,
});
return ResponseFactory.success(
`Successfully retrieved storage billing information for organization ${this.orgName}`,
response.data
);
} catch (err) {
return ResponseFactory.error(
`Failed to retrieve storage billing information: ${err.message}`,
err,
err.status || 500
);
}
}
/**
* Gets GitHub Packages billing information for the organization
* @returns {Promise<Array>} ResponseFactory result
*/
async getPackagesBillings() {
try {
const response = await this.octokit.rest.billing.getGithubPackagesBillingOrg({
org: this.orgName,
});
return ResponseFactory.success(
`Successfully retrieved Packages billing information for organization ${this.orgName}`,
response.data
);
} catch (err) {
return ResponseFactory.error(
`Failed to retrieve Packages billing information: ${err.message}`,
err,
err.status || 500
);
}
}
/**
* Gets all billing information for the organization
* @returns {Promise<Array>} ResponseFactory result with combined billing data
*/
async getAllBillings() {
try {
const [actionsResult, storageResult, packagesResult] = await Promise.all([
this.getActionsBillings(),
this.getStorageBillings(),
this.getPackagesBillings()
]);
if (!actionsResult[0] || !storageResult[0] || !packagesResult[0]) {
const failedRequests = [];
if (!actionsResult[0]) failedRequests.push('Actions');
if (!storageResult[0]) failedRequests.push('Storage');
if (!packagesResult[0]) failedRequests.push('Packages');
return ResponseFactory.error(
`Failed to retrieve some billing information: ${failedRequests.join(', ')}`,
{ actionsResult, storageResult, packagesResult },
500
);
}
const combinedData = {
actions: actionsResult[2],
storage: storageResult[2],
packages: packagesResult[2]
};
return ResponseFactory.success(
`Successfully retrieved all billing information for organization ${this.orgName}`,
combinedData
);
} catch (err) {
return ResponseFactory.error(
`Failed to retrieve billing information: ${err.message}`,
err
);
}
}
/**
* Gets workflow runs for a specific repository in the organization
* @param {string} repoName - Repository name
* @returns {Promise<Array>} ResponseFactory result with workflow runs data
*/
async getWorkflowRuns(repoName) {
try {
const response = await this.octokit.rest.actions.listWorkflowRunsForRepo({
owner: this.orgName,
repo: repoName
});
const workflowList = [];
let totalRunTimeThisMonth = 0;
const currentMonth = new Date().getMonth();
for (const workflow of response.data.workflow_runs) {
// Calculate runtime in minutes (minimum 1 minute)
const runTime = Math.ceil(
(new Date(workflow.updated_at) - new Date(workflow.created_at)) / 1000 / 60
) || 1;
// Skip workflows not from current month
if (new Date(workflow.updated_at).getMonth() !== currentMonth) {
continue;
}
totalRunTimeThisMonth += runTime;
// Add formatted workflow data to list
workflowList.push({
name: workflow.path.replace('.github/workflows/', '').replace('.yml', ''),
title: workflow.display_title,
id: workflow.id,
workflowId: workflow.workflow_id,
runTimeMinutes: runTime,
status: workflow.status,
conclusion: workflow.conclusion,
event: workflow.event,
path: workflow.path
});
}
// Sort by updated_at (most recent first)
workflowList.sort((a, b) => new Date(b.updated_at) - new Date(a.updated_at));
return ResponseFactory.success(
`Discovered ${workflowList.length} workflow runs for repository ${repoName}`,
{
workflowList,
totalRunTimeThisMonth,
repository: repoName
}
);
} catch (err) {
return ResponseFactory.error(
`Failed to retrieve workflow runs: ${err.message}`,
err,
err.status || 500
);
}
}
}
export default BillingManager;