UNPKG

@broadshield/github-actions-workflow-marie-kondo

Version:

This library supports you in only keeping Tags, Releases, and Action Workflow Runs that spark joy, and to remove the ones often created during the PR process

223 lines 11.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Kondo = exports.basename = void 0; const github_actions_core_typed_inputs_1 = require("@broadshield/github-actions-core-typed-inputs"); const github_actions_octokit_hydrated_1 = require("@broadshield/github-actions-octokit-hydrated"); function basename(path) { if (!path) return ''; return path.split('/').reverse()[0] ?? ''; } exports.basename = basename; const releasesRoute = 'GET /repos/{owner}/{repo}/releases'; const tagsRoute = 'GET /repos/{owner}/{repo}/tags'; const workflowsRoute = 'GET /repos/{owner}/{repo}/actions/workflows'; const workflowRunsRoute = 'GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs'; const availableRoutes = { [releasesRoute]: { returnKey: 'id', lookupKey: 'release_id', }, [tagsRoute]: { returnKey: 'ref', lookupKey: 'ref', }, [workflowsRoute]: { returnKey: 'id', lookupKey: 'workflow_id', }, [workflowRunsRoute]: { returnKey: 'id', lookupKey: 'run_id', }, }; function isKeyOfResponseData(arg, responseData) { return (typeof arg === 'string' && Object.keys(responseData).includes(arg) && ['string', 'number'].includes(typeof responseData[arg])); } function parametersToString(parameters) { if (!parameters) return ''; return Object.entries(parameters) .map(([key, value]) => `${key}=${value}`) .join('&'); } function itemFilterToString(filter, responseData) { if (filter) { let key; const outputStringArray = []; for (key in filter) { if (Object.prototype.hasOwnProperty.call(filter, key)) { const verifiedKey = isKeyOfResponseData(key, responseData ?? {}) ? key : ''; const value = filter[key]; let valueString = ''; if (value instanceof RegExp) { valueString = `RegEx of ${value.toString()}`; } else if (value instanceof Date) { valueString = value.toISOString(); } else if (typeof value === 'string') { valueString = value; } else if (typeof value === 'number') { valueString = Number(value).toString(10); } if (valueString) { if (typeof verifiedKey === 'string' && verifiedKey.length > 0) { outputStringArray.push(`[(V) ${String(key)}: ${valueString}]`); } else { outputStringArray.push(`[${String(key)}: ${valueString}]`); } } } } if (outputStringArray.length > 0) { return outputStringArray.join(', '); } } return 'undefined'; } function repoToString(repo) { return `${repo.owner}/${repo.repo}`; } function assertOctokit(octokit) { if (!octokit) { throw new Error('Octokit instance not set'); } } class Kondo { constructor(options) { this.repo = options.repo; if (options.github_token && !options.octokit) { this.octokit = (0, github_actions_octokit_hydrated_1.createOctokit)(options.github_token, options.octokit); } else if (options.octokit) { this.octokit = options.octokit; } } setOctokit(octokit) { this.octokit = octokit; } getOctokit() { return this.octokit; } async getMatchingItemsFromEndpointRest(endpoint, parameters, filter, octokit = this.octokit) { assertOctokit(octokit); const filtered_return_keys = []; github_actions_core_typed_inputs_1.logger.debug(`getMatchingItemsFromEndpointRest: endpoint: ${endpoint}, parameters: ${parametersToString(parameters)}, filter: ${itemFilterToString(filter)}`); if (!filter) { throw new Error('A filter is required'); } for await (const response of octokit.paginate.iterator(endpoint, parameters)) { if (response?.data && Array.isArray(response.data)) { const entries = response.data; let item; for (item of entries) { github_actions_core_typed_inputs_1.logger.debug(`getMatchingItemsFromEndpointRest: item: ${JSON.stringify(item, undefined, 2)}`); const rKey = availableRoutes[endpoint].returnKey; const itemReturnValue = item[rKey]; github_actions_core_typed_inputs_1.logger.debug(`getMatchingItemsFromEndpointRest: item return key: ${rKey}, value: ${itemReturnValue}`); if (itemReturnValue && filter) { let filterKey; for (filterKey in filter) { if (Object.prototype.hasOwnProperty.call(filter, filterKey) && isKeyOfResponseData(filterKey, item)) { const filterValue = filter[filterKey]; const itemValue = item[filterKey]; let addToList = false; if (filterValue instanceof RegExp) { if (filterValue.test(itemValue)) { addToList = true; } } else if (filterValue instanceof Date) { if (filterValue.getTime() === new Date(itemValue).getTime()) { addToList = true; } } else if (typeof filterValue === 'string' || typeof filterValue === 'number') { if (filterValue === itemValue) { addToList = true; } } else { github_actions_core_typed_inputs_1.logger.warn(`Unknown filter value type: ${filterValue} as ${typeof filterValue}`); } if (addToList) { filtered_return_keys.push(itemReturnValue); if ((0, github_actions_core_typed_inputs_1.isDebug)()) { github_actions_core_typed_inputs_1.logger.debug(`${itemReturnValue} matches filter: ${itemFilterToString(filter, item)}`); } } } else { github_actions_core_typed_inputs_1.logger.warn(`Unknown filter key: ${String(filterKey)} as ${typeof filterKey}`); } } } } } } github_actions_core_typed_inputs_1.logger.debug(`Endpoint ${endpoint}, Total matches: ${filtered_return_keys.length}, Filter: ${itemFilterToString(filter)}`); return filtered_return_keys; } async getFilteredReleaseIdsFromRepo(parameters, filter, repo = this.repo) { return this.getMatchingItemsFromEndpointRest(releasesRoute, { ...repo, ...parameters }, filter); } async getFilteredTagRefsFromRepo(parameters, filter, repo = this.repo) { return this.getMatchingItemsFromEndpointRest(tagsRoute, { ...repo, ...parameters }, filter); } async getFilteredWorkflowIdsFromRepo(parameters, filter, repo = this.repo) { return this.getMatchingItemsFromEndpointRest(workflowsRoute, { ...repo, ...parameters }, filter); } async getFilteredWorkflowRunIdsFromRepo(parameters, filter, repo = this.repo) { return this.getMatchingItemsFromEndpointRest(workflowRunsRoute, { ...repo, ...parameters }, filter); } async deleteReleasesByIds(release_ids, repo = this.repo, octokit = this.octokit) { assertOctokit(octokit); return Promise.all(release_ids.map(async (release_id) => octokit.rest.repos.deleteRelease({ ...repo, release_id }).then((value) => github_actions_core_typed_inputs_1.logger.debug(`Successfully deleted release ${release_id} in repo ${repoToString(repo)}. status: ${value.status}`), (error) => { github_actions_core_typed_inputs_1.logger.error(`Error deleting release ${release_id} in repo ${repoToString(repo)}`); if (error instanceof Error || typeof error === 'string') { github_actions_core_typed_inputs_1.logger.error(error); } else { github_actions_core_typed_inputs_1.logger.error(JSON.stringify(error)); } }))); } async deleteTagsByRefs(refs, repo = this.repo, octokit = this.octokit) { assertOctokit(octokit); return Promise.all(refs.map(async (ref) => octokit.rest.git.deleteRef({ ...repo, ref }).then((value) => github_actions_core_typed_inputs_1.logger.debug(`Successfully deleted tag ${ref} in repo ${repoToString(repo)}. status: ${value.status}`), (error) => { github_actions_core_typed_inputs_1.logger.error(`Error deleting tag ${ref} in repo ${repoToString(repo)}`); if (error instanceof Error || typeof error === 'string') { github_actions_core_typed_inputs_1.logger.error(error); } else { github_actions_core_typed_inputs_1.logger.error(JSON.stringify(error)); } }))); } /** * * @param {number[]} run_ids List of workflow run ids to cancel * @param {GithubOctokitRepo} repo Object containing repository's owner and repo keys, defaults to this.repo * @param {OctokitInstance} octokit Octokit instance to use, defaults to this.octokit * @returns {Promise<void[]>} Array of promises that resolve to void */ async deleteWorkflowRunsByIds(run_ids, repo = this.repo, octokit = this.octokit) { assertOctokit(octokit); return Promise.all(run_ids.map(async (run_id) => octokit.rest.actions.deleteWorkflowRun({ ...repo, run_id }).then((value) => github_actions_core_typed_inputs_1.logger.debug(`Successfully deleted workflow run ${run_id} in repo ${repoToString(repo)}. status: ${value.status}`), (error) => { github_actions_core_typed_inputs_1.logger.error(`Error deleting workflow run ${run_id} in repo ${repoToString(repo)}`); if (error instanceof Error || typeof error === 'string') { github_actions_core_typed_inputs_1.logger.error(error); } else { github_actions_core_typed_inputs_1.logger.error(JSON.stringify(error)); } }))); } } exports.Kondo = Kondo; //# sourceMappingURL=github-actions-workflow-marie-kondo.js.map