From fd012347a225f8b53ae63ae70104a62cdf360a9a Mon Sep 17 00:00:00 2001 From: atsushi-ishibashi Date: Wed, 30 Jul 2025 23:18:34 +0900 Subject: [PATCH] feat: exclude hidden (minimized) comments from GitHub Issues and PRs (#368) * feat: ignore minimized comments * fix tests --- src/github/api/queries/github.ts | 3 + src/github/data/fetcher.ts | 4 +- src/github/data/formatter.ts | 6 +- src/github/types.ts | 1 + test/data-formatter.test.ts | 210 +++++++++++++++++++++++++++++++ 5 files changed, 221 insertions(+), 3 deletions(-) diff --git a/src/github/api/queries/github.ts b/src/github/api/queries/github.ts index e0e4c25..25395b9 100644 --- a/src/github/api/queries/github.ts +++ b/src/github/api/queries/github.ts @@ -46,6 +46,7 @@ export const PR_QUERY = ` login } createdAt + isMinimized } } reviews(first: 100) { @@ -69,6 +70,7 @@ export const PR_QUERY = ` login } createdAt + isMinimized } } } @@ -98,6 +100,7 @@ export const ISSUE_QUERY = ` login } createdAt + isMinimized } } } diff --git a/src/github/data/fetcher.ts b/src/github/data/fetcher.ts index 160c724..ace1b85 100644 --- a/src/github/data/fetcher.ts +++ b/src/github/data/fetcher.ts @@ -134,7 +134,7 @@ export async function fetchGitHubData({ // Prepare all comments for image processing const issueComments: CommentWithImages[] = comments - .filter((c) => c.body) + .filter((c) => c.body && !c.isMinimized) .map((c) => ({ type: "issue_comment" as const, id: c.databaseId, @@ -154,7 +154,7 @@ export async function fetchGitHubData({ const reviewComments: CommentWithImages[] = reviewData?.nodes ?.flatMap((r) => r.comments?.nodes ?? []) - .filter((c) => c.body) + .filter((c) => c.body && !c.isMinimized) .map((c) => ({ type: "review_comment" as const, id: c.databaseId, diff --git a/src/github/data/formatter.ts b/src/github/data/formatter.ts index 3ecc579..63c4883 100644 --- a/src/github/data/formatter.ts +++ b/src/github/data/formatter.ts @@ -50,6 +50,7 @@ export function formatComments( imageUrlMap?: Map, ): string { return comments + .filter((comment) => !comment.isMinimized) .map((comment) => { let body = comment.body; @@ -96,6 +97,7 @@ export function formatReviewComments( review.comments.nodes.length > 0 ) { const comments = review.comments.nodes + .filter((comment) => !comment.isMinimized) .map((comment) => { let body = comment.body; @@ -110,7 +112,9 @@ export function formatReviewComments( return ` [Comment on ${comment.path}:${comment.line || "?"}]: ${body}`; }) .join("\n"); - reviewOutput += `\n${comments}`; + if (comments) { + reviewOutput += `\n${comments}`; + } } return reviewOutput; diff --git a/src/github/types.ts b/src/github/types.ts index c46c29f..f31d841 100644 --- a/src/github/types.ts +++ b/src/github/types.ts @@ -10,6 +10,7 @@ export type GitHubComment = { body: string; author: GitHubAuthor; createdAt: string; + isMinimized?: boolean; }; export type GitHubReviewComment = GitHubComment & { diff --git a/test/data-formatter.test.ts b/test/data-formatter.test.ts index 3181032..7ac455c 100644 --- a/test/data-formatter.test.ts +++ b/test/data-formatter.test.ts @@ -252,6 +252,63 @@ describe("formatComments", () => { `[user1 at 2023-01-01T00:00:00Z]: Image: ![](https://github.com/user-attachments/assets/test.png)`, ); }); + + test("filters out minimized comments", () => { + const comments: GitHubComment[] = [ + { + id: "1", + databaseId: "100001", + body: "Normal comment", + author: { login: "user1" }, + createdAt: "2023-01-01T00:00:00Z", + isMinimized: false, + }, + { + id: "2", + databaseId: "100002", + body: "Minimized comment", + author: { login: "user2" }, + createdAt: "2023-01-02T00:00:00Z", + isMinimized: true, + }, + { + id: "3", + databaseId: "100003", + body: "Another normal comment", + author: { login: "user3" }, + createdAt: "2023-01-03T00:00:00Z", + }, + ]; + + const result = formatComments(comments); + expect(result).toBe( + `[user1 at 2023-01-01T00:00:00Z]: Normal comment\n\n[user3 at 2023-01-03T00:00:00Z]: Another normal comment`, + ); + }); + + test("returns empty string when all comments are minimized", () => { + const comments: GitHubComment[] = [ + { + id: "1", + databaseId: "100001", + body: "Minimized comment 1", + author: { login: "user1" }, + createdAt: "2023-01-01T00:00:00Z", + isMinimized: true, + }, + { + id: "2", + databaseId: "100002", + body: "Minimized comment 2", + author: { login: "user2" }, + createdAt: "2023-01-02T00:00:00Z", + isMinimized: true, + }, + ]; + + const result = formatComments(comments); + expect(result).toBe(""); + }); }); describe("formatReviewComments", () => { @@ -517,6 +574,159 @@ describe("formatReviewComments", () => { `[Review by reviewer1 at 2023-01-01T00:00:00Z]: APPROVED\nReview body\n [Comment on src/index.ts:42]: Image: ![](https://github.com/user-attachments/assets/test.png)`, ); }); + + test("filters out minimized review comments", () => { + const reviewData = { + nodes: [ + { + id: "review1", + databaseId: "300001", + author: { login: "reviewer1" }, + body: "Review with mixed comments", + state: "APPROVED", + submittedAt: "2023-01-01T00:00:00Z", + comments: { + nodes: [ + { + id: "comment1", + databaseId: "200001", + body: "Normal review comment", + author: { login: "reviewer1" }, + createdAt: "2023-01-01T00:00:00Z", + path: "src/index.ts", + line: 42, + isMinimized: false, + }, + { + id: "comment2", + databaseId: "200002", + body: "Minimized review comment", + author: { login: "reviewer1" }, + createdAt: "2023-01-01T00:00:00Z", + path: "src/utils.ts", + line: 15, + isMinimized: true, + }, + { + id: "comment3", + databaseId: "200003", + body: "Another normal comment", + author: { login: "reviewer1" }, + createdAt: "2023-01-01T00:00:00Z", + path: "src/main.ts", + line: 10, + }, + ], + }, + }, + ], + }; + + const result = formatReviewComments(reviewData); + expect(result).toBe( + `[Review by reviewer1 at 2023-01-01T00:00:00Z]: APPROVED\nReview with mixed comments\n [Comment on src/index.ts:42]: Normal review comment\n [Comment on src/main.ts:10]: Another normal comment`, + ); + }); + + test("returns review with only body when all review comments are minimized", () => { + const reviewData = { + nodes: [ + { + id: "review1", + databaseId: "300001", + author: { login: "reviewer1" }, + body: "Review body only", + state: "APPROVED", + submittedAt: "2023-01-01T00:00:00Z", + comments: { + nodes: [ + { + id: "comment1", + databaseId: "200001", + body: "Minimized comment 1", + author: { login: "reviewer1" }, + createdAt: "2023-01-01T00:00:00Z", + path: "src/index.ts", + line: 42, + isMinimized: true, + }, + { + id: "comment2", + databaseId: "200002", + body: "Minimized comment 2", + author: { login: "reviewer1" }, + createdAt: "2023-01-01T00:00:00Z", + path: "src/utils.ts", + line: 15, + isMinimized: true, + }, + ], + }, + }, + ], + }; + + const result = formatReviewComments(reviewData); + expect(result).toBe( + `[Review by reviewer1 at 2023-01-01T00:00:00Z]: APPROVED\nReview body only`, + ); + }); + + test("handles multiple reviews with mixed minimized comments", () => { + const reviewData = { + nodes: [ + { + id: "review1", + databaseId: "300001", + author: { login: "reviewer1" }, + body: "First review", + state: "APPROVED", + submittedAt: "2023-01-01T00:00:00Z", + comments: { + nodes: [ + { + id: "comment1", + databaseId: "200001", + body: "Good comment", + author: { login: "reviewer1" }, + createdAt: "2023-01-01T00:00:00Z", + path: "src/index.ts", + line: 42, + isMinimized: false, + }, + ], + }, + }, + { + id: "review2", + databaseId: "300002", + author: { login: "reviewer2" }, + body: "Second review", + state: "COMMENTED", + submittedAt: "2023-01-02T00:00:00Z", + comments: { + nodes: [ + { + id: "comment2", + databaseId: "200002", + body: "Spam comment", + author: { login: "reviewer2" }, + createdAt: "2023-01-02T00:00:00Z", + path: "src/utils.ts", + line: 15, + isMinimized: true, + }, + ], + }, + }, + ], + }; + + const result = formatReviewComments(reviewData); + expect(result).toBe( + `[Review by reviewer1 at 2023-01-01T00:00:00Z]: APPROVED\nFirst review\n [Comment on src/index.ts:42]: Good comment\n\n[Review by reviewer2 at 2023-01-02T00:00:00Z]: COMMENTED\nSecond review`, + ); + }); }); describe("formatChangedFiles", () => {