diff --git a/src/agents/definitions/respond-to-review.yaml b/src/agents/definitions/respond-to-review.yaml index 6fea74e9..061187f8 100644 --- a/src/agents/definitions/respond-to-review.yaml +++ b/src/agents/definitions/respond-to-review.yaml @@ -27,7 +27,7 @@ capabilities: triggers: - event: scm:pr-review-submitted label: PR Review Submitted - description: Trigger when a review with changes requested is submitted + description: Trigger when a review with changes requested or comments is submitted defaultEnabled: true providers: [github] contextPipeline: [prContext, prConversation, directoryListing, contextFiles, squint] diff --git a/src/triggers/github/pr-review-submitted.ts b/src/triggers/github/pr-review-submitted.ts index e7b3b939..ed789fc9 100644 --- a/src/triggers/github/pr-review-submitted.ts +++ b/src/triggers/github/pr-review-submitted.ts @@ -16,8 +16,8 @@ export class PRReviewSubmittedTrigger implements TriggerHandler { // Only trigger on submitted reviews, not edits or dismissals if (ctx.payload.action !== 'submitted') return false; - // Only respond to changes_requested reviews — not approved or commented - if (ctx.payload.review.state !== 'changes_requested') return false; + // Respond to changes_requested and commented reviews — not approved + if (ctx.payload.review.state === 'approved') return false; return true; } @@ -51,7 +51,7 @@ export class PRReviewSubmittedTrigger implements TriggerHandler { const prNumber = reviewPayload.pull_request.number; const reviewAuthor = reviewPayload.review.user.login; - // Only respond to changes_requested from the reviewer persona + // Only respond to reviews from the reviewer persona if (!ctx.personaIdentities) { logger.warn('No persona identities available, skipping review trigger', { prNumber }); return null; diff --git a/tests/unit/triggers/pr-review-submitted.test.ts b/tests/unit/triggers/pr-review-submitted.test.ts index 197af803..7bdf95e5 100644 --- a/tests/unit/triggers/pr-review-submitted.test.ts +++ b/tests/unit/triggers/pr-review-submitted.test.ts @@ -61,7 +61,7 @@ describe('PRReviewSubmittedTrigger', () => { expect(trigger.matches(ctx)).toBe(true); }); - it('does not match submitted review with commented state', () => { + it('matches submitted review with commented state', () => { const ctx: TriggerContext = { project: mockProject, source: 'github', @@ -76,6 +76,25 @@ describe('PRReviewSubmittedTrigger', () => { }), }; + expect(trigger.matches(ctx)).toBe(true); + }); + + it('does not match dismissed reviews (action is dismissed, not submitted)', () => { + const ctx: TriggerContext = { + project: mockProject, + source: 'github', + payload: makeReviewPayload({ + action: 'dismissed', + review: { + id: 100, + state: 'dismissed', + body: 'Dismissed', + html_url: 'https://github.com/...', + user: { login: 'cascade-reviewer' }, + }, + }), + }; + expect(trigger.matches(ctx)).toBe(false); }); @@ -272,5 +291,60 @@ describe('PRReviewSubmittedTrigger', () => { expect(result?.agentInput.triggerCommentBody).toBe('Review: changes_requested'); }); + + it('returns respond-to-review result when reviewer persona posts commented review', async () => { + const ctx: TriggerContext = { + project: mockProject, + source: 'github', + payload: makeReviewPayload({ + review: { + id: 200, + state: 'commented', + body: 'Left some inline comments', + html_url: 'https://github.com/owner/repo/pull/42#pullrequestreview-200', + user: { login: 'cascade-reviewer' }, + }, + }), + personaIdentities: mockPersonaIdentities, + }; + + const result = await trigger.handle(ctx); + + expect(result).toEqual({ + agentType: 'respond-to-review', + agentInput: { + prNumber: 42, + prBranch: 'feature/test', + repoFullName: 'owner/repo', + triggerCommentId: 200, + triggerCommentBody: 'Left some inline comments', + triggerCommentPath: '', + triggerCommentUrl: 'https://github.com/owner/repo/pull/42#pullrequestreview-200', + }, + prNumber: 42, + workItemId: 'abc123', + }); + }); + + it('uses Review: commented fallback when commented review has null body', async () => { + const ctx: TriggerContext = { + project: mockProject, + source: 'github', + payload: makeReviewPayload({ + review: { + id: 200, + state: 'commented', + body: null, + html_url: 'https://github.com/owner/repo/pull/42#pullrequestreview-200', + user: { login: 'cascade-reviewer' }, + }, + }), + personaIdentities: mockPersonaIdentities, + }; + + const result = await trigger.handle(ctx); + + expect(result?.agentInput.triggerCommentBody).toBe('Review: commented'); + }); }); });