diff --git a/dist/index.js b/dist/index.js index d311df9..3e5a376 100644 --- a/dist/index.js +++ b/dist/index.js @@ -9415,6 +9415,407 @@ function wrappy (fn, cb) { } +/***/ }), + +/***/ 8111: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.deleteComment = exports.updateComment = exports.createComment = exports.generateBody = exports.getPreviousComment = void 0; +const github = __importStar(__nccwpck_require__(5438)); +const commentHeader = "**Merge Schedule**"; +const commentFooter = ""; +const commentFailFooter = ""; +async function getPreviousComment(octokit, pullRequestNumber, variant = "default") { + const prComments = await octokit.paginate(octokit.rest.issues.listComments, { + ...github.context.repo, + issue_number: pullRequestNumber, + }, (response) => { + return response.data.filter((comment) => comment.body?.includes(variant === "fail" ? commentFailFooter : commentFooter)); + }); + const previousComment = prComments.pop(); + return previousComment; +} +exports.getPreviousComment = getPreviousComment; +const statePrefix = { + success: ":white_check_mark:", + error: ":x:", + warning: ":warning:", + pending: ":hourglass:", +}; +function generateBody(body, state, variant = "default") { + let newBody = body; + if (!body.startsWith(commentHeader)) { + newBody = `${commentHeader}\n${newBody}`; + } + const footer = variant === "fail" ? commentFailFooter : commentFooter; + if (!body.endsWith(footer)) { + newBody = `${newBody}\n${footer}`; + } + return `${statePrefix[state]} ${newBody}`; +} +exports.generateBody = generateBody; +async function createComment(octokit, pullRequestNumber, body) { + return octokit.rest.issues.createComment({ + ...github.context.repo, + issue_number: pullRequestNumber, + body, + }); +} +exports.createComment = createComment; +async function updateComment(octokit, commentId, body) { + return octokit.rest.issues.updateComment({ + ...github.context.repo, + comment_id: commentId, + body, + }); +} +exports.updateComment = updateComment; +async function deleteComment(octokit, commentId) { + return octokit.rest.issues.deleteComment({ + ...github.context.repo, + comment_id: commentId, + }); +} +exports.deleteComment = deleteComment; + + +/***/ }), + +/***/ 1870: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.getCommitStatusesStatus = exports.getCommitChecksRunsStatus = void 0; +const github = __importStar(__nccwpck_require__(5438)); +async function getCommitChecksRunsStatus(octokit, commitRef) { + const { data } = await octokit.rest.checks.listForRef({ + ...github.context.repo, + ref: commitRef, + }); + if (data.total_count === 0) { + return "completed"; + } + if (data.check_runs.every((check) => check.status === "completed")) { + return "completed"; + } + return "in_progress"; +} +exports.getCommitChecksRunsStatus = getCommitChecksRunsStatus; +async function getCommitStatusesStatus(octokit, commitRef) { + const { data } = await octokit.rest.repos.getCombinedStatusForRef({ + ...github.context.repo, + ref: commitRef, + }); + if (data.statuses === undefined || data.statuses.length === 0) + return "success"; + return data.state; +} +exports.getCommitStatusesStatus = getCommitStatusesStatus; + + +/***/ }), + +/***/ 2719: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +const core = __importStar(__nccwpck_require__(2186)); +const github = __importStar(__nccwpck_require__(5438)); +const fs_1 = __nccwpck_require__(7147); +const locale_date_1 = __importDefault(__nccwpck_require__(3663)); +const utils_1 = __nccwpck_require__(1715); +const comment_1 = __nccwpck_require__(8111); +/** + * Handle "pull_request" event + */ +async function handlePullRequest() { + if (!process.env.GITHUB_TOKEN) { + core.setFailed("GITHUB_TOKEN environment variable is not set"); + return; + } + const octokit = github.getOctokit(process.env.GITHUB_TOKEN); + const eventPayload = JSON.parse((0, fs_1.readFileSync)(process.env.GITHUB_EVENT_PATH, { encoding: "utf8" })); + const pullRequest = eventPayload.pull_request; + core.info(`Handling pull request ${eventPayload.action} for ${pullRequest.html_url}`); + if (pullRequest.state !== "open") { + core.info("Pull request already closed, ignoring"); + return; + } + if ((0, utils_1.isFork)(pullRequest)) { + core.setFailed("Setting a scheduled merge is not allowed from forks"); + return; + } + const previousComment = await (0, comment_1.getPreviousComment)(octokit, pullRequest.number); + const prHasScheduledCommand = await (0, utils_1.hasScheduledCommand)(pullRequest, octokit); + if (!prHasScheduledCommand) { + if (previousComment) { + await (0, comment_1.deleteComment)(octokit, previousComment.id); + } + core.info("No /schedule command found"); + return; + } + const dateString = (0, utils_1.getScheduleDateString)(pullRequest.body); + if (dateString) { + core.info(`Schedule date found: "${dateString}"`); + } + let commentBody = ""; + if (dateString) { + if (!(0, utils_1.isValidDate)(dateString)) { + commentBody = (0, comment_1.generateBody)(`"${dateString}" is not a valid date`, "error"); + } + else if (new Date(dateString) < (0, locale_date_1.default)()) { + let message = `${(0, utils_1.stringifyDate)(dateString)} (UTC) is already in the past`; + if (process.env.INPUT_TIME_ZONE !== "UTC") { + message = `${message} on ${process.env.INPUT_TIME_ZONE} time zone`; + } + commentBody = (0, comment_1.generateBody)(message, "warning"); + } + else { + commentBody = (0, comment_1.generateBody)(`Scheduled to be merged on ${(0, utils_1.stringifyDate)(dateString)} (UTC)`, "pending"); + } + } + else { + commentBody = (0, comment_1.generateBody)(`Scheduled to be merged the next time the merge action is scheduled via the cron expressions`, "pending"); + } + if (previousComment) { + if (previousComment.body === commentBody) { + core.info("Comment already up to date"); + return; + } + const { data } = await (0, comment_1.updateComment)(octokit, previousComment.id, commentBody); + core.info(`Comment updated: ${data.html_url}`); + return; + } + const { data } = await (0, comment_1.createComment)(octokit, pullRequest.number, commentBody); + core.info(`Comment created: ${data.html_url}`); +} +exports["default"] = handlePullRequest; + + +/***/ }), + +/***/ 7976: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +const core = __importStar(__nccwpck_require__(2186)); +const github = __importStar(__nccwpck_require__(5438)); +const comment_1 = __nccwpck_require__(8111); +const locale_date_1 = __importDefault(__nccwpck_require__(3663)); +const commit_1 = __nccwpck_require__(1870); +const utils_1 = __nccwpck_require__(1715); +/** + * handle "schedule" event + */ +async function handleSchedule() { + if (!process.env.GITHUB_TOKEN) { + core.setFailed("GITHUB_TOKEN environment variable is not set"); + return; + } + const mergeMethod = process.env.INPUT_MERGE_METHOD; + const requireStatusesSuccess = process.env.INPUT_REQUIRE_STATUSES_SUCCESS === "true"; + const automergeFailLabel = process.env.INPUT_AUTOMERGE_FAIL_LABEL; + if (!(0, utils_1.isValidMergeMethod)(mergeMethod)) { + core.setFailed(`merge_method "${mergeMethod}" is invalid`); + return; + } + core.info(`GITHUB_TOKEN: ${process.env.GITHUB_TOKEN}`); + const octokit = github.getOctokit(process.env.GITHUB_TOKEN); + core.info("Loading open pull requests"); + const pullRequests = await octokit.paginate(octokit.rest.pulls.list, { + ...github.context.repo, + state: "open", + }, (response) => { + const responseData = response.data; + console.info(responseData); + return responseData + .filter((pullRequest) => !(0, utils_1.isFork)(pullRequest)) + .filter((pullRequest) => (0, utils_1.hasScheduledCommand)(pullRequest, octokit)) + .filter((pullRequest) => pullRequest.labels.every((label) => label.name !== automergeFailLabel)) + .map((pullRequest) => { + return { + number: pullRequest.number, + html_url: pullRequest.html_url, + scheduledDate: (0, utils_1.getScheduleDateString)(pullRequest.body), + ref: pullRequest.head.sha, + }; + }); + }); + core.info(`${pullRequests.length} scheduled pull requests found`); + if (pullRequests.length === 0) { + return; + } + const duePullRequests = pullRequests.filter((pullRequest) => pullRequest.scheduledDate === "" || + new Date(pullRequest.scheduledDate) < (0, locale_date_1.default)()); + core.info(`${duePullRequests.length} due pull requests found`); + if (duePullRequests.length === 0) { + return; + } + for await (const pullRequest of duePullRequests) { + if (requireStatusesSuccess) { + const [checkRunsStatus, statusesStatus] = await Promise.all([ + (0, commit_1.getCommitChecksRunsStatus)(octokit, pullRequest.ref), + (0, commit_1.getCommitStatusesStatus)(octokit, pullRequest.ref), + ]); + if (checkRunsStatus !== "completed" || statusesStatus !== "success") { + core.info(`${pullRequest.html_url} is not ready to be merged yet because all checks are not completed or statuses are not success`); + continue; + } + } + try { + await octokit.rest.pulls.merge({ + ...github.context.repo, + pull_number: pullRequest.number, + merge_method: mergeMethod, + }); + core.info(`${pullRequest.html_url} merged`); + } + catch (error) { + const previousComment = await (0, comment_1.getPreviousComment)(octokit, pullRequest.number, "fail"); + const commentBody = (0, comment_1.generateBody)(`Scheduled merge failed: ${error.message}\nIn order to let the automerge-automation try again, the label "${automergeFailLabel}" should be removed.`, "error", "fail"); + if (previousComment) { + const { data } = await (0, comment_1.updateComment)(octokit, previousComment.id, commentBody); + core.info(`Comment updated: ${data.html_url}`); + } + else { + const { data } = await (0, comment_1.createComment)(octokit, pullRequest.number, commentBody); + core.info(`Comment created: ${data.html_url}`); + } + await octokit.rest.issues.addLabels({ + ...github.context.repo, + issue_number: pullRequest.number, + labels: [automergeFailLabel], + }); + core.info(`Label added: "${automergeFailLabel}"`); + continue; + } + const previousComment = await (0, comment_1.getPreviousComment)(octokit, pullRequest.number); + let commentBody = ""; + if (pullRequest.scheduledDate) { + commentBody = (0, comment_1.generateBody)(`Scheduled on ${pullRequest.scheduledDate} (UTC) successfully merged`, "success"); + } + else { + commentBody = (0, comment_1.generateBody)(`Scheduled on next cron expression successfully merged`, "success"); + } + if (previousComment) { + const { data } = await (0, comment_1.updateComment)(octokit, previousComment.id, commentBody); + core.info(`Comment updated: ${data.html_url}`); + continue; + } + const { data } = await (0, comment_1.createComment)(octokit, pullRequest.number, commentBody); + core.info(`Comment created: ${data.html_url}`); + } +} +exports["default"] = handleSchedule; + + /***/ }), /***/ 5075: @@ -9445,18 +9846,23 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", ({ value: true })); const core = __importStar(__nccwpck_require__(2186)); const github = __importStar(__nccwpck_require__(5438)); +const handle_pull_request_1 = __importDefault(__nccwpck_require__(2719)); +const handle_schedule_1 = __importDefault(__nccwpck_require__(7976)); main(); async function main() { try { core.info(github.context.eventName); - // if (github.context.eventName === "pull_request" || github.context.eventName === "issue_comment") { - // await handlePullRequest(); - // return; - // } - // await handleSchedule(); + if (github.context.eventName === "pull_request" || github.context.eventName === "issue_comment") { + await (0, handle_pull_request_1.default)(); + return; + } + await (0, handle_schedule_1.default)(); } catch (error) { core.setFailed(error); @@ -9464,6 +9870,100 @@ async function main() { } +/***/ }), + +/***/ 3663: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +function localeDate() { + const localeString = new Date().toLocaleString("en-US", { + timeZone: process.env.INPUT_TIME_ZONE, + }); + return new Date(localeString); +} +exports["default"] = localeDate; + + +/***/ }), + +/***/ 1715: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.stringifyDate = exports.isValidDate = exports.isValidMergeMethod = exports.getScheduleDateString = exports.isFork = exports.hasScheduledCommand = void 0; +const github = __importStar(__nccwpck_require__(5438)); +const core = __importStar(__nccwpck_require__(2186)); +async function hasScheduledCommand(pullRequest, octokit) { + const bodyContains = pullRequest.body != null ? /(^|\n)\/schedule/.test(pullRequest.body) : false; + const prComments = await octokit.paginate(octokit.rest.issues.listComments, { + ...github.context.repo, + issue_number: pullRequest.number, + }, (response) => { + return response.data.filter((comment) => /(^|\n)\/schedule/.test(comment.body ?? "")); + }); + core.info(`PrComments: ${prComments}`); + const last = prComments.pop; + core.info(`Last pr comment: ${last}`); + return bodyContains || last != undefined; +} +exports.hasScheduledCommand = hasScheduledCommand; +function isFork(pullRequest) { + return pullRequest.head.repo.fork; +} +exports.isFork = isFork; +function getScheduleDateString(text) { + if (!text) + return ""; + return text.match(/(^|\n)\/schedule (.*)/)?.pop() ?? ""; +} +exports.getScheduleDateString = getScheduleDateString; +function isValidMergeMethod(method) { + return ["merge", "squash", "rebase"].includes(method); +} +exports.isValidMergeMethod = isValidMergeMethod; +/** + * @reference https://stackoverflow.com/a/1353711/206879 + */ +function isValidDate(dateString) { + return !isNaN(new Date(dateString).getTime()); +} +exports.isValidDate = isValidDate; +function stringifyDate(datestring) { + const dateTimeString = new Date(datestring).toISOString().split(".")[0]; + const [date, time] = dateTimeString.split("T"); + return `${date} ${time}`; +} +exports.stringifyDate = stringifyDate; + + /***/ }), /***/ 2877: diff --git a/lib/handle-pull-request.ts b/lib/handle-pull-request.ts index 2e83eab..e57b6bb 100644 --- a/lib/handle-pull-request.ts +++ b/lib/handle-pull-request.ts @@ -30,8 +30,6 @@ export default async function handlePullRequest(): Promise { return; } - core.info(`GITHUB_TOKEN: ${process.env.GITHUB_TOKEN}`) - const octokit = github.getOctokit(process.env.GITHUB_TOKEN); const eventPayload = JSON.parse( diff --git a/lib/index.ts b/lib/index.ts index 50141d0..98efbd8 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -10,12 +10,12 @@ async function main() { try { core.info(github.context.eventName); - // if (github.context.eventName === "pull_request" || github.context.eventName === "issue_comment") { - // await handlePullRequest(); - // return; - // } + if (github.context.eventName === "pull_request" || github.context.eventName === "issue_comment") { + await handlePullRequest(); + return; + } - // await handleSchedule(); + await handleSchedule(); } catch (error) { core.setFailed(error as Error); }