@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
JavaScript
;
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