diff --git a/apps/webapp/tests/lib/db.test.ts b/apps/webapp/tests/lib/db.test.ts index 7ff4f84..42b94e9 100644 --- a/apps/webapp/tests/lib/db.test.ts +++ b/apps/webapp/tests/lib/db.test.ts @@ -6,7 +6,7 @@ import { mockConnection, mockSection, mockPull } from "@repo/testing"; test("should save a connection", async () => { const connection = mockConnection({ viewer: { - user: { name: "pvcnt", avatarUrl: "" }, + user: { name: "pvcnt", avatarUrl: "", bot: false }, teams: [{ name: "test" }], }, orgs: ["apache", "kubernetes"], diff --git a/apps/webapp/tests/worker/instance.test.ts b/apps/webapp/tests/worker/instance.test.ts index 5342345..cfa1ae2 100644 --- a/apps/webapp/tests/worker/instance.test.ts +++ b/apps/webapp/tests/worker/instance.test.ts @@ -24,11 +24,11 @@ describe("sync viewers", () => { let connection = await db.connections.get("1"); expect(connection?.viewer).toBeDefined(); - expect(connection?.viewer?.user).toEqual({ name: "test[1]", avatarUrl: "" }); + expect(connection?.viewer?.user).toEqual({ name: "test[1]", avatarUrl: "", bot: false }); connection = await db.connections.get("2"); expect(connection?.viewer).toBeDefined(); - expect(connection?.viewer?.user).toEqual({ name: "test[2]", avatarUrl: "" }); + expect(connection?.viewer?.user).toEqual({ name: "test[2]", avatarUrl: "", bot: false }); activity = await db.activities.get("syncViewers"); expect(activity?.running).toBeFalsy(); diff --git a/packages/github/src/attention.ts b/packages/github/src/attention.ts index 4c26359..f8d9c32 100644 --- a/packages/github/src/attention.ts +++ b/packages/github/src/attention.ts @@ -29,9 +29,14 @@ export function isInAttentionSet(connection: Connection, pull: PullProps): Atten continue; } const lastViewerCommentPos = discussion.comments.findLastIndex(c => c.author?.name === viewerName); - const commentsAfterLastViewerComment = (lastViewerCommentPos === -1) + let commentsAfterLastViewerComment = (lastViewerCommentPos === -1) ? discussion.comments : discussion.comments.slice(lastViewerCommentPos + 1); + if (discussion.file === undefined) { + // Ignore bot comments in top-level discussions, since this particular one tends + // to be catch-all, and not really a threaded discussion. + commentsAfterLastViewerComment = commentsAfterLastViewerComment.filter(c => c.author === undefined || !c.author.bot); + } if (lastViewerCommentPos > -1 && commentsAfterLastViewerComment.length > 0) { // The author and reviewers are always notified when somebody replied to them. commentsAfterLastViewerComment diff --git a/packages/github/src/client.ts b/packages/github/src/client.ts index 1540756..49cb129 100644 --- a/packages/github/src/client.ts +++ b/packages/github/src/client.ts @@ -69,6 +69,7 @@ type GHReview = { } type GHUser = { + __typename: "Bot"|"EnterpriseUserAccount"|"Mannequin"|"Organization"|"User" login: string avatarUrl: string } @@ -93,6 +94,7 @@ export class DefaultGitHubClient implements GitHubClient { const user: User = { name: userResponse.data.login, avatarUrl: userResponse.data.avatar_url, + bot: false, }; const teamsResponse = await octokit.paginate("GET /user/teams", { per_page: 100 }); const teams: Team[] = teamsResponse.map(obj => ({ name: `${obj.organization.login}/${obj.slug}` })); @@ -152,8 +154,9 @@ export class DefaultGitHubClient implements GitHubClient { additions deletions author { + __typename login - avatarUrl + avatarUrl } statusCheckRollup { state @@ -163,6 +166,7 @@ export class DefaultGitHubClient implements GitHubClient { nodes { id author { + __typename login avatarUrl } @@ -198,6 +202,7 @@ export class DefaultGitHubClient implements GitHubClient { nodes { id author { + __typename login avatarUrl } @@ -217,6 +222,7 @@ export class DefaultGitHubClient implements GitHubClient { nodes { id author { + __typename login avatarUrl } @@ -330,7 +336,11 @@ export class DefaultGitHubClient implements GitHubClient { } private makeUser(user: GHUser): User { - return { name: user.login, avatarUrl: user.avatarUrl }; + return { + name: user.login, + avatarUrl: user.avatarUrl, + bot: user.__typename === "Bot", + }; } private makeTeam(team: GHTeam): Team { @@ -361,7 +371,7 @@ export class TestGitHubClient implements GitHubClient { getViewer(connection: Connection): Promise { return Promise.resolve({ - user: { name: `test[${connection.id}]`, avatarUrl: "" }, + user: { name: `test[${connection.id}]`, avatarUrl: "", bot: false }, teams: [ { name: `test[${connection.id}]` } ], }); } diff --git a/packages/github/tests/__recordings__/should-error-when-pull-does-not-exist_3266903050/recording.har b/packages/github/tests/__recordings__/should-error-when-pull-does-not-exist_3266903050/recording.har index dd068f0..54a1ec7 100644 --- a/packages/github/tests/__recordings__/should-error-when-pull-does-not-exist_3266903050/recording.har +++ b/packages/github/tests/__recordings__/should-error-when-pull-does-not-exist_3266903050/recording.har @@ -8,11 +8,11 @@ }, "entries": [ { - "_id": "cc0646ae14889a5d068e12034aa668ad", + "_id": "3227fef667e90b40698466a986053b05", "_order": 0, "cache": {}, "request": { - "bodySize": 2278, + "bodySize": 2372, "cookies": [], "headers": [ { @@ -32,23 +32,23 @@ "value": "octokit.js/0.0.0-development octokit-core.js/6.1.2 Node.js/22" } ], - "headersSize": 273, + "headersSize": 242, "httpVersion": "HTTP/1.1", "method": "POST", "postData": { "mimeType": "application/json; charset=utf-8", "params": [], - "text": "{\"query\":\"query pull($id: ID!) {\\n node(id: $id) {\\n ... on PullRequest {\\n number\\n title\\n repository {\\n nameWithOwner\\n }\\n createdAt\\n updatedAt\\n state\\n url\\n isDraft\\n closed\\n merged\\n reviewDecision\\n additions\\n deletions\\n author {\\n login\\n avatarUrl \\n }\\n statusCheckRollup {\\n state\\n }\\n comments(first: 100) {\\n totalCount\\n nodes {\\n id\\n author {\\n login\\n avatarUrl\\n }\\n body\\n createdAt\\n }\\n }\\n reviewRequests(first: 100) {\\n totalCount\\n nodes {\\n requestedReviewer {\\n __typename\\n ... on Bot {\\n login\\n avatarUrl\\n }\\n ... on Mannequin {\\n login\\n avatarUrl\\n }\\n ... on User {\\n login\\n avatarUrl\\n }\\n ... on Team {\\n combinedSlug\\n }\\n }\\n }\\n }\\n reviews(first: 100) {\\n totalCount\\n nodes {\\n id\\n author {\\n login\\n avatarUrl\\n }\\n authorCanPushToRepository\\n state\\n body\\n createdAt\\n }\\n }\\n reviewThreads(first: 100) {\\n totalCount\\n nodes {\\n isResolved\\n path\\n comments(first: 100) {\\n totalCount\\n nodes {\\n id\\n author {\\n login\\n avatarUrl\\n }\\n createdAt\\n body\\n }\\n }\\n }\\n }\\n }\\n }\\n rateLimit {\\n cost\\n }\\n }\",\"variables\":{\"id\":\"PR_none\"}}" + "text": "{\"query\":\"query pull($id: ID!) {\\n node(id: $id) {\\n ... on PullRequest {\\n number\\n title\\n repository {\\n nameWithOwner\\n }\\n createdAt\\n updatedAt\\n state\\n url\\n isDraft\\n closed\\n merged\\n reviewDecision\\n additions\\n deletions\\n author {\\n __typename\\n login\\n avatarUrl\\n }\\n statusCheckRollup {\\n state\\n }\\n comments(first: 100) {\\n totalCount\\n nodes {\\n id\\n author {\\n __typename\\n login\\n avatarUrl\\n }\\n body\\n createdAt\\n }\\n }\\n reviewRequests(first: 100) {\\n totalCount\\n nodes {\\n requestedReviewer {\\n __typename\\n ... on Bot {\\n login\\n avatarUrl\\n }\\n ... on Mannequin {\\n login\\n avatarUrl\\n }\\n ... on User {\\n login\\n avatarUrl\\n }\\n ... on Team {\\n combinedSlug\\n }\\n }\\n }\\n }\\n reviews(first: 100) {\\n totalCount\\n nodes {\\n id\\n author {\\n __typename\\n login\\n avatarUrl\\n }\\n authorCanPushToRepository\\n state\\n body\\n createdAt\\n }\\n }\\n reviewThreads(first: 100) {\\n totalCount\\n nodes {\\n isResolved\\n path\\n comments(first: 100) {\\n totalCount\\n nodes {\\n id\\n author {\\n __typename\\n login\\n avatarUrl\\n }\\n createdAt\\n body\\n }\\n }\\n }\\n }\\n }\\n }\\n rateLimit {\\n cost\\n }\\n }\",\"variables\":{\"id\":\"PR_none\"}}" }, "queryString": [], "url": "https://api.github.com/graphql" }, "response": { - "bodySize": 201, + "bodySize": 98, "content": { "mimeType": "application/json; charset=utf-8", - "size": 201, - "text": "{\"data\":{\"node\":null,\"rateLimit\":{\"cost\":1}},\"errors\":[{\"type\":\"NOT_FOUND\",\"path\":[\"node\"],\"locations\":[{\"line\":2,\"column\":7}],\"message\":\"Could not resolve to a node with the global id of 'PR_none'\"}]}" + "size": 98, + "text": "{\"message\":\"Bad credentials\",\"documentation_url\":\"https://docs.github.com/graphql\",\"status\":\"401\"}" }, "cookies": [], "headers": [ @@ -61,8 +61,8 @@ "value": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset" }, { - "name": "content-encoding", - "value": "gzip" + "name": "content-length", + "value": "98" }, { "name": "content-security-policy", @@ -74,7 +74,7 @@ }, { "name": "date", - "value": "Tue, 27 Aug 2024 14:12:26 GMT" + "value": "Tue, 27 Aug 2024 14:48:35 GMT" }, { "name": "referrer-policy", @@ -88,18 +88,10 @@ "name": "strict-transport-security", "value": "max-age=31536000; includeSubdomains; preload" }, - { - "name": "transfer-encoding", - "value": "chunked" - }, { "name": "vary", "value": "Accept-Encoding, Accept, X-Requested-With" }, - { - "name": "x-accepted-oauth-scopes", - "value": "repo" - }, { "name": "x-content-type-options", "value": "nosniff" @@ -114,23 +106,19 @@ }, { "name": "x-github-request-id", - "value": "C5FC:2D68BC:38B277D:395A312:66CDDEC9" - }, - { - "name": "x-oauth-scopes", - "value": "read:org, repo, user" + "value": "C805:B6DE5:3880FCB:392D728:66CDE743" }, { "name": "x-ratelimit-limit", - "value": "5000" + "value": "0" }, { "name": "x-ratelimit-remaining", - "value": "4874" + "value": "0" }, { "name": "x-ratelimit-reset", - "value": "1724768719" + "value": "1724773715" }, { "name": "x-ratelimit-resource", @@ -138,21 +126,21 @@ }, { "name": "x-ratelimit-used", - "value": "126" + "value": "0" }, { "name": "x-xss-protection", "value": "0" } ], - "headersSize": 1138, + "headersSize": 1028, "httpVersion": "HTTP/1.1", "redirectURL": "", - "status": 200, - "statusText": "OK" + "status": 401, + "statusText": "Unauthorized" }, - "startedDateTime": "2024-08-27T14:12:25.809Z", - "time": 201, + "startedDateTime": "2024-08-27T14:48:35.690Z", + "time": 147, "timings": { "blocked": -1, "connect": -1, @@ -160,7 +148,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 201 + "wait": 147 } } ], diff --git a/packages/github/tests/__recordings__/should-get-pull_2195211117/recording.har b/packages/github/tests/__recordings__/should-get-pull_2195211117/recording.har index b4430eb..f844721 100644 --- a/packages/github/tests/__recordings__/should-get-pull_2195211117/recording.har +++ b/packages/github/tests/__recordings__/should-get-pull_2195211117/recording.har @@ -8,11 +8,11 @@ }, "entries": [ { - "_id": "73055b5195ca9190b7ad5f4d1e351e32", + "_id": "c7e34c2748dbf4298449127460b015e7", "_order": 0, "cache": {}, "request": { - "bodySize": 2290, + "bodySize": 2384, "cookies": [], "headers": [ { @@ -38,17 +38,17 @@ "postData": { "mimeType": "application/json; charset=utf-8", "params": [], - "text": "{\"query\":\"query pull($id: ID!) {\\n node(id: $id) {\\n ... on PullRequest {\\n number\\n title\\n repository {\\n nameWithOwner\\n }\\n createdAt\\n updatedAt\\n state\\n url\\n isDraft\\n closed\\n merged\\n reviewDecision\\n additions\\n deletions\\n author {\\n login\\n avatarUrl \\n }\\n statusCheckRollup {\\n state\\n }\\n comments(first: 100) {\\n totalCount\\n nodes {\\n id\\n author {\\n login\\n avatarUrl\\n }\\n body\\n createdAt\\n }\\n }\\n reviewRequests(first: 100) {\\n totalCount\\n nodes {\\n requestedReviewer {\\n __typename\\n ... on Bot {\\n login\\n avatarUrl\\n }\\n ... on Mannequin {\\n login\\n avatarUrl\\n }\\n ... on User {\\n login\\n avatarUrl\\n }\\n ... on Team {\\n combinedSlug\\n }\\n }\\n }\\n }\\n reviews(first: 100) {\\n totalCount\\n nodes {\\n id\\n author {\\n login\\n avatarUrl\\n }\\n authorCanPushToRepository\\n state\\n body\\n createdAt\\n }\\n }\\n reviewThreads(first: 100) {\\n totalCount\\n nodes {\\n isResolved\\n path\\n comments(first: 100) {\\n totalCount\\n nodes {\\n id\\n author {\\n login\\n avatarUrl\\n }\\n createdAt\\n body\\n }\\n }\\n }\\n }\\n }\\n }\\n rateLimit {\\n cost\\n }\\n }\",\"variables\":{\"id\":\"PR_kwDOFFj3yM53-IjI\"}}" + "text": "{\"query\":\"query pull($id: ID!) {\\n node(id: $id) {\\n ... on PullRequest {\\n number\\n title\\n repository {\\n nameWithOwner\\n }\\n createdAt\\n updatedAt\\n state\\n url\\n isDraft\\n closed\\n merged\\n reviewDecision\\n additions\\n deletions\\n author {\\n __typename\\n login\\n avatarUrl\\n }\\n statusCheckRollup {\\n state\\n }\\n comments(first: 100) {\\n totalCount\\n nodes {\\n id\\n author {\\n __typename\\n login\\n avatarUrl\\n }\\n body\\n createdAt\\n }\\n }\\n reviewRequests(first: 100) {\\n totalCount\\n nodes {\\n requestedReviewer {\\n __typename\\n ... on Bot {\\n login\\n avatarUrl\\n }\\n ... on Mannequin {\\n login\\n avatarUrl\\n }\\n ... on User {\\n login\\n avatarUrl\\n }\\n ... on Team {\\n combinedSlug\\n }\\n }\\n }\\n }\\n reviews(first: 100) {\\n totalCount\\n nodes {\\n id\\n author {\\n __typename\\n login\\n avatarUrl\\n }\\n authorCanPushToRepository\\n state\\n body\\n createdAt\\n }\\n }\\n reviewThreads(first: 100) {\\n totalCount\\n nodes {\\n isResolved\\n path\\n comments(first: 100) {\\n totalCount\\n nodes {\\n id\\n author {\\n __typename\\n login\\n avatarUrl\\n }\\n createdAt\\n body\\n }\\n }\\n }\\n }\\n }\\n }\\n rateLimit {\\n cost\\n }\\n }\",\"variables\":{\"id\":\"PR_kwDOFFj3yM53-IjI\"}}" }, "queryString": [], "url": "https://api.github.com/graphql" }, "response": { - "bodySize": 1972, + "bodySize": 2032, "content": { "mimeType": "application/json; charset=utf-8", - "size": 1972, - "text": "{\"data\":{\"node\":{\"number\":2632,\"title\":\"remove deprecated (DocValues,Norms)FieldExistsQuery use\",\"repository\":{\"nameWithOwner\":\"apache/solr\"},\"createdAt\":\"2024-08-09T17:18:47Z\",\"updatedAt\":\"2024-08-23T19:12:59Z\",\"state\":\"OPEN\",\"url\":\"https://github.com/apache/solr/pull/2632\",\"isDraft\":false,\"closed\":false,\"merged\":false,\"reviewDecision\":\"CHANGES_REQUESTED\",\"additions\":25,\"deletions\":29,\"author\":{\"login\":\"cpoerschke\",\"avatarUrl\":\"https://avatars.githubusercontent.com/u/6458642?u=8ccfc26ce7209695b2fcca628a59baca42cff00f&v=4\"},\"statusCheckRollup\":{\"state\":\"SUCCESS\"},\"comments\":{\"totalCount\":0,\"nodes\":[]},\"reviewRequests\":{\"totalCount\":1,\"nodes\":[{\"requestedReviewer\":{\"__typename\":\"User\",\"login\":\"HoustonPutman\",\"avatarUrl\":\"https://avatars.githubusercontent.com/u/3376422?u=323311c61ac2b04e5deac436faaa4f4309fe7beb&v=4\"}}]},\"reviews\":{\"totalCount\":1,\"nodes\":[{\"id\":\"PRR_kwDOFFj3yM6GlVVP\",\"author\":{\"login\":\"dsmiley\",\"avatarUrl\":\"https://avatars.githubusercontent.com/u/377295?u=85f6ade89e5b34f001267475e806da2a52b2755a&v=4\"},\"authorCanPushToRepository\":true,\"state\":\"CHANGES_REQUESTED\",\"body\":\"As there is now FieldExistsQuery covering a range of cases (not just even docValues & norms), this probably obsoletes complexity inside FieldType.getExistenceQuery. Can we just call that and remove getSpecializedExistenceQuery as needless in lieu of subtypes overriding getExistenceQuery?\\r\\n\\r\\nCC @HoustonPutman as you worked on this method\",\"createdAt\":\"2024-08-23T19:07:24Z\"}]},\"reviewThreads\":{\"totalCount\":1,\"nodes\":[{\"isResolved\":false,\"path\":\"solr/core/src/java/org/apache/solr/search/facet/MissingAgg.java\",\"comments\":{\"totalCount\":1,\"nodes\":[{\"id\":\"PRRC_kwDOFFj3yM5nFK8J\",\"author\":{\"login\":\"dsmiley\",\"avatarUrl\":\"https://avatars.githubusercontent.com/u/377295?u=85f6ade89e5b34f001267475e806da2a52b2755a&v=4\"},\"createdAt\":\"2024-08-23T19:07:24Z\",\"body\":\"I suspect this code pre-dated FieldType.getExistenceQuery -- just call that.\"}]}}]}},\"rateLimit\":{\"cost\":1}}}" + "size": 2032, + "text": "{\"data\":{\"node\":{\"number\":2632,\"title\":\"remove deprecated (DocValues,Norms)FieldExistsQuery use\",\"repository\":{\"nameWithOwner\":\"apache/solr\"},\"createdAt\":\"2024-08-09T17:18:47Z\",\"updatedAt\":\"2024-08-23T19:12:59Z\",\"state\":\"OPEN\",\"url\":\"https://github.com/apache/solr/pull/2632\",\"isDraft\":false,\"closed\":false,\"merged\":false,\"reviewDecision\":\"CHANGES_REQUESTED\",\"additions\":25,\"deletions\":29,\"author\":{\"__typename\":\"User\",\"login\":\"cpoerschke\",\"avatarUrl\":\"https://avatars.githubusercontent.com/u/6458642?u=8ccfc26ce7209695b2fcca628a59baca42cff00f&v=4\"},\"statusCheckRollup\":{\"state\":\"SUCCESS\"},\"comments\":{\"totalCount\":0,\"nodes\":[]},\"reviewRequests\":{\"totalCount\":1,\"nodes\":[{\"requestedReviewer\":{\"__typename\":\"User\",\"login\":\"HoustonPutman\",\"avatarUrl\":\"https://avatars.githubusercontent.com/u/3376422?u=323311c61ac2b04e5deac436faaa4f4309fe7beb&v=4\"}}]},\"reviews\":{\"totalCount\":1,\"nodes\":[{\"id\":\"PRR_kwDOFFj3yM6GlVVP\",\"author\":{\"__typename\":\"User\",\"login\":\"dsmiley\",\"avatarUrl\":\"https://avatars.githubusercontent.com/u/377295?u=85f6ade89e5b34f001267475e806da2a52b2755a&v=4\"},\"authorCanPushToRepository\":true,\"state\":\"CHANGES_REQUESTED\",\"body\":\"As there is now FieldExistsQuery covering a range of cases (not just even docValues & norms), this probably obsoletes complexity inside FieldType.getExistenceQuery. Can we just call that and remove getSpecializedExistenceQuery as needless in lieu of subtypes overriding getExistenceQuery?\\r\\n\\r\\nCC @HoustonPutman as you worked on this method\",\"createdAt\":\"2024-08-23T19:07:24Z\"}]},\"reviewThreads\":{\"totalCount\":1,\"nodes\":[{\"isResolved\":false,\"path\":\"solr/core/src/java/org/apache/solr/search/facet/MissingAgg.java\",\"comments\":{\"totalCount\":1,\"nodes\":[{\"id\":\"PRRC_kwDOFFj3yM5nFK8J\",\"author\":{\"__typename\":\"User\",\"login\":\"dsmiley\",\"avatarUrl\":\"https://avatars.githubusercontent.com/u/377295?u=85f6ade89e5b34f001267475e806da2a52b2755a&v=4\"},\"createdAt\":\"2024-08-23T19:07:24Z\",\"body\":\"I suspect this code pre-dated FieldType.getExistenceQuery -- just call that.\"}]}}]}},\"rateLimit\":{\"cost\":1}}}" }, "cookies": [], "headers": [ @@ -74,7 +74,7 @@ }, { "name": "date", - "value": "Tue, 27 Aug 2024 14:12:25 GMT" + "value": "Tue, 27 Aug 2024 14:48:35 GMT" }, { "name": "referrer-policy", @@ -114,7 +114,7 @@ }, { "name": "x-github-request-id", - "value": "C5FC:2D68BC:38B2313:3959E78:66CDDEC8" + "value": "C805:B6DE5:3880BFF:392D33F:66CDE742" }, { "name": "x-oauth-scopes", @@ -126,11 +126,11 @@ }, { "name": "x-ratelimit-remaining", - "value": "4875" + "value": "4889" }, { "name": "x-ratelimit-reset", - "value": "1724768719" + "value": "1724772326" }, { "name": "x-ratelimit-resource", @@ -138,21 +138,21 @@ }, { "name": "x-ratelimit-used", - "value": "125" + "value": "111" }, { "name": "x-xss-protection", "value": "0" } ], - "headersSize": 1138, + "headersSize": 1137, "httpVersion": "HTTP/1.1", "redirectURL": "", "status": 200, "statusText": "OK" }, - "startedDateTime": "2024-08-27T14:12:24.809Z", - "time": 362, + "startedDateTime": "2024-08-27T14:48:34.692Z", + "time": 576, "timings": { "blocked": -1, "connect": -1, @@ -160,7 +160,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 362 + "wait": 576 } } ], diff --git a/packages/github/tests/attention.test.ts b/packages/github/tests/attention.test.ts index 79b1a33..598f091 100644 --- a/packages/github/tests/attention.test.ts +++ b/packages/github/tests/attention.test.ts @@ -3,10 +3,11 @@ import { isInAttentionSet } from "../src/attention.js"; import { mockConnection, mockPull } from "@repo/testing"; import { CheckState, PullState } from "@repo/model"; -const me = { name: "test", avatarUrl: "" }; -const user1 = { name: "test1", avatarUrl: "" }; -const user2 = { name: "test2", avatarUrl: "" }; -const user3 = { name: "test3", avatarUrl: "" }; +const me = { name: "test", avatarUrl: "", bot: false }; +const user1 = { name: "test1", avatarUrl: "", bot: false }; +const user2 = { name: "test2", avatarUrl: "", bot: false }; +const user3 = { name: "test3", avatarUrl: "", bot: false }; +const user4 = { name: "test4", avatarUrl: "", bot: true }; const connection = mockConnection({ viewer: { user: me, teams: []}}); test("should contain the author when pull is approved", () => { @@ -133,28 +134,25 @@ test("should not contain the author when a user replied in a resolved discussion expect(attention).toEqual({ set: false }); }) -test("should contain a reviewer when a user replied", () => { +test("should not contain the author when a bot replied to the top-level discussion", () => { const pull = mockPull({ state: PullState.Pending, - author: user1, - reviews: [ - { author: me, createdAt: new Date(0), lgtm: false }, - ], + author: me, discussions: [ { resolved: false, comments: [ { id: "1", author: me, createdAt: new Date(0), body: "" }, - { id: "2", author: user2, createdAt: new Date(1), body: "" }, + { id: "2", author: user4, createdAt: new Date(1), body: "" }, ], }, ], }); const attention = isInAttentionSet(connection, pull); - expect(attention).toEqual({ set: true, reason: "test2 left a comment" }); + expect(attention).toEqual({ set: false }); }) -test("should not contain a reviewer when a user replied in a resolved discussion", () => { +test("should contain a reviewer when a user replied", () => { const pull = mockPull({ state: PullState.Pending, author: user1, @@ -163,7 +161,7 @@ test("should not contain a reviewer when a user replied in a resolved discussion ], discussions: [ { - resolved: true, + resolved: false, comments: [ { id: "1", author: me, createdAt: new Date(0), body: "" }, { id: "2", author: user2, createdAt: new Date(1), body: "" }, @@ -172,7 +170,7 @@ test("should not contain a reviewer when a user replied in a resolved discussion ], }); const attention = isInAttentionSet(connection, pull); - expect(attention).toEqual({ set: false }); + expect(attention).toEqual({ set: true, reason: "test2 left a comment" }); }) test("should not contain the author when nobody replied", () => { @@ -227,22 +225,4 @@ test("should not contain the author when a non-reviewer left a comment", () => { }); const attention = isInAttentionSet(connection, pull); expect(attention).toEqual({ set: false }); -}) - -test("should not contain the author when a reviewer left a comment in a resolved discussion", () => { - const pull = mockPull({ - state: PullState.Pending, - author: me, - reviews: [{ author: user1, createdAt: new Date(0), lgtm: false }], - discussions: [ - { - resolved: true, - comments: [ - { id: "1", author: user1, createdAt: new Date(0), body: "" }, - ], - } - ] - }); - const attention = isInAttentionSet(connection, pull); - expect(attention).toEqual({ set: false }); }) \ No newline at end of file diff --git a/packages/github/tests/client.test.ts b/packages/github/tests/client.test.ts index 68732b7..36592a0 100644 --- a/packages/github/tests/client.test.ts +++ b/packages/github/tests/client.test.ts @@ -16,6 +16,7 @@ test("should return viewer", async () => { user: { name: "pvcnt", avatarUrl: "https://avatars.githubusercontent.com/u/944506?v=4", + bot: false, }, teams: [ { name: "privamov/developers" }, @@ -59,11 +60,13 @@ test("should get pull", async () => { author: { name: "cpoerschke", avatarUrl: "https://avatars.githubusercontent.com/u/6458642?u=8ccfc26ce7209695b2fcca628a59baca42cff00f&v=4", + bot: false, }, requestedReviewers: [ { name: "HoustonPutman", avatarUrl: "https://avatars.githubusercontent.com/u/3376422?u=323311c61ac2b04e5deac436faaa4f4309fe7beb&v=4", + bot: false, }, ], requestedTeams: [], @@ -72,6 +75,7 @@ test("should get pull", async () => { author: { name: "dsmiley", avatarUrl: "https://avatars.githubusercontent.com/u/377295?u=85f6ade89e5b34f001267475e806da2a52b2755a&v=4", + bot: false, }, createdAt: new Date("2024-08-23T19:07:24.000Z"), lgtm: false, @@ -86,6 +90,7 @@ test("should get pull", async () => { author: { name: "dsmiley", avatarUrl: "https://avatars.githubusercontent.com/u/377295?u=85f6ade89e5b34f001267475e806da2a52b2755a&v=4", + bot: false, }, body: "As there is now FieldExistsQuery covering a range of cases (not just even docValues & norms), this probably obsoletes complexity inside FieldType.getExistenceQuery. Can we just call that and remove getSpecializedExistenceQuery as needless in lieu of subtypes overriding getExistenceQuery?\r\n\r\nCC @HoustonPutman as you worked on this method", createdAt: new Date("2024-08-23T19:07:24.000Z"), @@ -98,8 +103,9 @@ test("should get pull", async () => { { id: "PRRC_kwDOFFj3yM5nFK8J", author: { - avatarUrl: "https://avatars.githubusercontent.com/u/377295?u=85f6ade89e5b34f001267475e806da2a52b2755a&v=4", name: "dsmiley", + avatarUrl: "https://avatars.githubusercontent.com/u/377295?u=85f6ade89e5b34f001267475e806da2a52b2755a&v=4", + bot: false, }, body: "I suspect this code pre-dated FieldType.getExistenceQuery -- just call that.", createdAt: new Date("2024-08-23T19:07:24.000Z"), diff --git a/packages/model/src/user.ts b/packages/model/src/user.ts index 8fc5e84..9efa4a2 100644 --- a/packages/model/src/user.ts +++ b/packages/model/src/user.ts @@ -1,6 +1,7 @@ export type User = { name: string avatarUrl: string + bot: boolean } export type Team = { diff --git a/packages/testing/src/index.ts b/packages/testing/src/index.ts index 28a2ef7..67583f1 100644 --- a/packages/testing/src/index.ts +++ b/packages/testing/src/index.ts @@ -18,7 +18,7 @@ export function mockPull(props?: Omit, "uid"|"url">): Pull { url: `https://${host}/${repo}/${number}`, additions: 0, deletions: 0, - author: { name: "pvcnt", avatarUrl: "" }, + author: { name: "pvcnt", avatarUrl: "", bot: false }, requestedReviewers: [], requestedTeams: [], reviews: [],