Move validateExclusiveModes before getBody for fail-fast validation (#1663)

* Initial plan

* feat: refactor option validation to list-based approach and add delete+hide_and_recreate check

Co-authored-by: marocchino <128431+marocchino@users.noreply.github.com>

* feat: add only_update to exclusive modes validation list

Co-authored-by: marocchino <128431+marocchino@users.noreply.github.com>

* refactor: extract validation logic into src/validate.ts

Co-authored-by: marocchino <128431+marocchino@users.noreply.github.com>

* refactor: move validateExclusiveModes before getBody in run()

Co-authored-by: marocchino <128431+marocchino@users.noreply.github.com>

* test: assert getBody is not called when validateExclusiveModes fails

Co-authored-by: marocchino <128431+marocchino@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: marocchino <128431+marocchino@users.noreply.github.com>
This commit is contained in:
Copilot 2026-03-13 21:05:41 +09:00 committed by GitHub
parent 70d2764d1a
commit 14d4f1e429
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 151 additions and 28 deletions

View file

@ -27,6 +27,7 @@ import {
repo,
skipUnchanged,
} from "./config"
import {validateBody, validateExclusiveModes} from "./validate"
async function run(): Promise<undefined> {
if (Number.isNaN(pullRequestNumber) || pullRequestNumber < 1) {
@ -35,6 +36,15 @@ async function run(): Promise<undefined> {
}
try {
validateExclusiveModes(
deleteOldComment,
recreate,
onlyCreateComment,
onlyUpdateComment,
hideOldComment,
hideAndRecreate,
)
const body = await getBody()
if (!body && ignoreEmpty) {
@ -42,29 +52,7 @@ async function run(): Promise<undefined> {
return
}
if (!deleteOldComment && !hideOldComment && !body) {
throw new Error("Either message or path input is required")
}
if (deleteOldComment && recreate) {
throw new Error("delete and recreate cannot be both set to true")
}
if (deleteOldComment && onlyCreateComment) {
throw new Error("delete and only_create cannot be both set to true")
}
if (deleteOldComment && hideOldComment) {
throw new Error("delete and hide cannot be both set to true")
}
if (onlyCreateComment && onlyUpdateComment) {
throw new Error("only_create and only_update cannot be both set to true")
}
if (hideOldComment && hideAndRecreate) {
throw new Error("hide and hide_and_recreate cannot be both set to true")
}
validateBody(body, deleteOldComment, hideOldComment)
const octokit = github.getOctokit(githubToken)
const previous = await findPreviousComment(octokit, repo, pullRequestNumber, header)

35
src/validate.ts Normal file
View file

@ -0,0 +1,35 @@
export function validateBody(
body: string,
deleteOldComment: boolean,
hideOldComment: boolean,
): void {
if (!deleteOldComment && !hideOldComment && !body) {
throw new Error("Either message or path input is required")
}
}
export function validateExclusiveModes(
deleteOldComment: boolean,
recreate: boolean,
onlyCreateComment: boolean,
onlyUpdateComment: boolean,
hideOldComment: boolean,
hideAndRecreate: boolean,
): void {
const exclusiveModes: [string, boolean][] = [
["delete", deleteOldComment],
["recreate", recreate],
["only_create", onlyCreateComment],
["only_update", onlyUpdateComment],
["hide", hideOldComment],
["hide_and_recreate", hideAndRecreate],
]
const enabledModes = exclusiveModes.filter(([, flag]) => flag).map(([name]) => name)
if (enabledModes.length > 1) {
const last = enabledModes[enabledModes.length - 1]
const rest = enabledModes.slice(0, -1)
const joined =
enabledModes.length === 2 ? `${rest[0]} and ${last}` : `${rest.join(", ")}, and ${last}`
throw new Error(`${joined} cannot be set to true simultaneously`)
}
}