diff --git a/actions/setup/js/add_reaction_and_edit_comment.cjs b/actions/setup/js/add_reaction_and_edit_comment.cjs index 4773b8aa7b4..69242c35126 100644 --- a/actions/setup/js/add_reaction_and_edit_comment.cjs +++ b/actions/setup/js/add_reaction_and_edit_comment.cjs @@ -31,6 +31,34 @@ function expectRestEndpoint(endpoint, endpointName, eventName) { return endpoint; } +/** + * Build the "create issue comment" REST endpoint used to post the workflow-link comment + * on the issue or pull request associated with the triggering event. + * @param {string} owner - Repository owner + * @param {string} repo - Repository name + * @param {number} issueNumber - Issue or pull request number + * @returns {RestEndpoint} + */ +function issueCommentEndpoint(owner, repo, issueNumber) { + return { route: "POST /repos/{owner}/{repo}/issues/{issue_number}/comments", params: { owner, repo, issue_number: issueNumber } }; +} + +/** + * Verify a required payload field is present, calling core.setFailed with a consistent + * message when it is missing. + * @param {unknown} value - The extracted field value + * @param {string} fieldName - Human-readable field name for the error message + * @param {string} errorCode - Error code prefix (ERR_NOT_FOUND or ERR_VALIDATION) + * @returns {boolean} true if present, false if missing (setFailed already called) + */ +function requirePayloadField(value, fieldName, errorCode) { + if (!value) { + core.setFailed(`${errorCode}: ${fieldName} not found in event payload`); + return false; + } + return true; +} + /** * Resolve the reaction and comment API endpoints for a given event. * Returns null (after calling core.setFailed) when the event or payload is invalid. @@ -44,71 +72,50 @@ async function resolveEventEndpoints(eventName, owner, repo, payload) { switch (eventName) { case "issues": { const issueNumber = payload?.issue?.number; - if (!issueNumber) { - core.setFailed(`${ERR_NOT_FOUND}: Issue number not found in event payload`); - return null; - } + if (!requirePayloadField(issueNumber, "Issue number", ERR_NOT_FOUND)) return null; return { reactionEndpoint: { route: "POST /repos/{owner}/{repo}/issues/{issue_number}/reactions", params: { owner, repo, issue_number: issueNumber } }, - commentUpdateEndpoint: { route: "POST /repos/{owner}/{repo}/issues/{issue_number}/comments", params: { owner, repo, issue_number: issueNumber } }, + commentUpdateEndpoint: issueCommentEndpoint(owner, repo, issueNumber), }; } case "issue_comment": { const commentId = payload?.comment?.id; const issueNumber = payload?.issue?.number; - if (!commentId) { - core.setFailed(`${ERR_VALIDATION}: Comment ID not found in event payload`); - return null; - } - if (!issueNumber) { - core.setFailed(`${ERR_NOT_FOUND}: Issue number not found in event payload`); - return null; - } + if (!requirePayloadField(commentId, "Comment ID", ERR_VALIDATION)) return null; + if (!requirePayloadField(issueNumber, "Issue number", ERR_NOT_FOUND)) return null; return { reactionEndpoint: { route: "POST /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions", params: { owner, repo, comment_id: commentId } }, // Create new comment on the issue itself, not on the comment - commentUpdateEndpoint: { route: "POST /repos/{owner}/{repo}/issues/{issue_number}/comments", params: { owner, repo, issue_number: issueNumber } }, + commentUpdateEndpoint: issueCommentEndpoint(owner, repo, issueNumber), }; } case "pull_request": { const prNumber = payload?.pull_request?.number; - if (!prNumber) { - core.setFailed(`${ERR_NOT_FOUND}: Pull request number not found in event payload`); - return null; - } + if (!requirePayloadField(prNumber, "Pull request number", ERR_NOT_FOUND)) return null; // PRs are "issues" for the reactions endpoint return { reactionEndpoint: { route: "POST /repos/{owner}/{repo}/issues/{issue_number}/reactions", params: { owner, repo, issue_number: prNumber } }, - commentUpdateEndpoint: { route: "POST /repos/{owner}/{repo}/issues/{issue_number}/comments", params: { owner, repo, issue_number: prNumber } }, + commentUpdateEndpoint: issueCommentEndpoint(owner, repo, prNumber), }; } case "pull_request_review_comment": { const reviewCommentId = payload?.comment?.id; const prNumber = payload?.pull_request?.number; - if (!reviewCommentId) { - core.setFailed(`${ERR_VALIDATION}: Review comment ID not found in event payload`); - return null; - } - if (!prNumber) { - core.setFailed(`${ERR_NOT_FOUND}: Pull request number not found in event payload`); - return null; - } + if (!requirePayloadField(reviewCommentId, "Review comment ID", ERR_VALIDATION)) return null; + if (!requirePayloadField(prNumber, "Pull request number", ERR_NOT_FOUND)) return null; return { reactionEndpoint: { route: "POST /repos/{owner}/{repo}/pulls/comments/{comment_id}/reactions", params: { owner, repo, comment_id: reviewCommentId } }, // Create new comment on the PR itself (using issues endpoint since PRs are issues) - commentUpdateEndpoint: { route: "POST /repos/{owner}/{repo}/issues/{issue_number}/comments", params: { owner, repo, issue_number: prNumber } }, + commentUpdateEndpoint: issueCommentEndpoint(owner, repo, prNumber), }; } case "discussion": { const discussionNumber = payload?.discussion?.number; - if (!discussionNumber) { - core.setFailed(`${ERR_NOT_FOUND}: Discussion number not found in event payload`); - return null; - } + if (!requirePayloadField(discussionNumber, "Discussion number", ERR_NOT_FOUND)) return null; // Discussions use GraphQL API - get the node ID const discussionNodeId = await getDiscussionNodeId(owner, repo, discussionNumber); return { @@ -120,15 +127,9 @@ async function resolveEventEndpoints(eventName, owner, repo, payload) { case "discussion_comment": { const discussionNumber = payload?.discussion?.number; const commentId = payload?.comment?.id; - if (!discussionNumber || !commentId) { - core.setFailed(`${ERR_NOT_FOUND}: Discussion or comment information not found in event payload`); - return null; - } + if (!requirePayloadField(discussionNumber && commentId, "Discussion or comment information", ERR_NOT_FOUND)) return null; const commentNodeId = payload?.comment?.node_id; - if (!commentNodeId) { - core.setFailed(`${ERR_NOT_FOUND}: Discussion comment node ID not found in event payload`); - return null; - } + if (!requirePayloadField(commentNodeId, "Discussion comment node ID", ERR_NOT_FOUND)) return null; return { reactionEndpoint: commentNodeId, // Store node ID for GraphQL commentUpdateEndpoint: `discussion_comment:${discussionNumber}:${commentId}`, // Special format