github-issue-tower-defence-management 1.73.1 → 1.73.3

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/bin/adapter/entry-points/cli/index.js +3 -0
  3. package/bin/adapter/entry-points/cli/index.js.map +1 -1
  4. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +8 -8
  5. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
  6. package/bin/adapter/repositories/issue/GraphqlProjectItemRepository.js +27 -7
  7. package/bin/adapter/repositories/issue/GraphqlProjectItemRepository.js.map +1 -1
  8. package/bin/domain/usecases/CheckIssueReviewReadinessUseCase.js +1 -1
  9. package/bin/domain/usecases/CheckIssueReviewReadinessUseCase.js.map +1 -1
  10. package/bin/domain/usecases/HandleScheduledEventUseCase.js +1 -0
  11. package/bin/domain/usecases/HandleScheduledEventUseCase.js.map +1 -1
  12. package/bin/domain/usecases/IssueRejectionEvaluator.js +3 -1
  13. package/bin/domain/usecases/IssueRejectionEvaluator.js.map +1 -1
  14. package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js +3 -3
  15. package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js.map +1 -1
  16. package/bin/domain/usecases/RevertOrphanedPreparationUseCase.js +4 -2
  17. package/bin/domain/usecases/RevertOrphanedPreparationUseCase.js.map +1 -1
  18. package/bin/domain/usecases/SetDependedIssueUrlForOpenTaskPRsUseCase.js +6 -1
  19. package/bin/domain/usecases/SetDependedIssueUrlForOpenTaskPRsUseCase.js.map +1 -1
  20. package/package.json +1 -1
  21. package/src/adapter/entry-points/cli/index.test.ts +4 -0
  22. package/src/adapter/entry-points/cli/index.ts +3 -0
  23. package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.test.ts +114 -1
  24. package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.ts +21 -11
  25. package/src/adapter/repositories/issue/GraphqlProjectItemRepository.test.ts +103 -0
  26. package/src/adapter/repositories/issue/GraphqlProjectItemRepository.ts +33 -9
  27. package/src/domain/usecases/CheckIssueReviewReadinessUseCase.ts +5 -1
  28. package/src/domain/usecases/HandleScheduledEventUseCase.ts +2 -0
  29. package/src/domain/usecases/IssueRejectionEvaluator.test.ts +51 -0
  30. package/src/domain/usecases/IssueRejectionEvaluator.ts +12 -5
  31. package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts +4 -1
  32. package/src/domain/usecases/RevertOrphanedPreparationUseCase.test.ts +73 -0
  33. package/src/domain/usecases/RevertOrphanedPreparationUseCase.ts +10 -2
  34. package/src/domain/usecases/SetDependedIssueUrlForOpenTaskPRsUseCase.test.ts +57 -0
  35. package/src/domain/usecases/SetDependedIssueUrlForOpenTaskPRsUseCase.ts +11 -5
  36. package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts.map +1 -1
  37. package/types/adapter/repositories/issue/GraphqlProjectItemRepository.d.ts +2 -2
  38. package/types/adapter/repositories/issue/GraphqlProjectItemRepository.d.ts.map +1 -1
  39. package/types/domain/usecases/CheckIssueReviewReadinessUseCase.d.ts +1 -0
  40. package/types/domain/usecases/CheckIssueReviewReadinessUseCase.d.ts.map +1 -1
  41. package/types/domain/usecases/HandleScheduledEventUseCase.d.ts.map +1 -1
  42. package/types/domain/usecases/IssueRejectionEvaluator.d.ts +1 -1
  43. package/types/domain/usecases/IssueRejectionEvaluator.d.ts.map +1 -1
  44. package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts +1 -0
  45. package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts.map +1 -1
  46. package/types/domain/usecases/RevertOrphanedPreparationUseCase.d.ts +1 -0
  47. package/types/domain/usecases/RevertOrphanedPreparationUseCase.d.ts.map +1 -1
  48. package/types/domain/usecases/SetDependedIssueUrlForOpenTaskPRsUseCase.d.ts.map +1 -1
@@ -32,7 +32,7 @@ class RevertOrphanedPreparationUseCase {
32
32
  if (!isOrphaned) {
33
33
  continue;
34
34
  }
35
- const { hasRejections, comments } = await this.evaluateHasRejections(issue);
35
+ const { hasRejections, comments } = await this.evaluateHasRejections(issue, params.labelsAsLlmAgentName ?? []);
36
36
  if (!hasRejections) {
37
37
  if (awaitingQualityCheckStatusOption) {
38
38
  await this.issueRepository.updateStatus(project, issue, awaitingQualityCheckStatusOption.id);
@@ -59,7 +59,7 @@ class RevertOrphanedPreparationUseCase {
59
59
  await this.issueCommentRepository.createComment(issue, rejectionStatusMessage);
60
60
  }
61
61
  };
62
- this.evaluateHasRejections = async (issue) => {
62
+ this.evaluateHasRejections = async (issue, labelsAsLlmAgentName) => {
63
63
  if (issue.isClosed) {
64
64
  return { hasRejections: false, comments: [] };
65
65
  }
@@ -73,7 +73,9 @@ class RevertOrphanedPreparationUseCase {
73
73
  }
74
74
  const categoryLabels = issue.labels.filter((label) => label.startsWith('category:'));
75
75
  const hasLlmAgentLabel = issue.labels.some((l) => l === 'llm-agent' || l.startsWith('llm-agent:'));
76
+ const hasLabelAsLlmAgentName = issue.labels.some((label) => labelsAsLlmAgentName.includes(label));
76
77
  if (hasLlmAgentLabel ||
78
+ hasLabelAsLlmAgentName ||
77
79
  (categoryLabels.length > 0 && !categoryLabels.includes('category:e2e'))) {
78
80
  return { hasRejections: false, comments };
79
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"RevertOrphanedPreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/RevertOrphanedPreparationUseCase.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RevertOrphanedPreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/RevertOrphanedPreparationUseCase.ts"],"names":[],"mappings":"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"}
@@ -15,7 +15,12 @@ class SetDependedIssueUrlForOpenTaskPRsUseCase {
15
15
  }
16
16
  const relatedOpenPRs = await this.issueRepository.findRelatedOpenPRs(issue.url);
17
17
  for (const pr of relatedOpenPRs) {
18
- await this.issueRepository.setDependedIssueUrl(pr.url, input.project, issue.url);
18
+ try {
19
+ await this.issueRepository.setDependedIssueUrl(pr.url, input.project, issue.url);
20
+ }
21
+ catch (error) {
22
+ console.warn(`Failed to set depended issue URL for PR ${pr.url}, skipping and continuing with remaining PRs: ${error instanceof Error ? error.message : String(error)}`);
23
+ }
19
24
  }
20
25
  }
21
26
  };
@@ -1 +1 @@
1
- {"version":3,"file":"SetDependedIssueUrlForOpenTaskPRsUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/SetDependedIssueUrlForOpenTaskPRsUseCase.ts"],"names":[],"mappings":";;;AAIA,MAAa,wCAAwC;IACnD,YACW,eAGR;QAHQ,oBAAe,GAAf,eAAe,CAGvB;QAGH,QAAG,GAAG,KAAK,EAAE,KAA4C,EAAiB,EAAE;YAC1E,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,gCAAgC,EAAE,CAAC;gBACpD,OAAO,CAAC,IAAI,CACV,qHAAqH,CACtH,CAAC;gBACF,OAAO;YACT,CAAC;YACD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACjC,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;oBACjC,SAAS;gBACX,CAAC;gBACD,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,kBAAkB,CAClE,KAAK,CAAC,GAAG,CACV,CAAC;gBACF,KAAK,MAAM,EAAE,IAAI,cAAc,EAAE,CAAC;oBAChC,MAAM,IAAI,CAAC,eAAe,CAAC,mBAAmB,CAC5C,EAAE,CAAC,GAAG,EACN,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,GAAG,CACV,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC,CAAC;IAxBC,CAAC;CAyBL;AA/BD,4FA+BC"}
1
+ {"version":3,"file":"SetDependedIssueUrlForOpenTaskPRsUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/SetDependedIssueUrlForOpenTaskPRsUseCase.ts"],"names":[],"mappings":";;;AAIA,MAAa,wCAAwC;IACnD,YACW,eAGR;QAHQ,oBAAe,GAAf,eAAe,CAGvB;QAGH,QAAG,GAAG,KAAK,EAAE,KAA4C,EAAiB,EAAE;YAC1E,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,gCAAgC,EAAE,CAAC;gBACpD,OAAO,CAAC,IAAI,CACV,qHAAqH,CACtH,CAAC;gBACF,OAAO;YACT,CAAC;YACD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACjC,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;oBACjC,SAAS;gBACX,CAAC;gBACD,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,kBAAkB,CAClE,KAAK,CAAC,GAAG,CACV,CAAC;gBACF,KAAK,MAAM,EAAE,IAAI,cAAc,EAAE,CAAC;oBAChC,IAAI,CAAC;wBACH,MAAM,IAAI,CAAC,eAAe,CAAC,mBAAmB,CAC5C,EAAE,CAAC,GAAG,EACN,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,GAAG,CACV,CAAC;oBACJ,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,OAAO,CAAC,IAAI,CACV,2CAA2C,EAAE,CAAC,GAAG,iDAAiD,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAC3J,CAAC;oBACJ,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC,CAAC;IA9BC,CAAC;CA+BL;AArCD,4FAqCC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-issue-tower-defence-management",
3
- "version": "1.73.1",
3
+ "version": "1.73.3",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
@@ -1188,6 +1188,7 @@ mysteryKey: 'value'
1188
1188
  thresholdForAutoReject: 3,
1189
1189
  workflowBlockerResolvedWebhookUrl: null,
1190
1190
  allowedIssueAuthors: null,
1191
+ labelsAsLlmAgentName: null,
1191
1192
  });
1192
1193
  });
1193
1194
 
@@ -1222,6 +1223,7 @@ mysteryKey: 'value'
1222
1223
  thresholdForAutoReject: 3,
1223
1224
  workflowBlockerResolvedWebhookUrl: null,
1224
1225
  allowedIssueAuthors: null,
1226
+ labelsAsLlmAgentName: null,
1225
1227
  });
1226
1228
  });
1227
1229
 
@@ -1501,6 +1503,7 @@ mysteryKey: 'value'
1501
1503
  expect(mockRun).toHaveBeenCalledWith({
1502
1504
  projectUrl: 'https://github.com/orgs/test/projects/1',
1503
1505
  issueUrl: 'https://github.com/test/repo/issues/1',
1506
+ labelsAsLlmAgentName: null,
1504
1507
  });
1505
1508
  expect(stdoutSpy).toHaveBeenCalledWith(
1506
1509
  `${JSON.stringify({ reviewReady: true, rejections: [] })}\n`,
@@ -1583,6 +1586,7 @@ mysteryKey: 'value'
1583
1586
  expect(mockRun).toHaveBeenCalledWith({
1584
1587
  projectUrl: 'https://github.com/orgs/override/projects/2',
1585
1588
  issueUrl: 'https://github.com/test/repo/issues/1',
1589
+ labelsAsLlmAgentName: null,
1586
1590
  });
1587
1591
 
1588
1592
  stdoutSpy.mockRestore();
@@ -268,6 +268,7 @@ program
268
268
  thresholdForAutoReject: config.thresholdForAutoReject ?? 3,
269
269
  awLogDirectoryPath: config.awLogDirectoryPath,
270
270
  awLogStaleThresholdMinutes: config.awLogStaleThresholdMinutes,
271
+ labelsAsLlmAgentName: config.labelsAsLlmAgentName ?? null,
271
272
  });
272
273
  }
273
274
 
@@ -448,6 +449,7 @@ program
448
449
  thresholdForAutoReject,
449
450
  workflowBlockerResolvedWebhookUrl,
450
451
  allowedIssueAuthors,
452
+ labelsAsLlmAgentName: config.labelsAsLlmAgentName ?? null,
451
453
  });
452
454
  });
453
455
 
@@ -540,6 +542,7 @@ program
540
542
  const result = await useCase.run({
541
543
  projectUrl,
542
544
  issueUrl: options.issueUrl,
545
+ labelsAsLlmAgentName: config.labelsAsLlmAgentName ?? null,
543
546
  });
544
547
 
545
548
  process.stdout.write(`${JSON.stringify(result)}\n`);
@@ -2,9 +2,13 @@ import { mock } from 'jest-mock-extended';
2
2
  import { ApiV3CheerioRestIssueRepository } from './ApiV3CheerioRestIssueRepository';
3
3
  import { ApiV3IssueRepository } from './ApiV3IssueRepository';
4
4
  import { RestIssueRepository } from './RestIssueRepository';
5
- import { GraphqlProjectItemRepository } from './GraphqlProjectItemRepository';
5
+ import {
6
+ GraphqlProjectItemRepository,
7
+ ProjectItem,
8
+ } from './GraphqlProjectItemRepository';
6
9
  import { LocalStorageCacheRepository } from '../LocalStorageCacheRepository';
7
10
  import { LocalStorageRepository } from '../LocalStorageRepository';
11
+ import { Project } from '../../../domain/entities/Project';
8
12
 
9
13
  describe('ApiV3CheerioRestIssueRepository', () => {
10
14
  describe('convertProjectItemToIssue', () => {
@@ -267,6 +271,115 @@ describe('ApiV3CheerioRestIssueRepository', () => {
267
271
  });
268
272
  });
269
273
 
274
+ describe('setDependedIssueUrl', () => {
275
+ const projectWithDependedIssueUrlField = {
276
+ ...mock<Project>(),
277
+ id: 'test-project-id',
278
+ dependedIssueUrlSeparatedByComma: {
279
+ name: 'Depended Issue URL separated by comma',
280
+ fieldId: 'depended-field-id',
281
+ },
282
+ };
283
+ const prUrl = 'https://github.com/owner/repo/pull/100';
284
+ const taskIssueUrl = 'https://github.com/owner/repo/issues/1';
285
+
286
+ const makeProjectItem = (
287
+ id: string,
288
+ customFields: { name: string; value: string | null }[],
289
+ ): ProjectItem => ({
290
+ ...mock<ProjectItem>(),
291
+ id,
292
+ url: prUrl,
293
+ customFields,
294
+ });
295
+
296
+ it('should add the PR to the current project and set the field when the PR has no project item on the current project', async () => {
297
+ const { repository, graphqlProjectItemRepository } =
298
+ createApiV3CheerioRestIssueRepository();
299
+ graphqlProjectItemRepository.fetchProjectItemByUrl.mockResolvedValue(
300
+ null,
301
+ );
302
+ graphqlProjectItemRepository.addIssueToProject.mockResolvedValue(
303
+ 'new-project-item-id',
304
+ );
305
+ graphqlProjectItemRepository.updateProjectTextField.mockResolvedValue();
306
+
307
+ await repository.setDependedIssueUrl(
308
+ prUrl,
309
+ projectWithDependedIssueUrlField,
310
+ taskIssueUrl,
311
+ );
312
+
313
+ expect(
314
+ graphqlProjectItemRepository.fetchProjectItemByUrl,
315
+ ).toHaveBeenCalledWith(prUrl, 'test-project-id');
316
+ expect(
317
+ graphqlProjectItemRepository.addIssueToProject,
318
+ ).toHaveBeenCalledWith('test-project-id', prUrl);
319
+ expect(
320
+ graphqlProjectItemRepository.updateProjectTextField,
321
+ ).toHaveBeenCalledWith(
322
+ 'test-project-id',
323
+ 'depended-field-id',
324
+ 'new-project-item-id',
325
+ taskIssueUrl,
326
+ );
327
+ });
328
+
329
+ it('should set the field on the existing project item without adding the PR when it already belongs to the current project', async () => {
330
+ const { repository, graphqlProjectItemRepository } =
331
+ createApiV3CheerioRestIssueRepository();
332
+ graphqlProjectItemRepository.fetchProjectItemByUrl.mockResolvedValue(
333
+ makeProjectItem('existing-project-item-id', []),
334
+ );
335
+ graphqlProjectItemRepository.updateProjectTextField.mockResolvedValue();
336
+
337
+ await repository.setDependedIssueUrl(
338
+ prUrl,
339
+ projectWithDependedIssueUrlField,
340
+ taskIssueUrl,
341
+ );
342
+
343
+ expect(
344
+ graphqlProjectItemRepository.addIssueToProject,
345
+ ).not.toHaveBeenCalled();
346
+ expect(
347
+ graphqlProjectItemRepository.updateProjectTextField,
348
+ ).toHaveBeenCalledWith(
349
+ 'test-project-id',
350
+ 'depended-field-id',
351
+ 'existing-project-item-id',
352
+ taskIssueUrl,
353
+ );
354
+ });
355
+
356
+ it('should do nothing when the depended-issue-url field value is already set on the existing project item', async () => {
357
+ const { repository, graphqlProjectItemRepository } =
358
+ createApiV3CheerioRestIssueRepository();
359
+ graphqlProjectItemRepository.fetchProjectItemByUrl.mockResolvedValue(
360
+ makeProjectItem('existing-project-item-id', [
361
+ {
362
+ name: 'Depended Issue URL separated by comma',
363
+ value: taskIssueUrl,
364
+ },
365
+ ]),
366
+ );
367
+
368
+ await repository.setDependedIssueUrl(
369
+ prUrl,
370
+ projectWithDependedIssueUrlField,
371
+ taskIssueUrl,
372
+ );
373
+
374
+ expect(
375
+ graphqlProjectItemRepository.addIssueToProject,
376
+ ).not.toHaveBeenCalled();
377
+ expect(
378
+ graphqlProjectItemRepository.updateProjectTextField,
379
+ ).not.toHaveBeenCalled();
380
+ });
381
+ });
382
+
270
383
  describe('getPullRequestChangedFilePaths', () => {
271
384
  afterEach(() => {
272
385
  jest.restoreAllMocks();
@@ -516,24 +516,31 @@ export class ApiV3CheerioRestIssueRepository
516
516
  project: Project,
517
517
  issueUrl: string,
518
518
  ): Promise<void> => {
519
- if (!project.dependedIssueUrlSeparatedByComma) {
519
+ const dependedIssueUrlField = project.dependedIssueUrlSeparatedByComma;
520
+ if (!dependedIssueUrlField) {
520
521
  return;
521
522
  }
522
- const projectItem =
523
- await this.graphqlProjectItemRepository.fetchProjectItemByUrl(prUrl);
524
- if (!projectItem) {
525
- return;
526
- }
527
- const existingValue = projectItem.customFields.find(
528
- (field) => field.name === project.dependedIssueUrlSeparatedByComma?.name,
523
+ const existingProjectItem =
524
+ await this.graphqlProjectItemRepository.fetchProjectItemByUrl(
525
+ prUrl,
526
+ project.id,
527
+ );
528
+ const existingValue = existingProjectItem?.customFields.find(
529
+ (field) => field.name === dependedIssueUrlField.name,
529
530
  )?.value;
530
531
  if (existingValue) {
531
532
  return;
532
533
  }
534
+ const projectItemId =
535
+ existingProjectItem?.id ??
536
+ (await this.graphqlProjectItemRepository.addIssueToProject(
537
+ project.id,
538
+ prUrl,
539
+ ));
533
540
  await this.graphqlProjectItemRepository.updateProjectTextField(
534
541
  project.id,
535
- project.dependedIssueUrlSeparatedByComma.fieldId,
536
- projectItem.id,
542
+ dependedIssueUrlField.fieldId,
543
+ projectItemId,
537
544
  issueUrl,
538
545
  );
539
546
  };
@@ -547,7 +554,10 @@ export class ApiV3CheerioRestIssueRepository
547
554
  return;
548
555
  }
549
556
  const projectItem =
550
- await this.graphqlProjectItemRepository.fetchProjectItemByUrl(issueUrl);
557
+ await this.graphqlProjectItemRepository.fetchProjectItemByUrl(
558
+ issueUrl,
559
+ project.id,
560
+ );
551
561
  if (!projectItem) {
552
562
  return;
553
563
  }
@@ -660,5 +660,108 @@ describe('GraphqlProjectItemRepository', () => {
660
660
 
661
661
  expect(result).toBeNull();
662
662
  });
663
+
664
+ const makeMultiProjectPrNode = (
665
+ url: string,
666
+ number: number,
667
+ nodes: {
668
+ id: string;
669
+ projectId: string;
670
+ }[],
671
+ ) => ({
672
+ number,
673
+ title: 'PR Title',
674
+ state: 'OPEN',
675
+ url,
676
+ body: 'body text',
677
+ createdAt: '2024-01-01T00:00:00Z',
678
+ author: { login: 'octocat' },
679
+ labels: { nodes: [] },
680
+ assignees: { nodes: [] },
681
+ repository: { nameWithOwner: 'owner/repo' },
682
+ projectItems: {
683
+ nodes: nodes.map((node) => ({
684
+ id: node.id,
685
+ project: { id: node.projectId },
686
+ fieldValues: {
687
+ nodes: [
688
+ {
689
+ __typename: 'ProjectV2ItemFieldSingleSelectValue',
690
+ name: 'Preparation',
691
+ field: { name: 'Status' },
692
+ },
693
+ ],
694
+ },
695
+ })),
696
+ },
697
+ });
698
+
699
+ it('should select the project item belonging to the given project id when the PR is on multiple projects', async () => {
700
+ const localStorageRepository = new LocalStorageRepository();
701
+ const repository = new GraphqlProjectItemRepository(
702
+ localStorageRepository,
703
+ 'dummy-token',
704
+ );
705
+
706
+ mockPost.mockReturnValueOnce(
707
+ mockJsonResponse({
708
+ data: {
709
+ repository: {
710
+ issue: null,
711
+ pullRequest: makeMultiProjectPrNode(
712
+ 'https://github.com/owner/repo/pull/11',
713
+ 11,
714
+ [
715
+ { id: 'item-other-project', projectId: 'project-other' },
716
+ { id: 'item-current-project', projectId: 'project-current' },
717
+ ],
718
+ ),
719
+ },
720
+ },
721
+ }),
722
+ );
723
+
724
+ const result = await repository.fetchProjectItemByUrl(
725
+ 'https://github.com/owner/repo/pull/11',
726
+ 'project-current',
727
+ );
728
+
729
+ expect(result).not.toBeNull();
730
+ expect(result?.id).toBe('item-current-project');
731
+ });
732
+
733
+ it('should return null and warn instead of throwing when the PR has no project item on the given project', async () => {
734
+ const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
735
+ const localStorageRepository = new LocalStorageRepository();
736
+ const repository = new GraphqlProjectItemRepository(
737
+ localStorageRepository,
738
+ 'dummy-token',
739
+ );
740
+
741
+ mockPost.mockReturnValueOnce(
742
+ mockJsonResponse({
743
+ data: {
744
+ repository: {
745
+ issue: null,
746
+ pullRequest: makeMultiProjectPrNode(
747
+ 'https://github.com/owner/repo/pull/12',
748
+ 12,
749
+ [{ id: 'item-other-project', projectId: 'project-other' }],
750
+ ),
751
+ },
752
+ },
753
+ }),
754
+ );
755
+
756
+ const result = await repository.fetchProjectItemByUrl(
757
+ 'https://github.com/owner/repo/pull/12',
758
+ 'project-current',
759
+ );
760
+
761
+ expect(result).toBeNull();
762
+ expect(warnSpy).toHaveBeenCalled();
763
+
764
+ warnSpy.mockRestore();
765
+ });
663
766
  });
664
767
  });
@@ -663,6 +663,7 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
663
663
  };
664
664
  fetchProjectItemByUrl = async (
665
665
  issueUrl: string,
666
+ projectId?: string,
666
667
  ): Promise<ProjectItem | null> => {
667
668
  const { owner, repo, issueNumber } = this.extractIssueFromUrl(issueUrl);
668
669
  const graphql = `query GetIssueOrPullRequest($owner: String!, $repo: String!, $number: Int!) {
@@ -693,6 +694,9 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
693
694
  projectItems(first: 10) {
694
695
  nodes {
695
696
  id
697
+ project {
698
+ id
699
+ }
696
700
  fieldValues(first: 10) {
697
701
  nodes {
698
702
  ... on ProjectV2ItemFieldTextValue {
@@ -767,6 +771,9 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
767
771
  projectItems(first: 10) {
768
772
  nodes {
769
773
  id
774
+ project {
775
+ id
776
+ }
770
777
  fieldValues(first: 10) {
771
778
  nodes {
772
779
  ... on ProjectV2ItemFieldTextValue {
@@ -839,6 +846,7 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
839
846
  projectItems: {
840
847
  nodes: {
841
848
  id: string;
849
+ project: { id: string } | null;
842
850
  fieldValues: {
843
851
  nodes: {
844
852
  text: string;
@@ -883,9 +891,16 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
883
891
  return null;
884
892
  }
885
893
  const projectItems = content.projectItems.nodes;
886
- const item = projectItems[0];
894
+ const item = projectId
895
+ ? projectItems.find((node) => node.project?.id === projectId)
896
+ : projectItems[0];
887
897
  if (!item) {
888
- throw new Error(`No project item found for issue ${issueUrl}`);
898
+ console.warn(
899
+ projectId
900
+ ? `No project item found for issue ${issueUrl} on project ${projectId}`
901
+ : `No project item found for issue ${issueUrl}`,
902
+ );
903
+ return null;
889
904
  }
890
905
  return {
891
906
  id: item.id,
@@ -1066,13 +1081,18 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
1066
1081
  addIssueToProject = async (
1067
1082
  projectId: string,
1068
1083
  issueUrl: string,
1069
- ): Promise<void> => {
1084
+ ): Promise<string> => {
1070
1085
  const { owner, repo, issueNumber } = this.extractIssueFromUrl(issueUrl);
1071
1086
  const nodeIdQuery = {
1072
- query: `query GetIssueNodeId($owner: String!, $repo: String!, $number: Int!) {
1087
+ query: `query GetContentNodeId($owner: String!, $repo: String!, $number: Int!) {
1073
1088
  repository(owner: $owner, name: $repo) {
1074
- issue(number: $number) {
1075
- id
1089
+ issueOrPullRequest(number: $number) {
1090
+ ... on Issue {
1091
+ id
1092
+ }
1093
+ ... on PullRequest {
1094
+ id
1095
+ }
1076
1096
  }
1077
1097
  }
1078
1098
  }`,
@@ -1088,9 +1108,9 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
1088
1108
  .json<{
1089
1109
  data: {
1090
1110
  repository: {
1091
- issue: {
1111
+ issueOrPullRequest: {
1092
1112
  id: string;
1093
- };
1113
+ } | null;
1094
1114
  };
1095
1115
  };
1096
1116
  errors?: { message: string }[];
@@ -1098,7 +1118,10 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
1098
1118
  if (nodeIdRes.errors) {
1099
1119
  throw new Error(nodeIdRes.errors.map((e) => e.message).join('\n'));
1100
1120
  }
1101
- const contentId = nodeIdRes.data.repository.issue.id;
1121
+ const contentId = nodeIdRes.data.repository.issueOrPullRequest?.id;
1122
+ if (!contentId) {
1123
+ throw new Error(`Content not found for url ${issueUrl}`);
1124
+ }
1102
1125
 
1103
1126
  const addQuery = {
1104
1127
  query: `mutation AddIssueToProject($projectId: ID!, $contentId: ID!) {
@@ -1126,5 +1149,6 @@ query GetProjectFields($owner: String!, $repository: String!, $issueNumber: Int!
1126
1149
  if (addRes.errors) {
1127
1150
  throw new Error(addRes.errors.map((e) => e.message).join('\n'));
1128
1151
  }
1152
+ return addRes.data.addProjectV2ItemById.item.id;
1129
1153
  };
1130
1154
  }
@@ -27,6 +27,7 @@ export class CheckIssueReviewReadinessUseCase {
27
27
  run = async (params: {
28
28
  projectUrl: string;
29
29
  issueUrl: string;
30
+ labelsAsLlmAgentName?: string[] | null;
30
31
  }): Promise<IssueReviewReadinessResult> => {
31
32
  const project = await this.projectRepository.getByUrl(params.projectUrl);
32
33
  const issue = await this.issueRepository.get(params.issueUrl, project);
@@ -35,7 +36,10 @@ export class CheckIssueReviewReadinessUseCase {
35
36
  throw new IssueNotFoundError(params.issueUrl);
36
37
  }
37
38
 
38
- const { rejections } = await this.issueRejectionEvaluator.evaluate(issue);
39
+ const { rejections } = await this.issueRejectionEvaluator.evaluate(
40
+ issue,
41
+ params.labelsAsLlmAgentName ?? [],
42
+ );
39
43
 
40
44
  return {
41
45
  reviewReady: rejections.length === 0,
@@ -301,6 +301,8 @@ ${JSON.stringify(e)}
301
301
  input.startPreparation.awLogStaleThresholdMinutes,
302
302
  awaitingQualityCheckStatus:
303
303
  input.startPreparation.awaitingQualityCheckStatus ?? undefined,
304
+ labelsAsLlmAgentName:
305
+ input.startPreparation.labelsAsLlmAgentName ?? null,
304
306
  });
305
307
  }
306
308
  const preparationResult = await this.startPreparationUseCase.run({
@@ -149,5 +149,56 @@ describe('IssueRejectionEvaluator', () => {
149
149
  expect(mockIssueRepository.findRelatedOpenPRs).not.toHaveBeenCalled();
150
150
  expect(result.rejections).toHaveLength(0);
151
151
  });
152
+
153
+ it('should reject with PULL_REQUEST_NOT_FOUND when a normal issue has no related PR', async () => {
154
+ mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([]);
155
+
156
+ const result = await evaluator.evaluate({
157
+ url: 'https://github.com/user/repo/issues/1',
158
+ labels: [],
159
+ isPr: false,
160
+ });
161
+
162
+ expect(mockIssueRepository.findRelatedOpenPRs).toHaveBeenCalledWith(
163
+ 'https://github.com/user/repo/issues/1',
164
+ );
165
+ expect(result.rejections).toHaveLength(1);
166
+ expect(result.rejections[0].type).toBe('PULL_REQUEST_NOT_FOUND');
167
+ expect(result.approvedPrUrl).toBeNull();
168
+ });
169
+
170
+ it('should not reject with PULL_REQUEST_NOT_FOUND when issue has a label listed in labelsAsLlmAgentName', async () => {
171
+ const result = await evaluator.evaluate(
172
+ {
173
+ url: 'https://github.com/user/repo/issues/1',
174
+ labels: ['story'],
175
+ isPr: false,
176
+ },
177
+ ['story'],
178
+ );
179
+
180
+ expect(mockIssueRepository.findRelatedOpenPRs).not.toHaveBeenCalled();
181
+ expect(result.rejections).toHaveLength(0);
182
+ expect(result.approvedPrUrl).toBeNull();
183
+ });
184
+
185
+ it('should still reject with PULL_REQUEST_NOT_FOUND when issue label is not in labelsAsLlmAgentName', async () => {
186
+ mockIssueRepository.findRelatedOpenPRs.mockResolvedValue([]);
187
+
188
+ const result = await evaluator.evaluate(
189
+ {
190
+ url: 'https://github.com/user/repo/issues/1',
191
+ labels: ['story'],
192
+ isPr: false,
193
+ },
194
+ ['bug'],
195
+ );
196
+
197
+ expect(mockIssueRepository.findRelatedOpenPRs).toHaveBeenCalledWith(
198
+ 'https://github.com/user/repo/issues/1',
199
+ );
200
+ expect(result.rejections).toHaveLength(1);
201
+ expect(result.rejections[0].type).toBe('PULL_REQUEST_NOT_FOUND');
202
+ });
152
203
  });
153
204
  });
@@ -25,11 +25,14 @@ export class IssueRejectionEvaluator {
25
25
  >,
26
26
  ) {}
27
27
 
28
- evaluate = async (issue: {
29
- url: string;
30
- labels: string[];
31
- isPr: boolean;
32
- }): Promise<PrRejectionResult> => {
28
+ evaluate = async (
29
+ issue: {
30
+ url: string;
31
+ labels: string[];
32
+ isPr: boolean;
33
+ },
34
+ labelsAsLlmAgentName: string[] = [],
35
+ ): Promise<PrRejectionResult> => {
33
36
  const rejections: { type: PrRejectedReasonType; detail: string }[] = [];
34
37
  let approvedPrUrl: string | null = null;
35
38
 
@@ -39,9 +42,13 @@ export class IssueRejectionEvaluator {
39
42
  const hasLlmAgentLabel = issue.labels.some(
40
43
  (l) => l === 'llm-agent' || l.startsWith('llm-agent:'),
41
44
  );
45
+ const hasLabelAsLlmAgentName = issue.labels.some((label) =>
46
+ labelsAsLlmAgentName.includes(label),
47
+ );
42
48
 
43
49
  if (
44
50
  !hasLlmAgentLabel &&
51
+ !hasLabelAsLlmAgentName &&
45
52
  (categoryLabels.length <= 0 || categoryLabels.includes('category:e2e'))
46
53
  ) {
47
54
  const prsToCheck = issue.isPr