[code-simplifier] refactor(js): simplify add_reaction.cjs payload validation and error handling#48271
Conversation
…handling - Extract requirePayloadField() helper to eliminate 4 repeated null-check + setFailed patterns in resolveRestEndpoint - Consolidate duplicate try/catch blocks in handleGraphQLOrUnknownEvent: resolve subjectId per-case, then call addDiscussionReaction once with a single shared error handler Behavior is unchanged. No new exports added. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅ |
|
✅ Design Decision Gate 🏗️ completed the design decision gate check. No ADR enforcement needed: PR #48271 does not have the 'implementation' label and has 0 new lines of code in business logic directories (threshold: 100). |
|
✅ Test Quality Sentinel completed test quality analysis. No test files were added or modified in this PR. Test Quality Sentinel skipped. |
|
✅ PR Code Quality Reviewer completed the code quality review. |
There was a problem hiding this comment.
Pull request overview
Refactors reaction payload validation and consolidates GraphQL reaction handling.
Changes:
- Extracts shared payload-field validation.
- Consolidates discussion reaction error handling.
- Introduces a regression where discussion lookup errors escape uncaught.
Show a summary per file
| File | Description |
|---|---|
actions/setup/js/add_reaction.cjs |
Simplifies validation and GraphQL reaction flow. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 1/1 changed files
- Comments generated: 1
- Review effort level: Medium
| } | ||
| return; | ||
| if (!requirePayloadField(payload, discussionNumber, "Discussion number", ERR_NOT_FOUND)) return; | ||
| subjectId = await getDiscussionNodeId(owner, repo, discussionNumber); |
There was a problem hiding this comment.
Fixed in 31a21c1. getDiscussionNodeId() is back inside the shared try so lookup-time GraphQL/not-found errors flow through handleReactionError again.
There was a problem hiding this comment.
Review: simplify add_reaction.cjs
The refactor is clear and the requirePayloadField extraction is a genuine improvement. Two blocking issues found:
- Unused
payloadparameter inrequirePayloadField— dead code, should be removed. getDiscussionNodeId()moved outsidetry/catch— behavioral regression; errors from that async call are no longer handled byhandleReactionErrorand will propagate as unhandled rejections.
See inline comments for details.
🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 17.1 AIC · ⌖ 4.66 AIC · ⊞ 5K
| * @returns {boolean} true if valid, false if missing (setFailed already called) | ||
| */ | ||
| function requirePayloadField(payload, value, fieldName, errorCode) { | ||
| if (!value) { |
There was a problem hiding this comment.
The payload parameter is declared in the function signature but never used inside the function body — it is dead code.
Consider removing it:
function requirePayloadField(value, fieldName, errorCode) {And update all call sites to drop the payload argument.
@copilot please address this.
There was a problem hiding this comment.
Fixed in 31a21c1. I removed the unused payload parameter from requirePayloadField() and updated all call sites.
There was a problem hiding this comment.
Skills-Based Review 🧠
Applied /codebase-design — requesting changes on three issues in the refactored code.
📋 Key Themes & Highlights
Issues Found
- Unused
payloadparameter (line 71) — dead code in the function signature. - Falsy
!valuecheck (line 73) — incorrectly rejects numeric0(valid GitHub ID); prefervalue == null. - Unguarded
subjectId(line 162) — uninitialisedletbefore the switch; a future case that forgets assignment silently passesundefinedtoaddDiscussionReaction.
Positive Highlights
- ✅ Clean extraction of
requirePayloadFieldeliminates 4 repeated 3-line blocks. - ✅ Single shared try/catch in
handleGraphQLOrUnknownEventis a clear readability win. - ✅ Net −3 lines with no functional regression.
🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 31.6 AIC · ⌖ 4.84 AIC · ⊞ 6.7K
Comment /matt to run again
| * @param {string} errorCode - Error code prefix (ERR_NOT_FOUND or ERR_VALIDATION) | ||
| * @returns {boolean} true if valid, false if missing (setFailed already called) | ||
| */ | ||
| function requirePayloadField(payload, value, fieldName, errorCode) { |
There was a problem hiding this comment.
[/codebase-design] The payload parameter is declared but never used inside requirePayloadField — it is dead code in the signature.
💡 Suggested fix
Remove the unused payload parameter and update call sites:
function requirePayloadField(value, fieldName, errorCode) {
if (!value) {
core.setFailed(`${errorCode}: ${fieldName} not found in event payload`);
return false;
}
return true;
}Call sites become e.g. requirePayloadField(issueNumber, "Issue number", ERR_NOT_FOUND).
@copilot please address this.
There was a problem hiding this comment.
Fixed in 31a21c1. requirePayloadField() now only accepts the resolved value, field name, and error code; the dead payload argument is gone.
| return; | ||
| } | ||
|
|
||
| try { |
There was a problem hiding this comment.
[/codebase-design] subjectId is declared with let before the switch but is never explicitly initialised. If a future developer adds a new case branch and forgets to assign subjectId, the code will silently call addDiscussionReaction(undefined, reaction) rather than failing fast.
💡 Suggested fix
Initialise to undefined explicitly and add a post-switch guard, or restructure with early returns as the original code did:
let subjectId = undefined;
// ... switch ...
if (subjectId == null) {
core.setFailed(`${ERR_VALIDATION}: subjectId could not be resolved for event: ${eventName}`);
return;
}
try {
await addDiscussionReaction(subjectId, reaction);This makes the contract explicit and is defensive against new case additions.
@copilot please address this.
There was a problem hiding this comment.
Addressed in 31a21c1. handleGraphQLOrUnknownEvent() now validates that subjectId was resolved before calling addDiscussionReaction().
There was a problem hiding this comment.
REQUEST_CHANGES — one correctness regression introduced by the refactor, plus two issues with the new helper.
### Blocking Issues
-
getDiscussionNodeIduncaught (high): Moving thisawaitoutside the try/catch is a behavioral regression — errors from GraphQL/network failures now propagate uncaught instead of going throughhandleReactionError. -
!valuefalsy guard (medium): Rejects0and""which are semantically valid-but-empty IDs. Should usevalue == null. -
Dead
payloadparameter (medium):requirePayloadField(payload, ...)acceptspayloadbut never reads it. Misleads callers and will trigger linter warnings.
🔎 Code quality review by PR Code Quality Reviewer · sonnet46 · 32.3 AIC · ⌖ 4.9 AIC · ⊞ 5.7K
Comment /review to run again
| * @param {string} errorCode - Error code prefix (ERR_NOT_FOUND or ERR_VALIDATION) | ||
| * @returns {boolean} true if valid, false if missing (setFailed already called) | ||
| */ | ||
| function requirePayloadField(payload, value, fieldName, errorCode) { |
There was a problem hiding this comment.
Falsy !value check silently rejects numeric 0 — while GitHub numbers are never 0 in practice, this guard is fragile and semantically wrong for an ID validator.
💡 Details and fix
!value is true for 0, "", false, null, and undefined. For numeric IDs the dangerous case is 0, and for string node IDs an empty string "" would also be silently treated as missing. Use an explicit null check:
function requirePayloadField(value, fieldName, errorCode) {
if (value == null) {
core.setFailed(`${errorCode}: ${fieldName} not found in event payload`);
return false;
}
return true;
}Note: the payload parameter is also unused — see related comment.
There was a problem hiding this comment.
Fixed in 31a21c1. The helper now uses value == null, so it only treats missing values as absent.
|
|
||
| /** | ||
| * Extract a required field from the event payload, calling setFailed if missing. | ||
| * @param {Record<string, any>} payload |
There was a problem hiding this comment.
Dead parameter: payload is accepted but never used inside requirePayloadField — removes from the caller's perspective any hint that the function inspects the payload, but it actually doesn't.
💡 Suggested fix
Drop the parameter entirely:
function requirePayloadField(value, fieldName, errorCode) {
if (!value) {
core.setFailed(`${errorCode}: ${fieldName} not found in event payload`);
return false;
}
return true;
}Update all call sites to remove the payload argument. The JSDoc @param {Record<string, any>} payload block also needs to be removed.
There was a problem hiding this comment.
Fixed in 31a21c1. I removed the unused payload parameter and its JSDoc entry from requirePayloadField().
|
@copilot run pr-finisher skill |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Summary
Refactors payload validation and error handling in
actions/setup/js/add_reaction.cjsfor clarity and maintainability. No functional API changes.Changes
actions/setup/js/add_reaction.cjsrequirePayloadField()helper — centralises null-check validation with consistent error messaging (ERR_NOT_FOUND/ERR_VALIDATION), replacing four identical inline blocks inresolveRestEndpoint().handleGraphQLOrUnknownEvent()— restructured to resolvesubjectIdin a singleswitch, then calladdDiscussionReaction()once, eliminating duplicatetry-catchblocks per event type.discussionevents that was inadvertently removed in a prior commit is now re-applied under the unifiedcatchblock.Impact
Commits
d0741419frefactor(js): simplify add_reaction.cjs payload validation and error handling31a21c174fix: restore add_reaction discussion error handling73a185909chore: start PR finisher triage