branch-remover
Version:
A small application for quickly removing unnecessary branches from GitHub.
236 lines • 9.68 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BranchRemoverOptionsBuilder = void 0;
const child_process_1 = __importDefault(require("child_process"));
const humanize_duration_1 = __importDefault(require("humanize-duration"));
const readline_1 = __importDefault(require("readline"));
const util_1 = __importDefault(require("util"));
const Core_1 = require("./Core");
const Formatters_1 = require("./Formatters");
const exec = util_1.default.promisify(child_process_1.default.exec);
class BranchRemoverOptionsBuilder {
constructor() {
this._quiet = false;
this._yes = false;
this._details = false;
this._mergedDate = null;
this._staleDate = null;
this._ignore = null;
this._beforeRemove = null;
this._afterRemove = null;
this._cacheTimeout = 0;
this._cachePath = BranchRemoverOptionsBuilder.DEFAULT_CACHE_PATH;
this._debug = false;
this.quiet = this.quiet.bind(this);
this.merged = this.merged.bind(this);
this.stale = this.stale.bind(this);
this.yes = this.yes.bind(this);
this.details = this.details.bind(this);
this.ignore = this.ignore.bind(this);
this.beforeRemove = this.beforeRemove.bind(this);
this.afterRemove = this.afterRemove.bind(this);
this.cacheTimeout = this.cacheTimeout.bind(this);
this.cachePath = this.cachePath.bind(this);
this.debug = this.debug.bind(this);
this.build = this.build.bind(this);
}
quiet() {
this._quiet = true;
return this;
}
yes() {
this._yes = true;
return this;
}
details() {
this._details = true;
return this;
}
merged(date) {
this._mergedDate = date;
return this;
}
stale(date) {
this._staleDate = date;
return this;
}
ignore(value) {
this._ignore = value;
return this;
}
beforeRemove(command) {
this._beforeRemove = command;
return this;
}
afterRemove(command) {
this._afterRemove = command;
return this;
}
cacheTimeout(timeout) {
this._cacheTimeout = Number(timeout);
return this;
}
cachePath(path) {
if (!path) {
throw new Error('Parameter "path" cannot be null or empty.');
}
this._cachePath = path;
return this;
}
debug() {
this._debug = true;
return this;
}
build() {
const displayDefaultAnswer = this._yes ? '[Y/n]' : '[y/N]';
const defaultAnswer = this._yes ? 'yes' : 'no';
const ignore = this.getRegExpOrNull(this._ignore);
const mergedDate = this._mergedDate;
const staleDate = this._staleDate;
const quiet = this._quiet;
const details = this._details;
const beforeRemove = this._beforeRemove;
const afterRemove = this._afterRemove;
const cachePath = this._cachePath;
const cacheTimeout = this._cacheTimeout;
const cacheProvider = new Core_1.FileCacheProvider(cachePath);
const logger = new Core_1.Logger(Core_1.Logger.defaultOptions(this._debug ? 'debug' : 'info'));
return {
logger,
cache: {
provider: cacheProvider,
timeout: cacheTimeout,
},
ignore: (e) => {
if (ignore) {
// When a regex has the global flag set, test() will advance the lastIndex of the regex.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test#using_test_on_a_regex_with_the_global_flag
ignore.lastIndex = 0;
if (ignore.test(e.branchName)) {
return Promise.resolve(true);
}
}
return Promise.resolve(false);
},
remove: async (e) => {
var _a, _b;
const { branch, context: { logger, }, } = e;
let result = false;
if (branch.merged) {
if (mergedDate) {
if (branch.mergedDate <= mergedDate) {
result = true;
logger.debug('Can remove merged "{branch.name}", because the merged date {branch.mergedDate} is less or equal to {date}.', {
branch,
date: mergedDate,
});
}
else {
result = Core_1.BranchRemoveCancelationReason.MergeDateOutOfRange;
logger.debug('Cannot remove merged "{branch.name}", because the merged date {branch.mergedDate} is greater than {date}.', {
branch,
date: mergedDate,
});
}
}
else {
result = true;
logger.debug('Can remove merged "{branch.name}", because no limit on merge date.', {
branch,
});
}
}
else {
if (staleDate && branch.updatedDate <= staleDate) {
result = true;
logger.debug('Can remove "{branch.name}", because the updated date {branch.updatedDate} is less or equal to {date}.', {
branch,
date: staleDate,
});
}
else {
result = Core_1.BranchRemoveCancelationReason.UpdateDateOutOfRange;
}
}
if (result === true && !quiet) {
const question = (query) => {
const rl = readline_1.default.createInterface({
input: process.stdin,
output: process.stdout,
});
return new Promise((resolve) => {
rl.question(query, (answer) => {
resolve(answer);
rl.close();
});
});
};
const now = new Date();
const duration = humanize_duration_1.default(now.getTime() - ((_b = (_a = branch.mergedDate) !== null && _a !== void 0 ? _a : branch.updatedDate) !== null && _b !== void 0 ? _b : now).getTime(), {
largest: 1,
round: true,
});
const date = `${branch.merged ? 'Merged' : 'Updated'} ${duration} ago`;
this.displayBranchInfo(branch);
const answer = await question(`Do you want to remove ${branch.merged ? 'merged' : 'unmerged'} branch "${branch.name}"? ${date} ${displayDefaultAnswer} `);
if (!/y(es|)+/gi.test(answer || defaultAnswer)) {
result = Core_1.BranchRemoveCancelationReason.CanceledByUser;
logger.debug('Removing branch "{branch.name}" canceled by user.', {
branch,
});
}
}
if (details && !quiet && result !== true) {
this.displayBranchInfo(branch);
}
return result;
},
beforeRemove: ({ branch, context }) => {
if (beforeRemove) {
return this.execCommand(beforeRemove, branch, context.logger);
}
else {
return Promise.resolve(true);
}
},
afterRemove: async ({ branch, context }) => {
if (afterRemove) {
await this.execCommand(afterRemove, branch, context.logger);
}
},
};
}
displayBranchInfo(branch) {
console.log(Formatters_1.branchInfoFormatter(branch));
}
getRegExpOrNull(value) {
return value
? new RegExp(value, 'g')
: null;
}
async execCommand(command, branch, logger) {
const commandToExec = command
.replace(/(\\)(.{1})/g, String.fromCharCode(0) + '$2$1')
.replace(/\{branch\}/g, branch.name)
.replace(/(\0)(.{1})(\\)/g, '$2');
logger.debug('Preparation for command execution. Source: "{source}". Command to execute: {parsed}.', {
source: command,
parsed: commandToExec,
});
const { stdout, stderr, } = await exec(commandToExec);
logger.debug('{command} > stdout - {stdout}, stderr - {stderr}', {
command: commandToExec,
stdout: stdout === null || stdout === void 0 ? void 0 : stdout.trim(),
stderr: stderr === null || stderr === void 0 ? void 0 : stderr.trim(),
});
return !stdout
|| (stdout
&& !/^(0|false)$/i.test(stdout));
}
}
exports.BranchRemoverOptionsBuilder = BranchRemoverOptionsBuilder;
BranchRemoverOptionsBuilder.DEFAULT_CACHE_PATH = './.branch-remover.cache';
//# sourceMappingURL=BranchRemoverOptionsBuilder.js.map