branch-remover
Version:
A small application for quickly removing unnecessary branches from GitHub.
183 lines • 7.69 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BranchRemover = void 0;
const chalk_1 = __importDefault(require("chalk"));
const Core_1 = require("./Core");
const Formatters_1 = require("./Formatters");
class BranchRemover {
constructor(provider) {
this._provider = provider;
this.execute = this.execute.bind(this);
}
get provider() {
return this._provider;
}
// TODO: I forgot why I made test a separate parameter from the options,
// it probably makes sense to combine
async execute(options, test) {
var _a, _b, _c;
// TODO: PackageInfo service
const { name: packageName, version: packageVersion, } = require('../package.json');
const logger = options.logger || new Core_1.Logger();
const cache = (_a = options.cache) === null || _a === void 0 ? void 0 : _a.provider;
const cacheTimeout = (_c = (_b = options.cache) === null || _b === void 0 ? void 0 : _b.timeout) !== null && _c !== void 0 ? _c : 0;
const isCacheAvailable = cache && cacheTimeout > 0;
logger.info('{package} v{version}', {
package: packageName,
version: packageVersion,
});
if (isCacheAvailable) {
cache.load();
}
try {
await this.processBranches(logger, options, test !== null && test !== void 0 ? test : false);
}
catch (error) {
// TODO: Output the number of processed branches and the elapsed time
throw new Error(error.message);
}
finally {
if (isCacheAvailable) {
cache.save();
}
}
}
buildIgnoreFunction(value) {
if (typeof value === 'function') {
return value;
}
if (typeof value === 'string') {
return (e) => {
return Promise.resolve(e.branchName === value);
};
}
if (value instanceof RegExp) {
return (e) => {
return Promise.resolve(value.test(e.branchName));
};
}
if (Array.isArray(value)) {
return (e) => {
return Promise.resolve(value.includes(e.branchName));
};
}
return () => Promise.resolve(false);
}
async processBranches(logger, options, test) {
var _a, _b, _c;
const start = new Date();
const ignore = this.buildIgnoreFunction(options.ignore);
const remove = options.remove;
const dummy = () => Promise.resolve(true);
const beforeRemove = options.beforeRemove || dummy;
const afterRemove = options.afterRemove || dummy;
const context = {
test,
logger,
};
const cache = (_a = options.cache) === null || _a === void 0 ? void 0 : _a.provider;
const cacheTimeout = (_c = (_b = options.cache) === null || _b === void 0 ? void 0 : _b.timeout) !== null && _c !== void 0 ? _c : 0;
const isCacheAvailable = cache && cacheTimeout > 0;
const addCache = (key, reason) => {
if (isCacheAvailable) {
cache.add(key, reason, cacheTimeout);
}
};
logger.info('Processing branches using {provider} provider in {mode} mode.', {
provider: chalk_1.default.yellow(this._provider.name),
mode: test ? chalk_1.default.yellow('test') : chalk_1.default.bold(chalk_1.default.red('REMOVE')),
});
const branches = await this._provider.getListBranches();
let totalRemoved = 0;
for (let i = 0, ic = branches.length; i < ic; ++i) {
const { name, lastCommitHash } = branches[i];
const cacheKey = `branch-${name}`;
logger.info('Processing branch {index} of {count} - {branch}', {
index: chalk_1.default.blue(i + 1),
count: chalk_1.default.blue(ic),
branch: name,
});
if (isCacheAvailable) {
if (cache.has(cacheKey)) {
logger.info('Skip cached branch "{branch}" until {ttl}: {reason}.', {
branch: name,
ttl: new Date(cache.getTtl(cacheKey)),
reason: Formatters_1.branchRemoveCancelationReasonFormatter(cache.get(cacheKey)),
});
continue;
}
}
// NOTE: we have to check before getting branch details
// because, depending on the provider, there may be limits on the number of requests;
// for example, GitHub currently allows no more than 5,000 requests per hour for free
const ignored = await ignore({
branchName: name,
context,
});
if (ignored) {
addCache(cacheKey, Core_1.BranchRemoveCancelationReason.Ignored);
logger.info('Skip branch "{branch}", because it matches an ignored value.', {
branch: name,
});
continue;
}
const branch = await this._provider.getBranch(name, lastCommitHash);
if (!branch) {
addCache(cacheKey, Core_1.BranchRemoveCancelationReason.BranchNotFound);
logger.info('Skip branch "{branch}", because no detailed information.', {
branch: name,
});
continue;
}
const args = {
branch,
context,
};
const canRemove = await remove(args);
if (canRemove === true) {
logger.info('Removing "{branch}"...', {
branch: name,
});
if (test) {
logger.info('Removing is not applicable in test mode.');
}
else {
// TODO: not sure if we need additional checking,
// this is probably redundant,
// need to think about this question
const canStillRemove = await beforeRemove(args);
if (canStillRemove) {
await this._provider.removeBranch(name);
++totalRemoved;
logger.info('Successfully removed "{branch}".', {
branch: name,
});
await afterRemove(args);
}
else {
addCache(cacheKey, Core_1.BranchRemoveCancelationReason.CanceledByBeforeHandler);
logger.info('Removing branch "{branch}" canceled by the result of the {handler} handler.', {
branch: name,
handler: 'beforeRemove',
});
}
}
}
else {
addCache(cacheKey, typeof canRemove === 'boolean'
? Core_1.BranchRemoveCancelationReason.Other
: canRemove);
}
}
logger.info('Removed {totalRemoved} out of {totalCount} branches in {duration} seconds.', {
totalRemoved,
totalCount: branches.length,
duration: (new Date().getTime() - start.getTime()) / 1000,
});
}
}
exports.BranchRemover = BranchRemover;
//# sourceMappingURL=BranchRemover.js.map