Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v5 #4

Merged
merged 17 commits into from
Nov 21, 2022
4 changes: 2 additions & 2 deletions dist/check-group/core/config_getter.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fetchConfig = void 0;
var utils_1 = require("../utils");
var user_config_parser_1 = require("./user_config_parser");
var core = __importStar(require("@actions/core"));
/**
* Fetches the app configuration from the user's repository.
Expand Down Expand Up @@ -106,7 +106,7 @@ var fetchConfig = function (context) { return __awaiter(void 0, void 0, void 0,
_a.label = 4;
case 4:
core.debug("configData: ".concat(JSON.stringify(configData)));
return [2 /*return*/, (0, utils_1.parseUserConfig)(configData)];
return [2 /*return*/, (0, user_config_parser_1.parseUserConfig)(configData)];
}
});
}); };
Expand Down
204 changes: 204 additions & 0 deletions dist/check-group/core/generate_progress.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
"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 (_) 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 };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.commentOnPr = exports.generateProgressDetailsMarkdown = exports.generateProgressDetailsCLI = void 0;
var statusToMark = function (check, postedChecks) {
if (check in postedChecks) {
if (postedChecks[check].conclusion === "success") {
return "✅";
}
if (postedChecks[check].conclusion === "failure") {
return "❌";
}
if (postedChecks[check].conclusion === "cancelled") {
return "🚫";
}
if (postedChecks[check].conclusion === null) {
return "⌛"; // pending
}
}
return "❓";
};
var statusToLink = function (check, postedChecks) {
if (check in postedChecks) {
var checkData = postedChecks[check];
// assert(checkData.name === check)
return "[".concat(check, "](").concat(checkData.details_url, ")");
}
return check;
};
var parseStatus = function (check, postedChecks) {
if (check in postedChecks) {
var checkData = postedChecks[check];
if (checkData.conclusion === null) {
return checkData.status;
}
else {
return checkData.conclusion;
}
}
return "no_status";
};
var generateProgressDetailsCLI = function (subprojects, postedChecks) {
var progress = "";
// these are the required subprojects
subprojects.forEach(function (subproject) {
progress += "Summary for sub-project ".concat(subproject.id, "\n");
// for padding
var longestLength = Math.max.apply(Math, (subproject.checks.map(function (check) { return check.length; })));
subproject.checks.forEach(function (check) {
var mark = statusToMark(check, postedChecks);
var status = parseStatus(check, postedChecks);
progress += "".concat(check.padEnd(longestLength, ' '), " | ").concat(mark, " | ").concat(status.padEnd(12, ' '), "\n");
});
progress += "\n\n";
});
progress += "\n";
progress += "## Currently received checks\n";
var longestLength = 1;
for (var availableCheck in postedChecks) {
longestLength = Math.max(longestLength, availableCheck.length);
}
for (var availableCheck in postedChecks) {
var mark = statusToMark(availableCheck, postedChecks);
var status_1 = parseStatus(availableCheck, postedChecks);
progress += "".concat(availableCheck.padEnd(longestLength, ' '), " | ").concat(mark, " | ").concat(status_1.padEnd(12, ' '), "\n");
}
progress += "\n";
return progress;
};
exports.generateProgressDetailsCLI = generateProgressDetailsCLI;
var generateProgressDetailsMarkdown = function (subprojects, postedChecks) {
var progress = "## Groups summary\n";
subprojects.forEach(function (subproject) {
// create a map of the relevant checks with their status
var subprojectCheckStatus = {};
subproject.checks.forEach(function (check) {
var status = (check in postedChecks) ? postedChecks[check].conclusion : 'no_status';
subprojectCheckStatus[check] = status;
});
// get the aggregated status of all statuses in the subproject
var subprojectEmoji = Object.values(subprojectCheckStatus).every(function (v) { return v === "success"; }) ? "🟢" : "🔴";
// generate the markdown table
progress += "<details>\n\n";
progress += "<summary><b>".concat(subprojectEmoji, " ").concat(subproject.id, "</b></summary>\n\n");
progress += "| Check ID | Status | |\n";
progress += "| -------- | ------ | --- |\n";
for (var _i = 0, _a = Object.entries(subprojectCheckStatus); _i < _a.length; _i++) {
var _b = _a[_i], check = _b[0], status_2 = _b[1];
var link = statusToLink(check, postedChecks);
var status_3 = parseStatus(check, postedChecks);
var mark = statusToMark(check, postedChecks);
progress += "| ".concat(link, " | ").concat(status_3, " | ").concat(mark, " |\n");
}
progress += "\n</details>\n\n";
});
return progress;
};
exports.generateProgressDetailsMarkdown = generateProgressDetailsMarkdown;
var PR_COMMENT_START = "<!-- checkgroup-comment-start -->";
function formPrComment(result, inputs, subprojects, postedChecks) {
var parsedConclusion = result.replace("_", " ");
// capitalize
parsedConclusion = parsedConclusion.charAt(0).toUpperCase() + parsedConclusion.slice(1);
var hasFailed = result === "has_failure";
var conclusionEmoji = (result === "all_passing") ? "🟢" : (hasFailed) ? "🔴" : "🟡";
var lightning = (result === "all_passing") ? "⚡" : (hasFailed) ? "⛈️" : "🌩️";
var failedMesage = ("\n**\u26A0\uFE0F This job will need to be re-run to merge your PR."
+ " If you do not have write access to the repository you can ask `".concat(inputs.maintainers, "` to re-run it for you.")
+ " If you push a new commit, all of CI will re-trigger ⚠️**"
+ " If you have any other questions, you can reach out to `".concat(inputs.owner, "` for help."));
var progressDetails = (0, exports.generateProgressDetailsMarkdown)(subprojects, postedChecks);
return (PR_COMMENT_START
+ "\n# ".concat(lightning, " Required checks status: ").concat(parsedConclusion, " ").concat(conclusionEmoji)
+ ((hasFailed) ? failedMesage : "")
+ ((subprojects.length) ? "\n".concat(progressDetails) : "\nNo groups match the files changed in this PR.")
+ "\n\n---"
+ "\nThis comment was automatically generated and updates for ".concat(inputs.timeout, " minutes ")
+ "every ".concat(inputs.interval, " seconds.")
+ "\n\nThank you for your contribution! 💜");
}
function getPrComment(context) {
return __awaiter(this, void 0, void 0, function () {
var params, commentsRes, _i, _a, comment;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
params = context.issue();
return [4 /*yield*/, context.octokit.rest.issues.listComments(params)];
case 1:
commentsRes = _b.sent();
for (_i = 0, _a = commentsRes.data; _i < _a.length; _i++) {
comment = _a[_i];
if (comment.body.includes(PR_COMMENT_START)) {
return [2 /*return*/, { id: comment.id, body: comment.body }];
}
}
return [2 /*return*/, { id: 0, body: "" }];
}
});
});
}
function commentOnPr(context, result, inputs, subprojects, postedChecks) {
return __awaiter(this, void 0, void 0, function () {
var existingData, newComment;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, getPrComment(context)];
case 1:
existingData = _a.sent();
context.log.debug("existingData: ".concat(JSON.stringify(existingData)));
newComment = formPrComment(result, inputs, subprojects, postedChecks);
if (existingData.body === newComment) {
return [2 /*return*/];
}
if (!(existingData.id === 0)) return [3 /*break*/, 3];
return [4 /*yield*/, context.octokit.issues.createComment(context.issue({ body: newComment }))];
case 2:
_a.sent();
return [3 /*break*/, 5];
case 3: return [4 /*yield*/, context.octokit.issues.updateComment(context.repo({ body: newComment, comment_id: existingData.id }))];
case 4:
_a.sent();
_a.label = 5;
case 5: return [2 /*return*/];
}
});
});
}
exports.commentOnPr = commentOnPr;
63 changes: 42 additions & 21 deletions dist/check-group/core/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
"use strict";
/**
* @module Core
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
Expand Down Expand Up @@ -63,52 +60,62 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fetchConfig = exports.CheckGroup = void 0;
var utils_1 = require("../utils");
/**
* @module Core
*/
var core = __importStar(require("@actions/core"));
var generate_progress_1 = require("./generate_progress");
var subproj_matching_1 = require("./subproj_matching");
var satisfy_expected_checks_1 = require("./satisfy_expected_checks");
var config_getter_1 = require("./config_getter");
Object.defineProperty(exports, "fetchConfig", { enumerable: true, get: function () { return config_getter_1.fetchConfig; } });
var utils_2 = require("../utils");
var utils_3 = require("../utils");
/**
* The orchestration class.
*/
var CheckGroup = /** @class */ (function () {
function CheckGroup(pullRequestNumber, config, context, sha) {
this.intervalTimer = setTimeout(function () { return ''; }, 0);
this.timeoutTimer = setTimeout(function () { return ''; }, 0);
this.inputs = {};
this.pullRequestNumber = pullRequestNumber;
this.config = config;
this.context = context;
this.sha = sha;
}
CheckGroup.prototype.run = function () {
return __awaiter(this, void 0, void 0, function () {
var filenames, subprojs, expectedChecks, interval, timeout;
var filenames, subprojs, expectedChecks, maintainers, owner, interval, timeout;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.files()];
case 1:
filenames = _a.sent();
core.info("Files are: ".concat(JSON.stringify(filenames)));
subprojs = (0, utils_2.matchFilenamesToSubprojects)(filenames, this.config.subProjects);
subprojs = (0, subproj_matching_1.matchFilenamesToSubprojects)(filenames, this.config.subProjects);
core.debug("Matching subprojects are: ".concat(JSON.stringify(subprojs)));
if (core.isDebug()) {
expectedChecks = collectExpectedChecks(subprojs);
core.debug("Expected checks are: ".concat(JSON.stringify(expectedChecks)));
}
maintainers = core.getInput('maintainers');
this.inputs.maintainers = maintainers;
owner = core.getInput('owner');
this.inputs.owner = owner;
interval = parseInt(core.getInput('interval'));
this.inputs.interval = interval;
core.info("Check interval: ".concat(interval));
this.runCheck(subprojs, 1, interval * 1000);
timeout = parseInt(core.getInput('timeout'));
this.inputs.timeout = timeout;
core.info("Timeout: ".concat(timeout));
// set a timeout that will stop the job to avoid polling the GitHub API infinitely
this.timeoutTimer = setTimeout(function () {
clearTimeout(_this.intervalTimer);
core.setFailed("The timeout of ".concat(timeout, " minutes has triggered but not all required jobs were passing.")
+ " This job will need to be re-run to merge your PR."
+ " If you do not have write access to the repository you can ask ".concat(core.getInput('maintainers'), " to re-run it for you.")
+ " If you have any other questions, you can reach out to ".concat(core.getInput('owner'), " for help."));
+ " If you do not have write access to the repository you can ask ".concat(maintainers, " to re-run it for you.")
+ " If you have any other questions, you can reach out to ".concat(owner, " for help."));
}, timeout * 60 * 1000);
return [2 /*return*/];
}
Expand All @@ -117,7 +124,7 @@ var CheckGroup = /** @class */ (function () {
};
CheckGroup.prototype.runCheck = function (subprojs, tries, interval) {
return __awaiter(this, void 0, void 0, function () {
var postedChecks, conclusion, summary, details, error_1;
var postedChecks, result, error_1;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
Expand All @@ -129,12 +136,10 @@ var CheckGroup = /** @class */ (function () {
case 1:
postedChecks = _a.sent();
core.debug("postedChecks: ".concat(JSON.stringify(postedChecks)));
conclusion = (0, utils_3.satisfyExpectedChecks)(subprojs, postedChecks);
summary = (0, utils_1.generateProgressSummary)(subprojs, postedChecks);
details = (0, utils_1.generateProgressDetails)(subprojs, postedChecks);
core.info("".concat(this.config.customServiceName, " conclusion: '").concat(conclusion, "':\n").concat(summary, "\n").concat(details));
result = (0, satisfy_expected_checks_1.satisfyExpectedChecks)(subprojs, postedChecks);
this.notifyProgress(subprojs, postedChecks, result);
core.endGroup();
if (conclusion === "all_passing") {
if (result === "all_passing") {
core.info("All required checks were successful!");
clearTimeout(this.intervalTimer);
clearTimeout(this.timeoutTimer);
Expand All @@ -155,6 +160,17 @@ var CheckGroup = /** @class */ (function () {
});
});
};
CheckGroup.prototype.notifyProgress = function (subprojs, postedChecks, result) {
return __awaiter(this, void 0, void 0, function () {
var details;
return __generator(this, function (_a) {
details = (0, generate_progress_1.generateProgressDetailsCLI)(subprojs, postedChecks);
core.info("".concat(this.config.customServiceName, " result: '").concat(result, "':\n").concat(details));
(0, generate_progress_1.commentOnPr)(this.context, result, this.inputs, subprojs, postedChecks);
return [2 /*return*/];
});
});
};
/**
* Gets a list of files that are modified in
* a pull request.
Expand Down Expand Up @@ -193,8 +209,13 @@ var getPostedChecks = function (context, sha) { return __awaiter(void 0, void 0,
core.debug("checkRuns: ".concat(JSON.stringify(checkRuns)));
checkNames = {};
checkRuns.forEach(function (checkRun) {
var conclusion = checkRun.conclusion ? checkRun.conclusion : "pending";
checkNames[checkRun.name] = conclusion;
var checkRunData = {
name: checkRun.name,
status: checkRun.status,
conclusion: checkRun.conclusion,
details_url: checkRun.details_url
};
checkNames[checkRun.name] = checkRunData;
});
return [2 /*return*/, checkNames];
}
Expand All @@ -205,11 +226,11 @@ var collectExpectedChecks = function (configs) {
var requiredChecks = {};
configs.forEach(function (config) {
config.checks.forEach(function (check) {
if (check.id in requiredChecks) {
requiredChecks[check.id].push(config.id);
if (check in requiredChecks) {
requiredChecks[check].push(config.id);
}
else {
requiredChecks[check.id] = [config.id];
requiredChecks[check] = [config.id];
}
});
});
Expand Down
Loading