From bbed4ddb9cd44c033813263aad57548510cb5922 Mon Sep 17 00:00:00 2001 From: Dale Seo <5466341+DaleSeo@users.noreply.github.com> Date: Sun, 19 Jul 2026 20:50:55 -0400 Subject: [PATCH] =?UTF-8?q?fix:=20=EB=B3=91=ED=95=A9=EC=9D=84=20squash=20?= =?UTF-8?q?=EA=B8=B0=EB=B3=B8=EA=B0=92=EC=9C=BC=EB=A1=9C=20=EB=B0=94?= =?UTF-8?q?=EA=BE=B8=EA=B3=A0=20auto-merge=20=EB=8C=80=EC=8B=A0=20?= =?UTF-8?q?=EC=A6=89=EC=8B=9C=20=EB=B3=91=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 2 +- README.md | 2 +- handlers/merge_prs.js | 85 +++++++------------------------------------ 3 files changed, 16 insertions(+), 73 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index bf5188f..269f4bb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -208,7 +208,7 @@ GitHub Organization webhook 수신용 엔드포인트 #### `POST /merge-prs` -열려있는 PR을 일괄 병합합니다. 기본 병합 방식은 `merge`이며 `merge_method` 값으로 `merge | squash | rebase` 중 선택할 수 있습니다. `excludes`로 특정 PR을 제외할 수 있습니다. 승인 리뷰가 없거나 `maintenance` 라벨이 붙은 PR, Draft PR, GitHub `mergeable_state !== "clean"` PR은 스킵되며 `unknown`/`behind` 상태는 최대 1초 후 한 번 더 확인합니다. +열려있는 PR을 일괄 병합합니다. 기본 병합 방식은 `squash`이며 `merge_method` 값으로 `merge | squash | rebase` 중 선택할 수 있습니다. `excludes`로 특정 PR을 제외할 수 있습니다. 승인 리뷰가 없거나 `maintenance` 라벨이 붙은 PR, Draft PR, GitHub `mergeable_state !== "clean"` PR은 스킵되며 `unknown`/`behind` 상태는 최대 1초 후 한 번 더 확인합니다. **Request:** diff --git a/README.md b/README.md index e85e9d6..6f446fb 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ https://github.dalestudy.com ### `POST /merge-prs` -열려있는 PR을 일괄 병합합니다. 기본 병합 방식은 `merge`이며, `merge_method`로 `merge | squash | rebase` 중 선택할 수 있습니다. `excludes` 배열로 특정 PR을 제외할 수 있습니다. 최소 1개의 승인 리뷰가 없거나 Draft/`maintenance` 라벨이 붙은 PR은 스킵되며, GitHub에서 `mergeable_state === "clean"`인 PR만 병합됩니다(`behind`, `dirty`, `unknown` 등은 스킵). `unknown`/`behind` 상태는 최대 1초 후 한 차례 재확인합니다. +열려있는 PR을 일괄 병합합니다. 기본 병합 방식은 `squash`이며, `merge_method`로 `merge | squash | rebase` 중 선택할 수 있습니다. `excludes` 배열로 특정 PR을 제외할 수 있습니다. 최소 1개의 승인 리뷰가 없거나 Draft/`maintenance` 라벨이 붙은 PR은 스킵되며, GitHub에서 `mergeable_state === "clean"`인 PR만 병합됩니다(`behind`, `dirty`, `unknown` 등은 스킵). `unknown`/`behind` 상태는 최대 1초 후 한 차례 재확인합니다. **Request:** diff --git a/handlers/merge_prs.js b/handlers/merge_prs.js index bb14d63..fb2726b 100644 --- a/handlers/merge_prs.js +++ b/handlers/merge_prs.js @@ -28,7 +28,7 @@ export async function mergePrs(request, env) { } const { repoOwner, repoName, week, excludes, rawPayload } = payload.data; - const mergeMethod = (rawPayload.merge_method || "merge").toLowerCase(); + const mergeMethod = (rawPayload.merge_method || "squash").toLowerCase(); if (!ALLOWED_MERGE_METHODS.has(mergeMethod)) { return errorResponse( @@ -150,90 +150,33 @@ export async function mergePrs(request, env) { } async function mergePullRequest(owner, repo, prNumber, mergeMethod, token, sha) { - // 1. PR의 GraphQL node ID 조회 - const nodeId = await getPullRequestNodeId(owner, repo, prNumber, token); - if (!nodeId) { - return { - merged: false, - error: "Failed to get PR node ID", - }; - } - - // 2. Merge method 매핑 (REST → GraphQL) - const graphqlMergeMethod = { - merge: "MERGE", - squash: "SQUASH", - rebase: "REBASE", - }[mergeMethod] || "MERGE"; - - // 3. Auto-merge 활성화 (Merge Queue 사용) - const mutation = ` - mutation { - enablePullRequestAutoMerge(input: { - pullRequestId: "${nodeId}" - mergeMethod: ${graphqlMergeMethod} - }) { - pullRequest { - id - number - autoMergeRequest { - enabledAt - mergeMethod - } - } - } + const response = await fetch( + `https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}/merge`, + { + method: "PUT", + headers: { + ...getGitHubHeaders(token), + "Content-Type": "application/json", + }, + body: JSON.stringify({ merge_method: mergeMethod, sha }), } - `; - - const response = await fetch("https://api.github.com/graphql", { - method: "POST", - headers: { - ...getGitHubHeaders(token), - "Content-Type": "application/json", - }, - body: JSON.stringify({ query: mutation }), - }); + ); const result = await safeJson(response); - if (response.ok && result.data?.enablePullRequestAutoMerge?.pullRequest) { + if (response.ok && result.merged) { return { merged: true, - autoMergeEnabled: true, - sha: sha, + sha: result.sha, }; } return { merged: false, - error: result.errors?.[0]?.message || "Auto-merge failed", + error: result.message || "Merge failed", }; } -async function getPullRequestNodeId(owner, repo, prNumber, token) { - const query = ` - query { - repository(owner: "${owner}", name: "${repo}") { - pullRequest(number: ${prNumber}) { - id - } - } - } - `; - - const response = await fetch("https://api.github.com/graphql", { - method: "POST", - headers: { - ...getGitHubHeaders(token), - "Content-Type": "application/json", - }, - body: JSON.stringify({ query }), - }); - - const result = await safeJson(response); - return result.data?.repository?.pullRequest?.id || null; -} - async function getMergeableState(owner, repo, prNumber, token) { const prDetails = await getPullRequestDetails(owner, repo, prNumber, token);