From 3e9e113b20f69fbb9314123cfa3812bd37e6aaa1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Jun 2026 23:07:01 +0000 Subject: [PATCH 1/4] Close zero-edited-file PRs --- .../src/_tests/zero-edited-files.test.ts | 45 +++++++++++++++++++ packages/mergebot/src/compute-pr-actions.ts | 1 + packages/mergebot/src/pr-info.ts | 6 ++- 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 packages/mergebot/src/_tests/zero-edited-files.test.ts diff --git a/packages/mergebot/src/_tests/zero-edited-files.test.ts b/packages/mergebot/src/_tests/zero-edited-files.test.ts new file mode 100644 index 0000000000..4e0c8298d4 --- /dev/null +++ b/packages/mergebot/src/_tests/zero-edited-files.test.ts @@ -0,0 +1,45 @@ +import { join } from "path"; +import { process } from "../compute-pr-actions"; +import { deriveStateForPR, PRQueryResponse } from "../pr-info"; +import { readJsonSync } from "../util/util"; + +describe("zero edited files", () => { + it("closes open PRs immediately", async () => { + const responsePath = join(__dirname, "fixtures", "43136", "_response.json"); + const response: PRQueryResponse = readJsonSync(responsePath); + const original = response.data.repository?.pullRequest; + if (!original) throw new Error("Missing pull request in fixture"); + + const prInfo = { + ...original, + changedFiles: 0, + files: { ...original.files, nodes: [] }, + }; + + const derived = await deriveStateForPR( + prInfo, + async () => { + throw new Error("fetchFile should not be called"); + }, + async () => { + throw new Error("getDownloads should not be called"); + }, + new Date("2026-01-01T00:00:00.000Z"), + ); + + expect(derived).toMatchObject({ + type: "remove", + message: "PR has no edited files", + isDraft: false, + shouldClose: true, + }); + + const actions = process(derived); + expect(actions).toMatchObject({ + projectColumn: "*REMOVE*", + shouldClose: true, + shouldUpdateLabels: false, + }); + expect(actions.responseComments).toEqual([]); + }); +}); diff --git a/packages/mergebot/src/compute-pr-actions.ts b/packages/mergebot/src/compute-pr-actions.ts index 41b27e673d..f3fef08bdc 100644 --- a/packages/mergebot/src/compute-pr-actions.ts +++ b/packages/mergebot/src/compute-pr-actions.ts @@ -284,6 +284,7 @@ export function process(prInfo: BotResult, extendedCallback: (info: ExtendedPrIn return { ...createEmptyActions(), projectColumn: prInfo.isDraft ? "Needs Author Action" : "*REMOVE*", + shouldClose: !!prInfo.shouldClose, }; } diff --git a/packages/mergebot/src/pr-info.ts b/packages/mergebot/src/pr-info.ts index 52bc288e92..76773c9bcb 100644 --- a/packages/mergebot/src/pr-info.ts +++ b/packages/mergebot/src/pr-info.ts @@ -53,6 +53,7 @@ interface BotEnsureRemovedFromProject { readonly now: Date; readonly message: string; readonly isDraft: boolean; + readonly shouldClose?: boolean; } export interface PackageInfo { @@ -216,6 +217,7 @@ export async function deriveStateForPR( if (prInfo.isDraft) return botEnsureRemovedFromProject("PR is a draft"); if (prInfo.state !== "OPEN") return botEnsureRemovedFromProject("PR is not active"); + if (prInfo.changedFiles === 0) return botEnsureRemovedFromProject("PR has no edited files", true); const headCommit = getHeadCommit(prInfo); // eslint-disable-next-line eqeqeq @@ -316,8 +318,8 @@ export async function deriveStateForPR( return { type: "error", now, message, author: prInfo.author?.login }; } - function botEnsureRemovedFromProject(message: string): BotEnsureRemovedFromProject { - return { type: "remove", now, message, isDraft: prInfo.isDraft }; + function botEnsureRemovedFromProject(message: string, shouldClose = false): BotEnsureRemovedFromProject { + return { type: "remove", now, message, isDraft: prInfo.isDraft, shouldClose }; } } From 22a71a60bc71deef80707b11548756fb9cfeb0f6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Jun 2026 23:08:24 +0000 Subject: [PATCH 2/4] Add zero-file PR regression test --- packages/mergebot/src/_tests/zero-edited-files.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/mergebot/src/_tests/zero-edited-files.test.ts b/packages/mergebot/src/_tests/zero-edited-files.test.ts index 4e0c8298d4..92c71c0ace 100644 --- a/packages/mergebot/src/_tests/zero-edited-files.test.ts +++ b/packages/mergebot/src/_tests/zero-edited-files.test.ts @@ -14,7 +14,7 @@ describe("zero edited files", () => { ...original, changedFiles: 0, files: { ...original.files, nodes: [] }, - }; + } as typeof original; const derived = await deriveStateForPR( prInfo, @@ -30,7 +30,6 @@ describe("zero edited files", () => { expect(derived).toMatchObject({ type: "remove", message: "PR has no edited files", - isDraft: false, shouldClose: true, }); From 52c92f27f43b11167f61369de7cf661187c19069 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Jun 2026 00:08:40 +0000 Subject: [PATCH 3/4] Use fixture for zero-edited-files behavior --- .../74980-zero-edited-files/_downloads.json | 1 + .../74980-zero-edited-files/_files.json | 1 + .../74980-zero-edited-files/_response.json | 133 ++++++++++++++++++ .../74980-zero-edited-files/derived.json | 7 + .../74980-zero-edited-files/mutations.json | 10 ++ .../74980-zero-edited-files/result.json | 8 ++ .../src/_tests/zero-edited-files.test.ts | 44 ------ 7 files changed, 160 insertions(+), 44 deletions(-) create mode 100644 packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/_downloads.json create mode 100644 packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/_files.json create mode 100644 packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/_response.json create mode 100644 packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/derived.json create mode 100644 packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/mutations.json create mode 100644 packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/result.json delete mode 100644 packages/mergebot/src/_tests/zero-edited-files.test.ts diff --git a/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/_downloads.json b/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/_downloads.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/_downloads.json @@ -0,0 +1 @@ +{} diff --git a/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/_files.json b/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/_files.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/_files.json @@ -0,0 +1 @@ +{} diff --git a/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/_response.json b/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/_response.json new file mode 100644 index 0000000000..5fef083866 --- /dev/null +++ b/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/_response.json @@ -0,0 +1,133 @@ +{ + "data": { + "repository": { + "id": "MDEwOlJlcG9zaXRvcnk2MDkzMzE2", + "pullRequest": { + "id": "PR_kwDOAFz6BM7aQ8jd", + "title": "just Update package.json", + "createdAt": "2026-05-11T13:20:01Z", + "author": { + "login": "justinkrn68-droid", + "__typename": "User" + }, + "authorAssociation": "FIRST_TIME_CONTRIBUTOR", + "baseRef": { + "name": "master", + "__typename": "Ref" + }, + "labels": { + "nodes": [], + "__typename": "LabelConnection" + }, + "isDraft": false, + "mergeable": "MERGEABLE", + "number": 74980, + "state": "OPEN", + "headRefOid": "c6d1344b3c7e49f62f4befd1aaa8665eb6bd6864", + "baseRefOid": "84efd8820459db1cdaad122f2347683b7db023ee", + "changedFiles": 0, + "additions": 0, + "deletions": 0, + "commitIds": { + "totalCount": 1, + "nodes": [ + { + "commit": { + "oid": "c6d1344b3c7e49f62f4befd1aaa8665eb6bd6864", + "parents": { + "nodes": [ + { + "oid": "84efd8820459db1cdaad122f2347683b7db023ee", + "__typename": "Commit" + } + ], + "__typename": "CommitConnection" + }, + "__typename": "Commit" + }, + "__typename": "PullRequestCommit" + } + ], + "__typename": "PullRequestCommitConnection" + }, + "timelineItems": { + "nodes": [], + "__typename": "PullRequestTimelineItemsConnection" + }, + "reviews": { + "totalCount": 0, + "nodes": [], + "__typename": "PullRequestReviewConnection" + }, + "commits": { + "totalCount": 1, + "nodes": [ + { + "commit": { + "checkSuites": { + "nodes": [ + { + "databaseId": 68415365071, + "app": { + "name": "GitHub Actions", + "__typename": "App" + }, + "conclusion": "ACTION_REQUIRED", + "resourcePath": "/DefinitelyTyped/DefinitelyTyped/commit/c6d1344b3c7e49f62f4befd1aaa8665eb6bd6864/checks?check_suite_id=68415365071", + "status": "COMPLETED", + "url": "https://github.com/DefinitelyTyped/DefinitelyTyped/commit/c6d1344b3c7e49f62f4befd1aaa8665eb6bd6864/checks?check_suite_id=68415365071", + "checkRuns": { + "nodes": [], + "__typename": "CheckRunConnection" + }, + "createdAt": "2026-05-11T13:20:11Z", + "workflowRun": { + "databaseId": 25672723099, + "file": { + "path": ".github/workflows/CI.yml", + "__typename": "WorkflowRunFile" + }, + "__typename": "WorkflowRun" + }, + "__typename": "CheckSuite" + } + ], + "__typename": "CheckSuiteConnection" + }, + "status": null, + "authoredDate": "2026-05-11T13:19:36Z", + "committedDate": "2026-05-11T13:19:36Z", + "pushedDate": null, + "oid": "c6d1344b3c7e49f62f4befd1aaa8665eb6bd6864", + "__typename": "Commit" + }, + "__typename": "PullRequestCommit" + } + ], + "__typename": "PullRequestCommitConnection" + }, + "comments": { + "totalCount": 0, + "nodes": [], + "__typename": "IssueCommentConnection" + }, + "files": { + "totalCount": 0, + "nodes": [], + "pageInfo": { + "hasNextPage": false, + "endCursor": "MQ", + "__typename": "PageInfo" + }, + "__typename": "PullRequestChangedFileConnection" + }, + "projectItems": { + "nodes": [], + "__typename": "ProjectV2ItemConnection" + }, + "__typename": "PullRequest" + }, + "__typename": "Repository" + } + } +} diff --git a/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/derived.json b/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/derived.json new file mode 100644 index 0000000000..c80473d035 --- /dev/null +++ b/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/derived.json @@ -0,0 +1,7 @@ +{ + "type": "remove", + "now": "2026-06-09T18:11:33.900Z", + "message": "PR has no edited files", + "isDraft": false, + "shouldClose": true +} diff --git a/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/mutations.json b/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/mutations.json new file mode 100644 index 0000000000..8bdc4b8080 --- /dev/null +++ b/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/mutations.json @@ -0,0 +1,10 @@ +[ + { + "mutation": "mutation ($input: ClosePullRequestInput!) {\n closePullRequest(input: $input) {\n __typename\n }\n}", + "variables": { + "input": { + "pullRequestId": "PR_kwDOAFz6BM7aQ8jd" + } + } + } +] diff --git a/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/result.json b/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/result.json new file mode 100644 index 0000000000..0337357d46 --- /dev/null +++ b/packages/mergebot/src/_tests/fixtures/74980-zero-edited-files/result.json @@ -0,0 +1,8 @@ +{ + "labels": [], + "responseComments": [], + "shouldClose": true, + "shouldMerge": false, + "shouldUpdateLabels": false, + "projectColumn": "*REMOVE*" +} diff --git a/packages/mergebot/src/_tests/zero-edited-files.test.ts b/packages/mergebot/src/_tests/zero-edited-files.test.ts deleted file mode 100644 index 92c71c0ace..0000000000 --- a/packages/mergebot/src/_tests/zero-edited-files.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { join } from "path"; -import { process } from "../compute-pr-actions"; -import { deriveStateForPR, PRQueryResponse } from "../pr-info"; -import { readJsonSync } from "../util/util"; - -describe("zero edited files", () => { - it("closes open PRs immediately", async () => { - const responsePath = join(__dirname, "fixtures", "43136", "_response.json"); - const response: PRQueryResponse = readJsonSync(responsePath); - const original = response.data.repository?.pullRequest; - if (!original) throw new Error("Missing pull request in fixture"); - - const prInfo = { - ...original, - changedFiles: 0, - files: { ...original.files, nodes: [] }, - } as typeof original; - - const derived = await deriveStateForPR( - prInfo, - async () => { - throw new Error("fetchFile should not be called"); - }, - async () => { - throw new Error("getDownloads should not be called"); - }, - new Date("2026-01-01T00:00:00.000Z"), - ); - - expect(derived).toMatchObject({ - type: "remove", - message: "PR has no edited files", - shouldClose: true, - }); - - const actions = process(derived); - expect(actions).toMatchObject({ - projectColumn: "*REMOVE*", - shouldClose: true, - shouldUpdateLabels: false, - }); - expect(actions.responseComments).toEqual([]); - }); -}); From 0743d6ff1d64b04c2541ca54a4c324416af2487e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Jun 2026 14:56:45 +0000 Subject: [PATCH 4/4] Fix remove-state fixture regression for shouldClose --- packages/mergebot/src/pr-info.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/mergebot/src/pr-info.ts b/packages/mergebot/src/pr-info.ts index 76773c9bcb..c10518ce96 100644 --- a/packages/mergebot/src/pr-info.ts +++ b/packages/mergebot/src/pr-info.ts @@ -319,7 +319,8 @@ export async function deriveStateForPR( } function botEnsureRemovedFromProject(message: string, shouldClose = false): BotEnsureRemovedFromProject { - return { type: "remove", now, message, isDraft: prInfo.isDraft, shouldClose }; + const base: BotEnsureRemovedFromProject = { type: "remove", now, message, isDraft: prInfo.isDraft }; + return shouldClose ? { ...base, shouldClose: true } : base; } }