bitbucket-gemini-action 1.0.11 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +115 -0
- package/dist/cli.js +49 -32
- package/dist/entrypoints/execute.js +18 -14
- package/dist/entrypoints/prepare.js +40 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -52,6 +52,8 @@ pipelines:
|
|
|
52
52
|
- `@gemini what does this function do?`
|
|
53
53
|
- `@gemini check for security issues`
|
|
54
54
|
|
|
55
|
+
> **Note**: `@gemini` 멘션 기능을 사용하려면 [웹훅 설정](#webhook-setup-for-gemini-mentions)이 필요합니다.
|
|
56
|
+
|
|
55
57
|
## Configuration
|
|
56
58
|
|
|
57
59
|
### Environment Variables
|
|
@@ -235,6 +237,119 @@ Triggered by providing a `PROMPT` variable. Executes predefined tasks automatica
|
|
|
235
237
|
- npx bitbucket-gemini-action
|
|
236
238
|
```
|
|
237
239
|
|
|
240
|
+
### 자동 리뷰 + @gemini 멘션 동시 사용
|
|
241
|
+
|
|
242
|
+
두 기능을 동시에 사용하려면:
|
|
243
|
+
|
|
244
|
+
1. **자동 리뷰**: `PROMPT` 환경변수로 PR 생성/업데이트 시 자동 실행
|
|
245
|
+
2. **@gemini 멘션**: 웹훅으로 코멘트 이벤트 수신 시 실행
|
|
246
|
+
|
|
247
|
+
```yaml
|
|
248
|
+
image: node:20
|
|
249
|
+
|
|
250
|
+
pipelines:
|
|
251
|
+
pull-requests:
|
|
252
|
+
'**':
|
|
253
|
+
- step:
|
|
254
|
+
name: AI Code Review
|
|
255
|
+
script:
|
|
256
|
+
- export PROMPT="Review this PR"
|
|
257
|
+
- export ALLOW_BOTS=true
|
|
258
|
+
- export REVIEW_PRESETS="middle,nextjs,typescript"
|
|
259
|
+
- npx bitbucket-gemini-action@latest
|
|
260
|
+
|
|
261
|
+
custom:
|
|
262
|
+
gemini-comment:
|
|
263
|
+
- step:
|
|
264
|
+
name: Gemini Comment Handler
|
|
265
|
+
script:
|
|
266
|
+
- export ALLOW_BOTS=true
|
|
267
|
+
- npx bitbucket-gemini-action@latest
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
- `pull-requests` 파이프라인: PR 생성/업데이트 시 자동 리뷰
|
|
271
|
+
- `custom/gemini-comment` 파이프라인: 웹훅에서 코멘트 이벤트 수신 시 `@gemini` 멘션 처리
|
|
272
|
+
|
|
273
|
+
## Webhook Setup for @gemini Mentions
|
|
274
|
+
|
|
275
|
+
`@gemini` 멘션 기능을 사용하려면 Bitbucket 웹훅과 중간 서버가 필요합니다.
|
|
276
|
+
|
|
277
|
+
### 왜 중간 서버가 필요한가?
|
|
278
|
+
|
|
279
|
+
Bitbucket Pipelines는 **외부 웹훅 URL로 직접 트리거할 수 없습니다**. 따라서:
|
|
280
|
+
|
|
281
|
+
1. 웹훅 → 중간 서버 → Bitbucket API로 파이프라인 트리거
|
|
282
|
+
|
|
283
|
+
### 옵션 1: 외부 서버 사용 (권장)
|
|
284
|
+
|
|
285
|
+
AWS Lambda, Cloudflare Workers, 또는 별도 서버에서 웹훅을 수신하고 Bitbucket API를 호출:
|
|
286
|
+
|
|
287
|
+
```javascript
|
|
288
|
+
// Cloudflare Worker 예시
|
|
289
|
+
export default {
|
|
290
|
+
async fetch(request, env) {
|
|
291
|
+
const payload = await request.json();
|
|
292
|
+
|
|
293
|
+
// @gemini 멘션 확인
|
|
294
|
+
if (!payload.comment?.content?.raw?.includes('@gemini')) {
|
|
295
|
+
return new Response('No trigger', { status: 200 });
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Bitbucket Pipeline API 호출
|
|
299
|
+
const response = await fetch(
|
|
300
|
+
`https://api.bitbucket.org/2.0/repositories/${payload.repository.full_name}/pipelines/`,
|
|
301
|
+
{
|
|
302
|
+
method: 'POST',
|
|
303
|
+
headers: {
|
|
304
|
+
'Authorization': `Bearer ${env.BITBUCKET_ACCESS_TOKEN}`,
|
|
305
|
+
'Content-Type': 'application/json',
|
|
306
|
+
},
|
|
307
|
+
body: JSON.stringify({
|
|
308
|
+
target: {
|
|
309
|
+
ref_type: 'branch',
|
|
310
|
+
type: 'pipeline_ref_target',
|
|
311
|
+
ref_name: payload.pullrequest.source.branch.name,
|
|
312
|
+
selector: {
|
|
313
|
+
type: 'custom',
|
|
314
|
+
pattern: 'gemini-comment',
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
variables: [
|
|
318
|
+
{ key: 'WEBHOOK_PAYLOAD', value: JSON.stringify(payload) },
|
|
319
|
+
{ key: 'TRIGGER_EVENT', value: 'pullrequest:comment_created' },
|
|
320
|
+
],
|
|
321
|
+
}),
|
|
322
|
+
}
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
return new Response('Pipeline triggered', { status: 200 });
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### 옵션 2: Bitbucket Connect 앱 개발
|
|
331
|
+
|
|
332
|
+
더 깊은 통합이 필요하면 Bitbucket Connect 앱을 개발하세요.
|
|
333
|
+
|
|
334
|
+
### 웹훅 설정 방법
|
|
335
|
+
|
|
336
|
+
1. **Repository Settings → Webhooks → Add webhook**
|
|
337
|
+
2. **Title**: `bitbucket-gemini`
|
|
338
|
+
3. **URL**: 중간 서버 URL (예: `https://your-worker.workers.dev/webhook`)
|
|
339
|
+
4. **Triggers 선택**:
|
|
340
|
+
- ✅ Pull request: Comment created
|
|
341
|
+
- ✅ Pull request: Comment updated (선택사항)
|
|
342
|
+
5. **Save**
|
|
343
|
+
|
|
344
|
+
### 환경 변수
|
|
345
|
+
|
|
346
|
+
웹훅 핸들러에서 파이프라인 트리거 시 다음 변수를 전달해야 합니다:
|
|
347
|
+
|
|
348
|
+
| Variable | Description |
|
|
349
|
+
|----------|-------------|
|
|
350
|
+
| `WEBHOOK_PAYLOAD` | 웹훅 페이로드 JSON 문자열 |
|
|
351
|
+
| `TRIGGER_EVENT` | `pullrequest:comment_created` 또는 `pullrequest:comment_updated` |
|
|
352
|
+
|
|
238
353
|
## Pipeline Examples
|
|
239
354
|
|
|
240
355
|
### Basic PR Review
|
package/dist/cli.js
CHANGED
|
@@ -169,16 +169,21 @@ class BitbucketClient {
|
|
|
169
169
|
async getPullRequestCommits(workspace, repoSlug, prId) {
|
|
170
170
|
return this.paginatedRequest(`/repositories/${workspace}/${repoSlug}/pullrequests/${prId}/commits`);
|
|
171
171
|
}
|
|
172
|
-
async createPullRequestComment(workspace, repoSlug, prId, content,
|
|
172
|
+
async createPullRequestComment(workspace, repoSlug, prId, content, options) {
|
|
173
173
|
const body = {
|
|
174
174
|
content: {
|
|
175
175
|
raw: content
|
|
176
176
|
}
|
|
177
177
|
};
|
|
178
|
-
if (inline) {
|
|
178
|
+
if (options?.inline) {
|
|
179
179
|
body.inline = {
|
|
180
|
-
|
|
181
|
-
path: inline.path
|
|
180
|
+
from: options.inline.line,
|
|
181
|
+
path: options.inline.path
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
if (options?.parentId) {
|
|
185
|
+
body.parent = {
|
|
186
|
+
id: options.parentId
|
|
182
187
|
};
|
|
183
188
|
}
|
|
184
189
|
return this.request(`/repositories/${workspace}/${repoSlug}/pullrequests/${prId}/comments`, {
|
|
@@ -2849,19 +2854,21 @@ function detectMode(context, options) {
|
|
|
2849
2854
|
reason: `Explicitly specified mode: ${options.mode}`
|
|
2850
2855
|
};
|
|
2851
2856
|
}
|
|
2857
|
+
if (context.eventType === "pullrequest:comment_created" || context.eventType === "pullrequest:comment_updated") {
|
|
2858
|
+
const tagTrigger = tagMode.shouldTrigger(context, {
|
|
2859
|
+
triggerPhrase: options.triggerPhrase
|
|
2860
|
+
});
|
|
2861
|
+
if (tagTrigger.shouldTrigger) {
|
|
2862
|
+
return {
|
|
2863
|
+
mode: tagMode,
|
|
2864
|
+
reason: "Trigger phrase detected in comment"
|
|
2865
|
+
};
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2852
2868
|
if (options.prompt) {
|
|
2853
2869
|
return {
|
|
2854
2870
|
mode: agentMode,
|
|
2855
|
-
reason: "Explicit prompt provided"
|
|
2856
|
-
};
|
|
2857
|
-
}
|
|
2858
|
-
const tagTrigger = tagMode.shouldTrigger(context, {
|
|
2859
|
-
triggerPhrase: options.triggerPhrase
|
|
2860
|
-
});
|
|
2861
|
-
if (tagTrigger.shouldTrigger) {
|
|
2862
|
-
return {
|
|
2863
|
-
mode: tagMode,
|
|
2864
|
-
reason: "Trigger phrase detected in comment"
|
|
2871
|
+
reason: "Explicit prompt provided for auto-review"
|
|
2865
2872
|
};
|
|
2866
2873
|
}
|
|
2867
2874
|
if (context.eventType === "manual" || context.eventType === "schedule") {
|
|
@@ -2878,23 +2885,33 @@ function detectMode(context, options) {
|
|
|
2878
2885
|
|
|
2879
2886
|
// src/bitbucket/validation/trigger.ts
|
|
2880
2887
|
function validateTrigger(context, options) {
|
|
2881
|
-
if (
|
|
2888
|
+
if (context.eventType === "pullrequest:comment_created" || context.eventType === "pullrequest:comment_updated") {
|
|
2889
|
+
const commentResult = validateCommentTrigger(context.comment, options);
|
|
2890
|
+
if (commentResult.shouldTrigger) {
|
|
2891
|
+
return commentResult;
|
|
2892
|
+
}
|
|
2882
2893
|
return {
|
|
2883
|
-
shouldTrigger:
|
|
2884
|
-
reason:
|
|
2885
|
-
triggerType: "automation",
|
|
2886
|
-
userMessage: options.prompt
|
|
2894
|
+
shouldTrigger: false,
|
|
2895
|
+
reason: `Comment event but no trigger phrase found`
|
|
2887
2896
|
};
|
|
2888
2897
|
}
|
|
2889
2898
|
if (context.eventType === "manual" || context.eventType === "schedule") {
|
|
2890
2899
|
return {
|
|
2891
2900
|
shouldTrigger: true,
|
|
2892
2901
|
reason: `Triggered by ${context.eventType} event`,
|
|
2893
|
-
triggerType: "manual"
|
|
2902
|
+
triggerType: "manual",
|
|
2903
|
+
userMessage: options.prompt
|
|
2894
2904
|
};
|
|
2895
2905
|
}
|
|
2896
|
-
if (
|
|
2897
|
-
|
|
2906
|
+
if (options.prompt) {
|
|
2907
|
+
if (context.eventType === "pullrequest:created" || context.eventType === "pullrequest:updated" || context.isPR) {
|
|
2908
|
+
return {
|
|
2909
|
+
shouldTrigger: true,
|
|
2910
|
+
reason: "Explicit prompt provided for PR event",
|
|
2911
|
+
triggerType: "automation",
|
|
2912
|
+
userMessage: options.prompt
|
|
2913
|
+
};
|
|
2914
|
+
}
|
|
2898
2915
|
}
|
|
2899
2916
|
return {
|
|
2900
2917
|
shouldTrigger: false,
|
|
@@ -7214,6 +7231,7 @@ async function prepare() {
|
|
|
7214
7231
|
containsTrigger: true,
|
|
7215
7232
|
mode: mode.name,
|
|
7216
7233
|
trackingCommentId: modeResult.trackingCommentId,
|
|
7234
|
+
triggerCommentId: context.comment?.id,
|
|
7217
7235
|
prompt: triggerResult.userMessage || config.PROMPT || "",
|
|
7218
7236
|
systemPrompt: modeResult.modeContext.systemPrompt,
|
|
7219
7237
|
tools: modeResult.modeContext.tools,
|
|
@@ -8283,12 +8301,11 @@ async function updateTrackingComment(client, workspace, repoSlug, prId, commentI
|
|
|
8283
8301
|
}
|
|
8284
8302
|
async function createInlineComment(client, workspace, repoSlug, prId, filePath, line, content) {
|
|
8285
8303
|
return client.createPullRequestComment(workspace, repoSlug, prId, content, {
|
|
8286
|
-
path: filePath,
|
|
8287
|
-
line
|
|
8304
|
+
inline: { path: filePath, line }
|
|
8288
8305
|
});
|
|
8289
8306
|
}
|
|
8290
|
-
async function createPRComment(client, workspace, repoSlug, prId, content) {
|
|
8291
|
-
return client.createPullRequestComment(workspace, repoSlug, prId, content);
|
|
8307
|
+
async function createPRComment(client, workspace, repoSlug, prId, content, parentId) {
|
|
8308
|
+
return client.createPullRequestComment(workspace, repoSlug, prId, content, parentId ? { parentId } : undefined);
|
|
8292
8309
|
}
|
|
8293
8310
|
function formatTrackingComment(content) {
|
|
8294
8311
|
const statusEmoji = getStatusEmoji(content.status);
|
|
@@ -8482,16 +8499,15 @@ async function execute(options) {
|
|
|
8482
8499
|
console.log(`✅ Gemini response received (${response.finishReason})`);
|
|
8483
8500
|
let inlineCommentsCreated = 0;
|
|
8484
8501
|
if (response.toolCalls && context.entityNumber) {
|
|
8485
|
-
inlineCommentsCreated = await processToolCalls(bitbucketClient, context.workspace, context.repoSlug, context.entityNumber, response.toolCalls, opts.trackingCommentId);
|
|
8502
|
+
inlineCommentsCreated = await processToolCalls(bitbucketClient, context.workspace, context.repoSlug, context.entityNumber, response.toolCalls, opts.trackingCommentId, opts.triggerCommentId);
|
|
8486
8503
|
}
|
|
8487
8504
|
if (!response.toolCalls?.length && response.text && context.entityNumber) {
|
|
8488
|
-
await createPRComment(bitbucketClient, context.workspace, context.repoSlug, context.entityNumber, response.text);
|
|
8505
|
+
await createPRComment(bitbucketClient, context.workspace, context.repoSlug, context.entityNumber, response.text, opts.triggerCommentId);
|
|
8489
8506
|
}
|
|
8490
8507
|
if (opts.trackingCommentId && context.entityNumber) {
|
|
8491
8508
|
await updateTrackingComment(bitbucketClient, context.workspace, context.repoSlug, context.entityNumber, opts.trackingCommentId, {
|
|
8492
8509
|
status: "completed",
|
|
8493
8510
|
message: "Review completed successfully.",
|
|
8494
|
-
summary: response.text.substring(0, 500),
|
|
8495
8511
|
inlineCommentsCount: inlineCommentsCreated
|
|
8496
8512
|
});
|
|
8497
8513
|
}
|
|
@@ -8523,7 +8539,7 @@ async function execute(options) {
|
|
|
8523
8539
|
};
|
|
8524
8540
|
}
|
|
8525
8541
|
}
|
|
8526
|
-
async function processToolCalls(client, workspace, repoSlug, prId, toolCalls, trackingCommentId) {
|
|
8542
|
+
async function processToolCalls(client, workspace, repoSlug, prId, toolCalls, trackingCommentId, triggerCommentId) {
|
|
8527
8543
|
let inlineCommentsCreated = 0;
|
|
8528
8544
|
for (const toolCall of toolCalls) {
|
|
8529
8545
|
console.log(`\uD83D\uDD27 Processing tool call: ${toolCall.name}`);
|
|
@@ -8537,7 +8553,7 @@ async function processToolCalls(client, workspace, repoSlug, prId, toolCalls, tr
|
|
|
8537
8553
|
}
|
|
8538
8554
|
case "create_pr_comment": {
|
|
8539
8555
|
const args = toolCall.args;
|
|
8540
|
-
await createPRComment(client, workspace, repoSlug, prId, args.content);
|
|
8556
|
+
await createPRComment(client, workspace, repoSlug, prId, args.content, triggerCommentId);
|
|
8541
8557
|
break;
|
|
8542
8558
|
}
|
|
8543
8559
|
case "update_tracking_comment": {
|
|
@@ -8571,7 +8587,8 @@ function loadPrepareOutput() {
|
|
|
8571
8587
|
mode: data.mode || "tag",
|
|
8572
8588
|
prompt: data.prompt || "",
|
|
8573
8589
|
systemPrompt: data.systemPrompt || "",
|
|
8574
|
-
trackingCommentId: data.trackingCommentId
|
|
8590
|
+
trackingCommentId: data.trackingCommentId,
|
|
8591
|
+
triggerCommentId: data.triggerCommentId
|
|
8575
8592
|
};
|
|
8576
8593
|
}
|
|
8577
8594
|
|
|
@@ -1113,16 +1113,21 @@ class BitbucketClient {
|
|
|
1113
1113
|
async getPullRequestCommits(workspace, repoSlug, prId) {
|
|
1114
1114
|
return this.paginatedRequest(`/repositories/${workspace}/${repoSlug}/pullrequests/${prId}/commits`);
|
|
1115
1115
|
}
|
|
1116
|
-
async createPullRequestComment(workspace, repoSlug, prId, content,
|
|
1116
|
+
async createPullRequestComment(workspace, repoSlug, prId, content, options) {
|
|
1117
1117
|
const body = {
|
|
1118
1118
|
content: {
|
|
1119
1119
|
raw: content
|
|
1120
1120
|
}
|
|
1121
1121
|
};
|
|
1122
|
-
if (inline) {
|
|
1122
|
+
if (options?.inline) {
|
|
1123
1123
|
body.inline = {
|
|
1124
|
-
|
|
1125
|
-
path: inline.path
|
|
1124
|
+
from: options.inline.line,
|
|
1125
|
+
path: options.inline.path
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
if (options?.parentId) {
|
|
1129
|
+
body.parent = {
|
|
1130
|
+
id: options.parentId
|
|
1126
1131
|
};
|
|
1127
1132
|
}
|
|
1128
1133
|
return this.request(`/repositories/${workspace}/${repoSlug}/pullrequests/${prId}/comments`, {
|
|
@@ -3741,12 +3746,11 @@ async function updateTrackingComment(client, workspace, repoSlug, prId, commentI
|
|
|
3741
3746
|
}
|
|
3742
3747
|
async function createInlineComment(client, workspace, repoSlug, prId, filePath, line, content) {
|
|
3743
3748
|
return client.createPullRequestComment(workspace, repoSlug, prId, content, {
|
|
3744
|
-
path: filePath,
|
|
3745
|
-
line
|
|
3749
|
+
inline: { path: filePath, line }
|
|
3746
3750
|
});
|
|
3747
3751
|
}
|
|
3748
|
-
async function createPRComment(client, workspace, repoSlug, prId, content) {
|
|
3749
|
-
return client.createPullRequestComment(workspace, repoSlug, prId, content);
|
|
3752
|
+
async function createPRComment(client, workspace, repoSlug, prId, content, parentId) {
|
|
3753
|
+
return client.createPullRequestComment(workspace, repoSlug, prId, content, parentId ? { parentId } : undefined);
|
|
3750
3754
|
}
|
|
3751
3755
|
function formatTrackingComment(content) {
|
|
3752
3756
|
const statusEmoji = getStatusEmoji(content.status);
|
|
@@ -7988,16 +7992,15 @@ async function execute(options) {
|
|
|
7988
7992
|
console.log(`✅ Gemini response received (${response.finishReason})`);
|
|
7989
7993
|
let inlineCommentsCreated = 0;
|
|
7990
7994
|
if (response.toolCalls && context.entityNumber) {
|
|
7991
|
-
inlineCommentsCreated = await processToolCalls(bitbucketClient, context.workspace, context.repoSlug, context.entityNumber, response.toolCalls, opts.trackingCommentId);
|
|
7995
|
+
inlineCommentsCreated = await processToolCalls(bitbucketClient, context.workspace, context.repoSlug, context.entityNumber, response.toolCalls, opts.trackingCommentId, opts.triggerCommentId);
|
|
7992
7996
|
}
|
|
7993
7997
|
if (!response.toolCalls?.length && response.text && context.entityNumber) {
|
|
7994
|
-
await createPRComment(bitbucketClient, context.workspace, context.repoSlug, context.entityNumber, response.text);
|
|
7998
|
+
await createPRComment(bitbucketClient, context.workspace, context.repoSlug, context.entityNumber, response.text, opts.triggerCommentId);
|
|
7995
7999
|
}
|
|
7996
8000
|
if (opts.trackingCommentId && context.entityNumber) {
|
|
7997
8001
|
await updateTrackingComment(bitbucketClient, context.workspace, context.repoSlug, context.entityNumber, opts.trackingCommentId, {
|
|
7998
8002
|
status: "completed",
|
|
7999
8003
|
message: "Review completed successfully.",
|
|
8000
|
-
summary: response.text.substring(0, 500),
|
|
8001
8004
|
inlineCommentsCount: inlineCommentsCreated
|
|
8002
8005
|
});
|
|
8003
8006
|
}
|
|
@@ -8029,7 +8032,7 @@ async function execute(options) {
|
|
|
8029
8032
|
};
|
|
8030
8033
|
}
|
|
8031
8034
|
}
|
|
8032
|
-
async function processToolCalls(client, workspace, repoSlug, prId, toolCalls, trackingCommentId) {
|
|
8035
|
+
async function processToolCalls(client, workspace, repoSlug, prId, toolCalls, trackingCommentId, triggerCommentId) {
|
|
8033
8036
|
let inlineCommentsCreated = 0;
|
|
8034
8037
|
for (const toolCall of toolCalls) {
|
|
8035
8038
|
console.log(`\uD83D\uDD27 Processing tool call: ${toolCall.name}`);
|
|
@@ -8043,7 +8046,7 @@ async function processToolCalls(client, workspace, repoSlug, prId, toolCalls, tr
|
|
|
8043
8046
|
}
|
|
8044
8047
|
case "create_pr_comment": {
|
|
8045
8048
|
const args = toolCall.args;
|
|
8046
|
-
await createPRComment(client, workspace, repoSlug, prId, args.content);
|
|
8049
|
+
await createPRComment(client, workspace, repoSlug, prId, args.content, triggerCommentId);
|
|
8047
8050
|
break;
|
|
8048
8051
|
}
|
|
8049
8052
|
case "update_tracking_comment": {
|
|
@@ -8077,7 +8080,8 @@ function loadPrepareOutput() {
|
|
|
8077
8080
|
mode: data.mode || "tag",
|
|
8078
8081
|
prompt: data.prompt || "",
|
|
8079
8082
|
systemPrompt: data.systemPrompt || "",
|
|
8080
|
-
trackingCommentId: data.trackingCommentId
|
|
8083
|
+
trackingCommentId: data.trackingCommentId,
|
|
8084
|
+
triggerCommentId: data.triggerCommentId
|
|
8081
8085
|
};
|
|
8082
8086
|
}
|
|
8083
8087
|
export {
|
|
@@ -168,16 +168,21 @@ class BitbucketClient {
|
|
|
168
168
|
async getPullRequestCommits(workspace, repoSlug, prId) {
|
|
169
169
|
return this.paginatedRequest(`/repositories/${workspace}/${repoSlug}/pullrequests/${prId}/commits`);
|
|
170
170
|
}
|
|
171
|
-
async createPullRequestComment(workspace, repoSlug, prId, content,
|
|
171
|
+
async createPullRequestComment(workspace, repoSlug, prId, content, options) {
|
|
172
172
|
const body = {
|
|
173
173
|
content: {
|
|
174
174
|
raw: content
|
|
175
175
|
}
|
|
176
176
|
};
|
|
177
|
-
if (inline) {
|
|
177
|
+
if (options?.inline) {
|
|
178
178
|
body.inline = {
|
|
179
|
-
|
|
180
|
-
path: inline.path
|
|
179
|
+
from: options.inline.line,
|
|
180
|
+
path: options.inline.path
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
if (options?.parentId) {
|
|
184
|
+
body.parent = {
|
|
185
|
+
id: options.parentId
|
|
181
186
|
};
|
|
182
187
|
}
|
|
183
188
|
return this.request(`/repositories/${workspace}/${repoSlug}/pullrequests/${prId}/comments`, {
|
|
@@ -2848,19 +2853,21 @@ function detectMode(context, options) {
|
|
|
2848
2853
|
reason: `Explicitly specified mode: ${options.mode}`
|
|
2849
2854
|
};
|
|
2850
2855
|
}
|
|
2856
|
+
if (context.eventType === "pullrequest:comment_created" || context.eventType === "pullrequest:comment_updated") {
|
|
2857
|
+
const tagTrigger = tagMode.shouldTrigger(context, {
|
|
2858
|
+
triggerPhrase: options.triggerPhrase
|
|
2859
|
+
});
|
|
2860
|
+
if (tagTrigger.shouldTrigger) {
|
|
2861
|
+
return {
|
|
2862
|
+
mode: tagMode,
|
|
2863
|
+
reason: "Trigger phrase detected in comment"
|
|
2864
|
+
};
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2851
2867
|
if (options.prompt) {
|
|
2852
2868
|
return {
|
|
2853
2869
|
mode: agentMode,
|
|
2854
|
-
reason: "Explicit prompt provided"
|
|
2855
|
-
};
|
|
2856
|
-
}
|
|
2857
|
-
const tagTrigger = tagMode.shouldTrigger(context, {
|
|
2858
|
-
triggerPhrase: options.triggerPhrase
|
|
2859
|
-
});
|
|
2860
|
-
if (tagTrigger.shouldTrigger) {
|
|
2861
|
-
return {
|
|
2862
|
-
mode: tagMode,
|
|
2863
|
-
reason: "Trigger phrase detected in comment"
|
|
2870
|
+
reason: "Explicit prompt provided for auto-review"
|
|
2864
2871
|
};
|
|
2865
2872
|
}
|
|
2866
2873
|
if (context.eventType === "manual" || context.eventType === "schedule") {
|
|
@@ -2877,23 +2884,33 @@ function detectMode(context, options) {
|
|
|
2877
2884
|
|
|
2878
2885
|
// src/bitbucket/validation/trigger.ts
|
|
2879
2886
|
function validateTrigger(context, options) {
|
|
2880
|
-
if (
|
|
2887
|
+
if (context.eventType === "pullrequest:comment_created" || context.eventType === "pullrequest:comment_updated") {
|
|
2888
|
+
const commentResult = validateCommentTrigger(context.comment, options);
|
|
2889
|
+
if (commentResult.shouldTrigger) {
|
|
2890
|
+
return commentResult;
|
|
2891
|
+
}
|
|
2881
2892
|
return {
|
|
2882
|
-
shouldTrigger:
|
|
2883
|
-
reason:
|
|
2884
|
-
triggerType: "automation",
|
|
2885
|
-
userMessage: options.prompt
|
|
2893
|
+
shouldTrigger: false,
|
|
2894
|
+
reason: `Comment event but no trigger phrase found`
|
|
2886
2895
|
};
|
|
2887
2896
|
}
|
|
2888
2897
|
if (context.eventType === "manual" || context.eventType === "schedule") {
|
|
2889
2898
|
return {
|
|
2890
2899
|
shouldTrigger: true,
|
|
2891
2900
|
reason: `Triggered by ${context.eventType} event`,
|
|
2892
|
-
triggerType: "manual"
|
|
2901
|
+
triggerType: "manual",
|
|
2902
|
+
userMessage: options.prompt
|
|
2893
2903
|
};
|
|
2894
2904
|
}
|
|
2895
|
-
if (
|
|
2896
|
-
|
|
2905
|
+
if (options.prompt) {
|
|
2906
|
+
if (context.eventType === "pullrequest:created" || context.eventType === "pullrequest:updated" || context.isPR) {
|
|
2907
|
+
return {
|
|
2908
|
+
shouldTrigger: true,
|
|
2909
|
+
reason: "Explicit prompt provided for PR event",
|
|
2910
|
+
triggerType: "automation",
|
|
2911
|
+
userMessage: options.prompt
|
|
2912
|
+
};
|
|
2913
|
+
}
|
|
2897
2914
|
}
|
|
2898
2915
|
return {
|
|
2899
2916
|
shouldTrigger: false,
|
|
@@ -7213,6 +7230,7 @@ async function prepare() {
|
|
|
7213
7230
|
containsTrigger: true,
|
|
7214
7231
|
mode: mode.name,
|
|
7215
7232
|
trackingCommentId: modeResult.trackingCommentId,
|
|
7233
|
+
triggerCommentId: context.comment?.id,
|
|
7216
7234
|
prompt: triggerResult.userMessage || config.PROMPT || "",
|
|
7217
7235
|
systemPrompt: modeResult.modeContext.systemPrompt,
|
|
7218
7236
|
tools: modeResult.modeContext.tools,
|