fix(github): complete PR reactions for CodeRabbit reviews (#13456)

* feat(github): add PR comment reaction controls

* feat(github): add full PR comment reaction picker

* fix(github): cover all reactable PR comment paths

* fix(github): reconcile comment reactions with main

* fix(github): preserve focus on failed reaction removal
This commit is contained in:
Neil
2026-08-09 23:14:17 -07:00
committed by GitHub
parent d6362deb04
commit 016df33f00
7 changed files with 237 additions and 34 deletions
+54
View File
@@ -4044,6 +4044,60 @@ describe('GitHub GraphQL rate-limit guard', () => {
expect(noteRateLimitSpendMock).not.toHaveBeenCalledWith('graphql')
})
it('maps review summary reaction subjects from GraphQL', async () => {
getOwnerRepoMock.mockResolvedValueOnce({ owner: 'acme', repo: 'widgets' })
ghExecFileAsyncMock
.mockResolvedValueOnce({
stdout: JSON.stringify({
data: {
repository: {
pullRequest: {
reviewThreads: { nodes: [] },
comments: { nodes: [] },
reviews: {
nodes: [
{
id: 'PRR_44',
databaseId: 44,
author: {
__typename: 'Bot',
login: 'coderabbitai',
avatarUrl: 'https://avatar'
},
body: 'Automated review summary',
createdAt: '2026-04-01T00:00:00Z',
url: 'https://github.com/acme/widgets/pull/7#pullrequestreview-44',
reactionGroups: [
{
content: 'ROCKET',
viewerHasReacted: true,
reactors: { totalCount: 2 }
}
]
}
]
}
}
}
}
})
})
.mockResolvedValueOnce({ stdout: '[]' })
.mockResolvedValueOnce({ stdout: '[]' })
await expect(getPRComments('/repo-root', 7)).resolves.toEqual([
expect.objectContaining({
id: 44,
reactionSubjectId: 'PRR_44',
isBot: true,
reactions: [{ content: 'rocket', count: 2, viewerHasReacted: true }]
})
])
expect(ghExecFileAsyncMock.mock.calls[0]?.[0]).toEqual(
expect.arrayContaining([expect.stringContaining('reviews(first: 100)')])
)
})
it('uses explicit PR repo for comments when a fork PR is discovered', async () => {
rateLimitGuardMock.mockImplementation(((bucket: string) =>
bucket === 'graphql'