1
1
import { JSONContent } from '@tiptap/core'
2
+ import tracer from 'dd-trace'
2
3
import AzureDevOpsIssueId from 'parabol-client/shared/gqlIds/AzureDevOpsIssueId'
3
4
import IntegrationHash from 'parabol-client/shared/gqlIds/IntegrationHash'
4
5
import { splitTipTapContent } from 'parabol-client/shared/tiptap/splitTipTapContent'
@@ -422,55 +423,59 @@ class AzureDevOpsServerManager implements TaskIntegrationManager {
422
423
}
423
424
424
425
async getWorkItemData ( instanceId : string , workItemIds : number [ ] , fields ?: string [ ] ) {
425
- const workItems = [ ] as WorkItem [ ]
426
- let firstError : Error | undefined
427
- const uri = `https://${ instanceId } /_apis/wit/workitemsbatch?api-version=7.1-preview.1`
428
- // we can fetch at most 200 items at once VS403474
429
- for ( let i = 0 ; i < workItemIds . length ; i += 200 ) {
430
- const ids = workItemIds . slice ( i , i + 200 )
431
- const payload = ! ! fields ? { ids, fields : fields } : { ids, $expand : 'Links' }
432
- const res = await this . post < WorkItemBatchResponse > ( uri , payload )
426
+ return tracer . trace ( 'AzureDevOpsServerManager.getWorkItemData' , async ( ) => {
427
+ const workItems = [ ] as WorkItem [ ]
428
+ let firstError : Error | undefined
429
+ const uri = `https://${ instanceId } /_apis/wit/workitemsbatch?api-version=7.1-preview.1`
430
+ // we can fetch at most 200 items at once VS403474
431
+ for ( let i = 0 ; i < workItemIds . length ; i += 200 ) {
432
+ const ids = workItemIds . slice ( i , i + 200 )
433
+ const payload = ! ! fields ? { ids, fields : fields } : { ids, $expand : 'Links' }
434
+ const res = await this . post < WorkItemBatchResponse > ( uri , payload )
435
+ if ( res instanceof Error ) {
436
+ if ( ! firstError ) {
437
+ firstError = res
438
+ }
439
+ } else {
440
+ const mappedWorkItems = ( res . value as WorkItem [ ] ) . map ( ( workItem ) => {
441
+ return {
442
+ ...workItem
443
+ }
444
+ } )
445
+ workItems . push ( ...mappedWorkItems )
446
+ }
447
+ }
448
+ return { error : firstError , workItems : workItems }
449
+ } )
450
+ }
451
+
452
+ async executeWiqlQuery ( instanceId : string , query : string ) {
453
+ return tracer . trace ( 'AzureDevOpsServerManager.executeWiqlQuery' , async ( ) => {
454
+ const workItemReferences = [ ] as WorkItemReference [ ]
455
+ let firstError : Error | undefined
456
+ const payload = {
457
+ query : query
458
+ }
459
+ const res = await this . post < WorkItemQueryResult > (
460
+ `https://${ instanceId } /_apis/wit/wiql?api-version=6.0` ,
461
+ payload
462
+ )
433
463
if ( res instanceof Error ) {
434
464
if ( ! firstError ) {
435
465
firstError = res
436
466
}
437
467
} else {
438
- const mappedWorkItems = ( res . value as WorkItem [ ] ) . map ( ( workItem ) => {
468
+ const workItems = res . workItems . map ( ( workItem ) => {
469
+ const { id, url} = workItem
439
470
return {
440
- ...workItem
471
+ id,
472
+ url
441
473
}
442
474
} )
443
- workItems . push ( ...mappedWorkItems )
444
- }
445
- }
446
- return { error : firstError , workItems : workItems }
447
- }
448
-
449
- async executeWiqlQuery ( instanceId : string , query : string ) {
450
- const workItemReferences = [ ] as WorkItemReference [ ]
451
- let firstError : Error | undefined
452
- const payload = {
453
- query : query
454
- }
455
- const res = await this . post < WorkItemQueryResult > (
456
- `https://${ instanceId } /_apis/wit/wiql?api-version=6.0` ,
457
- payload
458
- )
459
- if ( res instanceof Error ) {
460
- if ( ! firstError ) {
461
- firstError = res
475
+ workItemReferences . push ( ...workItems )
462
476
}
463
- } else {
464
- const workItems = res . workItems . map ( ( workItem ) => {
465
- const { id, url} = workItem
466
- return {
467
- id,
468
- url
469
- }
470
- } )
471
- workItemReferences . push ( ...workItems )
472
- }
473
- return { error : firstError , workItems : workItemReferences }
477
+ return { error : firstError , workItems : workItemReferences }
478
+ } )
474
479
}
475
480
476
481
async getWorkItems (
@@ -479,74 +484,78 @@ class AzureDevOpsServerManager implements TaskIntegrationManager {
479
484
projectKeyFilters : string [ ] | null ,
480
485
isWIQL : boolean
481
486
) {
482
- let projectFilter = ''
483
- if ( projectKeyFilters && projectKeyFilters . length > 0 ) {
484
- projectKeyFilters . forEach ( ( projectKey , idx ) => {
485
- if ( idx === 0 ) projectFilter = `AND ( [System.TeamProject] = '${ projectKey } '`
486
- else projectFilter += ` OR [System.TeamProject] = '${ projectKey } '`
487
- } )
488
- projectFilter += ` )`
489
- }
490
- let customQueryString = ''
491
- if ( isWIQL )
492
- customQueryString = queryString
493
- ? `Select [System.Id], [System.Title], [System.State] From WorkItems Where ${ queryString } ${ projectFilter } `
494
- : `Select [System.Id], [System.Title], [System.State] From WorkItems Where [System.WorkItemType] IN('User Story', 'Task', 'Issue', 'Bug', 'Feature', 'Epic') AND [State] <> 'Closed' AND [State] <> 'Removed' order by [Microsoft.VSTS.Common.Priority] asc, [System.CreatedDate] desc`
495
- else {
496
- const queryFilter = queryString ? `AND [System.Title] contains '${ queryString } '` : ''
497
- customQueryString = `Select [System.Id], [System.Title], [System.State] From WorkItems Where [System.WorkItemType] IN('User Story', 'Task', 'Issue', 'Bug', 'Feature', 'Epic') AND [State] <> 'Closed' ${ queryFilter } ${ projectFilter } AND [State] <> 'Removed' order by [Microsoft.VSTS.Common.Priority] asc, [System.CreatedDate] desc`
498
- }
499
- return await this . executeWiqlQuery ( instanceId , customQueryString )
487
+ return tracer . trace ( 'AzureDevOpsServerManager.getWorkItems' , async ( ) => {
488
+ let projectFilter = ''
489
+ if ( projectKeyFilters && projectKeyFilters . length > 0 ) {
490
+ projectKeyFilters . forEach ( ( projectKey , idx ) => {
491
+ if ( idx === 0 ) projectFilter = `AND ( [System.TeamProject] = '${ projectKey } '`
492
+ else projectFilter += ` OR [System.TeamProject] = '${ projectKey } '`
493
+ } )
494
+ projectFilter += ` )`
495
+ }
496
+ let customQueryString = ''
497
+ if ( isWIQL )
498
+ customQueryString = queryString
499
+ ? `Select [System.Id], [System.Title], [System.State] From WorkItems Where ${ queryString } ${ projectFilter } `
500
+ : `Select [System.Id], [System.Title], [System.State] From WorkItems Where [System.WorkItemType] IN('User Story', 'Task', 'Issue', 'Bug', 'Feature', 'Epic') AND [State] <> 'Closed' AND [State] <> 'Removed' order by [Microsoft.VSTS.Common.Priority] asc, [System.CreatedDate] desc`
501
+ else {
502
+ const queryFilter = queryString ? `AND [System.Title] contains '${ queryString } '` : ''
503
+ customQueryString = `Select [System.Id], [System.Title], [System.State] From WorkItems Where [System.WorkItemType] IN('User Story', 'Task', 'Issue', 'Bug', 'Feature', 'Epic') AND [State] <> 'Closed' ${ queryFilter } ${ projectFilter } AND [State] <> 'Removed' order by [Microsoft.VSTS.Common.Priority] asc, [System.CreatedDate] desc`
504
+ }
505
+ return await this . executeWiqlQuery ( instanceId , customQueryString )
506
+ } )
500
507
}
501
508
502
509
async getAllUserWorkItems (
503
510
queryString : string | null ,
504
511
projectKeyFilters : string [ ] | null ,
505
512
isWIQL : boolean
506
513
) {
507
- const allWorkItems = [ ] as WorkItem [ ]
508
- let firstError : Error | undefined
509
-
510
- const meResult = await this . getMe ( )
511
- const { error : meError , azureDevOpsUser} = meResult
512
- if ( ! ! meError || ! azureDevOpsUser ) return { error : meError , projects : null }
513
-
514
- const { id} = azureDevOpsUser
515
- const { error : accessibleError , accessibleOrgs} = await this . getAccessibleOrgs ( id )
516
- if ( ! ! accessibleError ) return { error : accessibleError , projects : null }
517
-
518
- for ( const resource of accessibleOrgs ) {
519
- const { accountName} = resource
520
- const instanceId = `dev.azure.com/${ accountName } `
521
- const { error : workItemsError , workItems} = await this . getWorkItems (
522
- instanceId ,
523
- queryString ,
524
- projectKeyFilters ,
525
- isWIQL
526
- )
527
- if ( ! ! workItemsError ) {
528
- if ( ! firstError ) {
529
- firstError = workItemsError
530
- }
531
- }
532
- if ( ! ! workItems ) {
533
- const resturnedIds = workItems . map ( ( workItem ) => workItem . id )
534
- if ( resturnedIds . length > 0 ) {
535
- const { error : fullWorkItemsError , workItems : fullWorkItems } = await this . getWorkItemData (
514
+ return tracer . trace ( 'AzureDevOpsServerManager.getAllUserWorkItems' , async ( ) => {
515
+ const allWorkItems = [ ] as WorkItem [ ]
516
+ let firstError : Error | undefined
517
+
518
+ const meResult = await this . getMe ( )
519
+ const { error : meError , azureDevOpsUser} = meResult
520
+ if ( ! ! meError || ! azureDevOpsUser ) return { error : meError , projects : null }
521
+
522
+ const { id} = azureDevOpsUser
523
+ const { error : accessibleError , accessibleOrgs} = await this . getAccessibleOrgs ( id )
524
+ if ( ! ! accessibleError ) return { error : accessibleError , projects : null }
525
+
526
+ await Promise . allSettled (
527
+ accessibleOrgs . map ( async ( resource ) => {
528
+ const { accountName} = resource
529
+ const instanceId = `dev.azure.com/${ accountName } `
530
+ const { error : workItemsError , workItems} = await this . getWorkItems (
536
531
instanceId ,
537
- resturnedIds
532
+ queryString ,
533
+ projectKeyFilters ,
534
+ isWIQL
538
535
)
539
- if ( ! ! fullWorkItemsError ) {
536
+ if ( ! ! workItemsError ) {
540
537
if ( ! firstError ) {
541
- firstError = fullWorkItemsError
538
+ firstError = workItemsError
542
539
}
543
- } else {
544
- allWorkItems . push ( ...fullWorkItems )
545
540
}
546
- }
547
- }
548
- }
549
- return { error : firstError , workItems : allWorkItems }
541
+ if ( ! ! workItems ) {
542
+ const resturnedIds = workItems . map ( ( workItem ) => workItem . id )
543
+ if ( resturnedIds . length > 0 ) {
544
+ const { error : fullWorkItemsError , workItems : fullWorkItems } =
545
+ await this . getWorkItemData ( instanceId , resturnedIds )
546
+ if ( ! ! fullWorkItemsError ) {
547
+ if ( ! firstError ) {
548
+ firstError = fullWorkItemsError
549
+ }
550
+ } else {
551
+ allWorkItems . push ( ...fullWorkItems )
552
+ }
553
+ }
554
+ }
555
+ } )
556
+ )
557
+ return { error : firstError , workItems : allWorkItems }
558
+ } )
550
559
}
551
560
552
561
async getMe ( ) {
@@ -567,28 +576,30 @@ class AzureDevOpsServerManager implements TaskIntegrationManager {
567
576
}
568
577
569
578
async getAllUserProjects ( ) {
570
- const teamProjectReferences = [ ] as TeamProjectReference [ ]
571
- let firstError : Error | undefined
572
- const meResult = await this . getMe ( )
573
- const { error : meError , azureDevOpsUser} = meResult
574
- if ( ! ! meError || ! azureDevOpsUser ) return { error : meError , projects : null }
575
-
576
- const { id} = azureDevOpsUser
577
- const { error : accessibleError , accessibleOrgs} = await this . getAccessibleOrgs ( id )
578
- if ( ! ! accessibleError ) return { error : accessibleError , projects : null }
579
-
580
- for ( const resource of accessibleOrgs ) {
581
- const { error : accountProjectsError , accountProjects} = await this . getAccountProjects (
582
- resource . accountName
583
- )
584
- if ( ! ! accountProjectsError && ! firstError ) {
585
- firstError = accountProjectsError
586
- break
587
- } else {
588
- teamProjectReferences . push ( ...accountProjects )
579
+ return tracer . trace ( 'AzureDevOpsServerManager.getAllUserProjects' , async ( ) => {
580
+ const teamProjectReferences = [ ] as TeamProjectReference [ ]
581
+ let firstError : Error | undefined
582
+ const meResult = await this . getMe ( )
583
+ const { error : meError , azureDevOpsUser} = meResult
584
+ if ( ! ! meError || ! azureDevOpsUser ) return { error : meError , projects : null }
585
+
586
+ const { id} = azureDevOpsUser
587
+ const { error : accessibleError , accessibleOrgs} = await this . getAccessibleOrgs ( id )
588
+ if ( ! ! accessibleError ) return { error : accessibleError , projects : null }
589
+
590
+ for ( const resource of accessibleOrgs ) {
591
+ const { error : accountProjectsError , accountProjects} = await this . getAccountProjects (
592
+ resource . accountName
593
+ )
594
+ if ( ! ! accountProjectsError && ! firstError ) {
595
+ firstError = accountProjectsError
596
+ break
597
+ } else {
598
+ teamProjectReferences . push ( ...accountProjects )
599
+ }
589
600
}
590
- }
591
- return { error : undefined , projects : teamProjectReferences }
601
+ return { error : undefined , projects : teamProjectReferences }
602
+ } )
592
603
}
593
604
594
605
private async getProjectProperties ( instanceId : string , projectId : string ) {
@@ -603,39 +614,43 @@ class AzureDevOpsServerManager implements TaskIntegrationManager {
603
614
}
604
615
605
616
async getProjectProcessTemplate ( instanceId : string , projectId : string ) {
606
- let firstError : Error | undefined
607
- const result = await this . getProjectProperties ( instanceId , projectId )
608
- if ( result . error ) {
609
- firstError = result . error
610
- }
611
- const processTemplateProperty = result . projectProperties . value [ 0 ]
612
- if ( processTemplateProperty ?. name !== 'System.CurrentProcessTemplateId' ) {
613
- return { error : firstError , projectTemplate : '' }
614
- }
615
- const processTemplateDetailsResult = await this . getProcessTemplate (
616
- instanceId ,
617
- processTemplateProperty ?. value
618
- )
619
- if ( processTemplateDetailsResult . error ) {
620
- if ( ! firstError ) {
621
- firstError = processTemplateDetailsResult . error
617
+ return tracer . trace ( 'AzureDevOpsServerManager.getProjectProcessTemplate' , async ( ) => {
618
+ let firstError : Error | undefined
619
+ const result = await this . getProjectProperties ( instanceId , projectId )
620
+ if ( result . error ) {
621
+ firstError = result . error
622
622
}
623
- }
624
- return { error : firstError , projectTemplate : processTemplateDetailsResult . process }
623
+ const processTemplateProperty = result . projectProperties . value [ 0 ]
624
+ if ( processTemplateProperty ?. name !== 'System.CurrentProcessTemplateId' ) {
625
+ return { error : firstError , projectTemplate : '' }
626
+ }
627
+ const processTemplateDetailsResult = await this . getProcessTemplate (
628
+ instanceId ,
629
+ processTemplateProperty ?. value
630
+ )
631
+ if ( processTemplateDetailsResult . error ) {
632
+ if ( ! firstError ) {
633
+ firstError = processTemplateDetailsResult . error
634
+ }
635
+ }
636
+ return { error : firstError , projectTemplate : processTemplateDetailsResult . process }
637
+ } )
625
638
}
626
639
627
640
async getProcessTemplate ( instanceId : string , processId : string ) {
628
- let firstError : Error | undefined
629
- const uri = `https://${ instanceId } /_apis/process/processes/${ processId } ?api-version=6.0`
630
- const result = await this . get < Process > ( uri )
631
- const unknownProcessErrorCode = 'VS402362'
632
- if ( result instanceof Error ) {
633
- if ( result . message . includes ( unknownProcessErrorCode , 0 ) ) {
634
- return { error : firstError , process : 'Basic' }
641
+ return tracer . trace ( 'AzureDevOpsServerManager.getProcessTemplate' , async ( ) => {
642
+ let firstError : Error | undefined
643
+ const uri = `https://${ instanceId } /_apis/process/processes/${ processId } ?api-version=6.0`
644
+ const result = await this . get < Process > ( uri )
645
+ const unknownProcessErrorCode = 'VS402362'
646
+ if ( result instanceof Error ) {
647
+ if ( result . message . includes ( unknownProcessErrorCode , 0 ) ) {
648
+ return { error : firstError , process : 'Basic' }
649
+ }
650
+ firstError = result
635
651
}
636
- firstError = result
637
- }
638
- return { error : firstError , process : result . name }
652
+ return { error : firstError , process : result . name }
653
+ } )
639
654
}
640
655
641
656
async getProject ( instanceId : string , projectId : string ) {
0 commit comments