/** * @fileoverview Repository 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'; import { encodeContent } from './utils.js'; /** * Manages low-level GitHub repository operations */ class RepositoryManager { /** * @constructor * @param {Object} octokit - Octokit instance * @param {String} orgName - GitHub organization name * @param {String} repoName - GitHub repository name */ constructor(octokit, orgName, repoName) { this.octokit = octokit; this.orgName = orgName; this.repoName = repoName; } /** * Gets content from the repository * @param {String} path - Path to the content * @param {String} ref - Branch or commit reference * @returns {Promise<Array>} ResponseFactory result */ async getContent(path, ref) { try { const response = await this.octokit.rest.repos.getContent({ owner: this.orgName, repo: this.repoName, path, ref }); return ResponseFactory.success(`Retrieved content at ${path}`, response.data); } catch (err) { return ResponseFactory.error(`Failed to get content at ${path}: ${err.message}`, err); } } /** * Creates or updates a file in the repository * @param {String} path - Path to the file * @param {String|Object} content - Content to write (will be encoded) * @param {String} message - Commit message * @param {String} branch - Branch name * @param {String} sha - SHA of the file (if updating) * @returns {Promise<Array>} ResponseFactory result */ async createOrUpdateFile(path, content, message, branch, sha = null) { try { const params = { owner: this.orgName, repo: this.repoName, path, message, content: encodeContent(content), branch }; if (sha) params.sha = sha; const response = await this.octokit.rest.repos.createOrUpdateFileContents(params); return ResponseFactory.success(`Updated ${path}`, response.data); } catch (err) { return ResponseFactory.error(`Failed to update ${path}: ${err.message}`, err); } } /** * Deletes a file from the repository * @param {String} path - Path to the file * @param {String} message - Commit message * @param {String} branch - Branch name * @param {String} sha - SHA of the file * @returns {Promise<Array>} ResponseFactory result */ async deleteFile(path, message, branch, sha) { try { const response = await this.octokit.rest.repos.deleteFile({ owner: this.orgName, repo: this.repoName, path, message, branch, sha }); return ResponseFactory.success(`Deleted ${path}`, response.data); } catch (err) { return ResponseFactory.error(`Failed to delete ${path}: ${err.message}`, err); } } /** * Gets user information * @returns {Promise<Array>} ResponseFactory result */ async getUser() { try { const response = await this.octokit.rest.users.getAuthenticated(); return ResponseFactory.success('Successfully retrieved user information', response.data); } catch (err) { return ResponseFactory.error(`Failed to get user: ${err.message}`, err.message); } } /** * Gets all users (collaborators) for the repository * @returns {Promise<Array>} ResponseFactory result */ async getCollaborators() { try { const response = await this.octokit.rest.repos.listCollaborators({ owner: this.orgName, repo: this.repoName, affiliation: 'all' }); return ResponseFactory.success('Successfully retrieved collaborators', response.data); } catch (err) { return ResponseFactory.error(`Failed to get collaborators: ${err.message}`, err.message); } } /** * Gets billing information for GitHub Actions * @returns {Promise<Array>} ResponseFactory result */ async getActionsBilling() { try { const response = await this.octokit.rest.billing.getGithubActionsBillingOrg({ org: this.orgName, }); return ResponseFactory.success('Successfully retrieved actions billing', response.data); } catch (err) { return ResponseFactory.error(`Failed to get actions billing: ${err.message}`, err.message, 404); } } /** * Gets billing information for GitHub Storage * @returns {Promise<Array>} ResponseFactory result */ async getStorageBilling() { try { const response = await this.octokit.rest.billing.getSharedStorageBillingOrg({ org: this.orgName, }); return ResponseFactory.success('Successfully retrieved storage billing', response.data); } catch (err) { return ResponseFactory.error(`Failed to get storage billing: ${err.message}`, err.message, 404); } } /** * Creates a repository in the organization * @param {String} description - Repository description * @returns {Promise<Array>} ResponseFactory result */ async createRepository(description) { try { const response = await this.octokit.rest.repos.createInOrg({ org: this.orgName, name: this.repoName, description: description, private: true }); return ResponseFactory.success(`Created repository ${this.repoName}`, response.data); } catch (err) { return ResponseFactory.error(`Failed to create repository: ${err.message}`, err.message); } } /** * Gets organization information * @returns {Promise<Array>} ResponseFactory result */ async getOrganization() { try { const response = await this.octokit.rest.orgs.get({ org: this.orgName }); return ResponseFactory.success(`Retrieved organization ${this.orgName}`, response.data); } catch (err) { return ResponseFactory.error(`Failed to get organization: ${err.message}`, err.message); } } } export default RepositoryManager;