UNPKG

diffjam

Version:
392 lines (391 loc) 20.8 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Runner = void 0; /* Performs top-level actions of the CLI. Connects the file paths found in the `CurrentWorkingDirectory` to the worker pool. */ var env_ci_1 = __importDefault(require("env-ci")); var chalk_1 = __importDefault(require("chalk")); var node_assert_1 = require("node:assert"); var Policy_1 = require("./Policy"); var log_1 = require("./log"); var clientVersion_1 = require("./clientVersion"); var count_1 = require("./count"); var policyModify_1 = require("./policyModify"); var Runner = /** @class */ (function () { function Runner(config, flags, cwd, workerPool) { this.config = config; this.flags = flags; this.cwd = cwd; this.workerPool = workerPool; this.ran = false; this.policies = Object.values(config.policyMap); for (var policyName in config.policyMap) { this.workerPool.resultsMap[policyName] = { policy: config.policyMap[policyName], matches: [], }; } } Runner.prototype.run = function () { var _this = this; (0, node_assert_1.equal)(this.ran, false, "Runner.run() should only be called once"); (0, node_assert_1.equal)(this.policies.length > 0, true, "No policies specified.\nPlease check your config file at " + this.config.filePath); return new Promise(function (resolve) { _this.workerPool.onResults = function () { _this.ran = true; resolve({ resultsMap: _this.workerPool.resultsMap, filesChecked: _this.workerPool.filesChecked }); }; _this.cwd.allNonGitIgnoredFiles(_this.processFile.bind(_this), _this.workerPool.onFilesDone.bind(_this.workerPool)); }); }; Runner.prototype.check = function () { return __awaiter(this, void 0, void 0, function () { var _a, resultsMap, filesChecked, breaches; return __generator(this, function (_b) { switch (_b.label) { case 0: return [4 /*yield*/, this.run()]; case 1: _a = _b.sent(), resultsMap = _a.resultsMap, filesChecked = _a.filesChecked; breaches = (0, log_1.logResults)(resultsMap, filesChecked).breaches; if (breaches.length) { (0, log_1.logCheckFailedError)(); process.exitCode = 1; } else { console.log("\n".concat(log_1.GREEN_CHECK, " ").concat(chalk_1.default.bold("All policies passed with ".concat(filesChecked.length, " matching files checked")))); } return [2 /*return*/]; } }); }); }; Runner.prototype.count = function () { return __awaiter(this, void 0, void 0, function () { var clientVers, start, _a, resultsMap, filesChecked, _b, breaches, successes, all, results, _i, all_1, result, verbose, apiKey, configJson; return __generator(this, function (_c) { switch (_c.label) { case 0: clientVers = (0, clientVersion_1.clientVersion)(); start = new Date(); return [4 /*yield*/, this.run()]; case 1: _a = _c.sent(), resultsMap = _a.resultsMap, filesChecked = _a.filesChecked; _b = (0, log_1.logResults)(resultsMap, filesChecked), breaches = _b.breaches, successes = _b.successes, all = _b.all; results = {}; for (_i = 0, all_1 = all; _i < all_1.length; _i++) { result = all_1[_i]; results[result.policy.name] = { measurement: result.matches.length }; } verbose = Boolean(this.flags.verbose); if (breaches.length) { (0, log_1.logCheckFailedError)(); } if (!this.flags.record && !this.flags.ci) { console.log(chalk_1.default.green.bold("Done in ".concat(Date.now() - start.getTime(), " ms."))); return [2 /*return*/]; } console.log(chalk_1.default.yellow("sending metrics to server...")); verbose && console.log(chalk_1.default.cyan("successes: ".concat(JSON.stringify(successes)))); verbose && console.log(chalk_1.default.cyan("breaches: ".concat(JSON.stringify(breaches)))); apiKey = process.env.DIFFJAM_API_KEY; if (!apiKey) { console.error(chalk_1.default.red("Missing api key! Could not post metrics.")); console.error(chalk_1.default.red("You must have an api key in an environment variable named DIFFJAM_API_KEY")); process.exitCode = 1; return [2 /*return*/]; } configJson = this.config.toJson(); verbose && console.log("apiKey, config, results: ", apiKey, configJson, results); if (!this.flags.record) return [3 /*break*/, 3]; return [4 /*yield*/, (0, count_1.postMetrics)(apiKey, configJson, results, clientVers)]; case 2: _c.sent(); _c.label = 3; case 3: if (!this.flags.ci) return [3 /*break*/, 5]; if (!(0, env_ci_1.default)().isCi) { throw new Error("could not detect CI environment"); } return [4 /*yield*/, (0, count_1.commentResults)(apiKey, configJson, results, clientVers)]; case 4: _c.sent(); _c.label = 5; case 5: console.log(chalk_1.default.green.bold("Done in ".concat(Date.now() - start.getTime(), " ms."))); return [2 /*return*/]; } }); }); }; Runner.prototype.cinch = function () { return __awaiter(this, void 0, void 0, function () { var _a, resultsMap, filesChecked, _b, breaches, successes, anyCinched, _i, successes_1, success, before_1; return __generator(this, function (_c) { switch (_c.label) { case 0: return [4 /*yield*/, this.run()]; case 1: _a = _c.sent(), resultsMap = _a.resultsMap, filesChecked = _a.filesChecked; _b = (0, log_1.logResults)(resultsMap, filesChecked), breaches = _b.breaches, successes = _b.successes; console.log(); if (breaches.length > 0) { console.error(chalk_1.default.bold("Cannot cinch a policy that doesn't even meet the baseline. \n")); process.exitCode = 1; return [2 /*return*/]; } anyCinched = false; for (_i = 0, successes_1 = successes; _i < successes_1.length; _i++) { success = successes_1[_i]; if (success.policy.isCountCinchable(success.matches)) { anyCinched = true; before_1 = success.policy.baseline; success.policy.baseline = success.matches.length; console.log("".concat(log_1.GREEN_CHECK, " cinching ").concat(chalk_1.default.bold(success.policy.name), " from ").concat(before_1, " to ").concat(chalk_1.default.bold(success.matches.length.toString()), "!")); } } if (anyCinched) { this.config.write(); } else { console.log("".concat(log_1.GREEN_CHECK, " ").concat(chalk_1.default.bold("All policies are already exactly at their baseline, so none were cinched"))); } return [2 /*return*/]; } }); }); }; Runner.prototype.bump = function () { return __awaiter(this, void 0, void 0, function () { var _a, resultsMap, filesChecked, breaches, _i, breaches_1, breach, before_2; return __generator(this, function (_b) { switch (_b.label) { case 0: return [4 /*yield*/, this.run()]; case 1: _a = _b.sent(), resultsMap = _a.resultsMap, filesChecked = _a.filesChecked; breaches = (0, log_1.logResults)(resultsMap, filesChecked).breaches; console.log(); for (_i = 0, breaches_1 = breaches; _i < breaches_1.length; _i++) { breach = breaches_1[_i]; before_2 = breach.policy.baseline; breach.policy.baseline = breach.matches.length; console.log("\uD83C\uDF9A bumping ".concat(chalk_1.default.bold(breach.policy.name), " from ").concat(before_2, " to ").concat(chalk_1.default.bold(breach.matches.length.toString()), "!")); } if (breaches.length) { this.config.write(); } else { console.log("".concat(log_1.GREEN_CHECK, " ").concat(chalk_1.default.bold("All policies are already exactly at their baseline, so none were bumped"))); } return [2 /*return*/]; } }); }); }; Runner.prototype.addPolicy = function () { return __awaiter(this, void 0, void 0, function () { var ui, name, isRegex, search, negativeSearchTerms, regex, negativeSearchTerm, filePattern, ignoreFilePatterns, ignoreFilePattern, description, policy, _a, resultsMap, filesChecked, matches; return __generator(this, function (_b) { switch (_b.label) { case 0: ui = require("./ui"); return [4 /*yield*/, ui.textInput("Enter a name for this policy: ")]; case 1: name = _b.sent(); return [4 /*yield*/, ui.confirm("Is this a regex search?")]; case 2: isRegex = _b.sent(); negativeSearchTerms = []; if (!isRegex) return [3 /*break*/, 4]; return [4 /*yield*/, ui.textInput("Enter the regex to search for: ")]; case 3: regex = _b.sent(); search = "regex:".concat(regex); return [3 /*break*/, 8]; case 4: return [4 /*yield*/, ui.textInput("Enter the string to match : ")]; case 5: search = _b.sent(); _b.label = 6; case 6: if (!true) return [3 /*break*/, 8]; return [4 /*yield*/, ui.textInput("Enter any string to negate (or leave blank to continue): ")]; case 7: negativeSearchTerm = _b.sent(); if (negativeSearchTerm.trim()) { negativeSearchTerms.push(negativeSearchTerm); } else { return [3 /*break*/, 8]; } return [3 /*break*/, 6]; case 8: return [4 /*yield*/, ui.textInput("Enter the filePattern to search for this policy: ")]; case 9: filePattern = _b.sent(); ignoreFilePatterns = []; _b.label = 10; case 10: if (!true) return [3 /*break*/, 12]; return [4 /*yield*/, ui.textInput("Enter any filePatterns to ignore (or leave blank to continue): ")]; case 11: ignoreFilePattern = _b.sent(); if (ignoreFilePattern.trim()) { ignoreFilePatterns.push(ignoreFilePattern); } else { return [3 /*break*/, 12]; } return [3 /*break*/, 10]; case 12: return [4 /*yield*/, ui.textInput("Give a description for this policy: ")]; case 13: description = _b.sent(); policy = new Policy_1.Policy(name, description, filePattern, __spreadArray([search], negativeSearchTerms, true), 0, ignoreFilePatterns); this.config.setPolicy(policy); this.policies = [policy]; this.workerPool.resultsMap[policy.name] = { policy: policy, matches: [] }; return [4 /*yield*/, this.run()]; case 14: _a = _b.sent(), resultsMap = _a.resultsMap, filesChecked = _a.filesChecked; matches = resultsMap[policy.name].matches; policy.baseline = matches.length; return [4 /*yield*/, ui.confirm("There are currently ".concat(policy.baseline, " matches for that configuration after checking ").concat(filesChecked.length, " files. Save it?"))]; case 15: if (_b.sent()) { this.config.write(); console.log("Saved!"); } else { console.log("Cancelled save."); } return [2 /*return*/]; } }); }); }; Runner.prototype.runSinglePolicy = function (policyName) { return __awaiter(this, void 0, void 0, function () { var policy, resultsMap; return __generator(this, function (_a) { switch (_a.label) { case 0: policy = this.config.getPolicy(policyName); if (!policy) { throw new Error("Could not find policy ".concat(policyName)); } return [4 /*yield*/, this.run()]; case 1: resultsMap = (_a.sent()).resultsMap; return [2 /*return*/, resultsMap[policyName]]; } }); }); }; Runner.prototype.removePolicy = function () { return __awaiter(this, void 0, void 0, function () { var ui, policy; return __generator(this, function (_a) { switch (_a.label) { case 0: ui = require("./ui"); return [4 /*yield*/, ui.select("Select a policy to remove: ", this.config.policyMap)]; case 1: policy = _a.sent(); return [4 /*yield*/, this.config.deletePolicy(policy.name)]; case 2: _a.sent(); return [4 /*yield*/, this.config.write()]; case 3: _a.sent(); console.log("Removed ".concat(policy.name)); return [2 /*return*/]; } }); }); }; Runner.prototype.modifyPolicy = function () { return (0, policyModify_1.actionPolicyModify)(this); }; Runner.prototype.checkBreachesForPolicy = function () { return __awaiter(this, void 0, void 0, function () { var ui, policy, result; return __generator(this, function (_a) { switch (_a.label) { case 0: ui = require("./ui"); return [4 /*yield*/, ui.select("Select a policy to check for breaches: ", this.config.policyMap)]; case 1: policy = _a.sent(); return [4 /*yield*/, this.runSinglePolicy(policy.name)]; case 2: result = _a.sent(); (0, log_1.logAllResultDetails)(result); return [2 /*return*/]; } }); }); }; Runner.prototype.processFile = function (filePath) { var isUnderPolicy = this.policies.some(function (policy) { return policy.isFileUnderPolicy(filePath); }); if (!isUnderPolicy) return; this.workerPool.processFile(filePath); }; return Runner; }()); exports.Runner = Runner;