88namespace Microsoft . OneFuzz . Service ;
99
1010public interface IAdo {
11- public Async . Task NotifyAdo ( AdoTemplate config , Container container , string filename , IReport reportable , bool isLastRetryAttempt , Guid notificationId ) ;
11+ public Async . Task < OneFuzzResultVoid > NotifyAdo ( AdoTemplate config , Container container , IReport reportable , bool isLastRetryAttempt , Guid notificationId ) ;
1212}
1313
1414public class Ado : NotificationsBase , IAdo {
1515 public Ado ( ILogTracer logTracer , IOnefuzzContext context ) : base ( logTracer , context ) {
1616 }
1717
18- public async Async . Task NotifyAdo ( AdoTemplate config , Container container , string filename , IReport reportable , bool isLastRetryAttempt , Guid notificationId ) {
18+ public async Async . Task < OneFuzzResultVoid > NotifyAdo ( AdoTemplate config , Container container , IReport reportable , bool isLastRetryAttempt , Guid notificationId ) {
19+ var filename = reportable . FileName ( ) ;
1920 if ( reportable is RegressionReport ) {
2021 _logTracer . Info ( $ "ado integration does not support regression report. container:{ container : Tag:Container} filename:{ filename : Tag:Filename} ") ;
21- return ;
22+ return OneFuzzResultVoid . Ok ;
2223 }
2324
2425 var report = ( Report ) reportable ;
@@ -44,8 +45,11 @@ public async Async.Task NotifyAdo(AdoTemplate config, Container container, strin
4445 } else {
4546 _logTracer . WithTags ( notificationInfo ) . Exception ( e , $ "Failed to process ado notification") ;
4647 await LogFailedNotification ( report , e , notificationId ) ;
48+ return OneFuzzResultVoid . Error ( ErrorCode . NOTIFICATION_FAILURE ,
49+ $ "Failed to process ado notification : exception: { e } ") ;
4750 }
4851 }
52+ return OneFuzzResultVoid . Ok ;
4953 }
5054
5155 private static bool IsTransient ( Exception e ) {
@@ -205,7 +209,7 @@ public async IAsyncEnumerable<WorkItem> ExistingWorkItems((string, string)[] not
205209 }
206210 }
207211
208- var query = "select [System.Id] from WorkItems" ;
212+ var query = "select [System.Id] from WorkItems order by [System.Id] " ;
209213 if ( parts != null && parts . Any ( ) ) {
210214 query += " where " + string . Join ( " AND " , parts ) ;
211215 }
@@ -331,47 +335,42 @@ private async Async.Task<WorkItem> CreateNew() {
331335 }
332336
333337 public async Async . Task Process ( ( string , string ) [ ] notificationInfo ) {
334- var matchingWorkItems = await ExistingWorkItems ( notificationInfo ) . ToListAsync ( ) ;
335-
336- var nonDuplicateWorkItems = matchingWorkItems
337- . Where ( wi => ! IsADODuplicateWorkItem ( wi ) )
338- . ToList ( ) ;
339-
340- if ( nonDuplicateWorkItems . Count > 1 ) {
341- var nonDuplicateWorkItemIds = nonDuplicateWorkItems . Select ( wi => wi . Id ) ;
342- var matchingWorkItemIds = matchingWorkItems . Select ( wi => wi . Id ) ;
343-
344- var extraTags = new List < ( string , string ) > {
345- ( "NonDuplicateWorkItemIds" , JsonSerializer . Serialize ( nonDuplicateWorkItemIds ) ) ,
346- ( "MatchingWorkItemIds" , JsonSerializer . Serialize ( matchingWorkItemIds ) )
347- } ;
348- extraTags . AddRange ( notificationInfo ) ;
349-
350- _logTracer . WithTags ( extraTags ) . Info ( $ "Found more than 1 matching, non-duplicate work item") ;
351- foreach ( var workItem in nonDuplicateWorkItems ) {
352- _ = await UpdateExisting ( workItem , notificationInfo ) ;
338+ var updated = false ;
339+ WorkItem ? oldestWorkItem = null ;
340+ await foreach ( var workItem in ExistingWorkItems ( notificationInfo ) ) {
341+ // work items are ordered by id, so the oldest one is the first one
342+ oldestWorkItem ??= workItem ;
343+ _logTracer . WithTags ( new List < ( string , string ) > { ( "MatchingWorkItemIds" , $ "{ workItem . Id } ") } ) . Info ( $ "Found matching work item") ;
344+ if ( IsADODuplicateWorkItem ( workItem ) ) {
345+ continue ;
353346 }
354- } else if ( nonDuplicateWorkItems . Count == 1 ) {
355- _ = await UpdateExisting ( nonDuplicateWorkItems . Single ( ) , notificationInfo ) ;
356- } else if ( matchingWorkItems . Any ( ) ) {
357- // We have matching work items but all are duplicates
358- _logTracer . WithTags ( notificationInfo ) . Info ( $ "All matching work items were duplicates, re-opening the oldest one") ;
359- var oldestWorkItem = matchingWorkItems . OrderBy ( wi => wi . Id ) . First ( ) ;
360- var stateChanged = await UpdateExisting ( oldestWorkItem , notificationInfo ) ;
361- if ( stateChanged ) {
362- // add a comment if we re-opened the bug
363- _ = await _client . AddCommentAsync (
364- new CommentCreate ( ) {
365- Text = "This work item was re-opened because OneFuzz could only find related work items that are marked as duplicate."
366- } ,
367- _project ,
368- ( int ) oldestWorkItem . Id ! ) ;
347+ _logTracer . WithTags ( new List < ( string , string ) > { ( "NonDuplicateWorkItemId" , $ "{ workItem . Id } ") } ) . Info ( $ "Found matching non-duplicate work item") ;
348+ _ = await UpdateExisting ( workItem , notificationInfo ) ;
349+ updated = true ;
350+ }
351+
352+ if ( ! updated ) {
353+ if ( oldestWorkItem != null ) {
354+ // We have matching work items but all are duplicates
355+ _logTracer . WithTags ( notificationInfo )
356+ . Info ( $ "All matching work items were duplicates, re-opening the oldest one") ;
357+ var stateChanged = await UpdateExisting ( oldestWorkItem , notificationInfo ) ;
358+ if ( stateChanged ) {
359+ // add a comment if we re-opened the bug
360+ _ = await _client . AddCommentAsync (
361+ new CommentCreate ( ) {
362+ Text =
363+ "This work item was re-opened because OneFuzz could only find related work items that are marked as duplicate."
364+ } ,
365+ _project ,
366+ ( int ) oldestWorkItem . Id ! ) ;
367+ }
368+ } else {
369+ // We never saw a work item like this before, it must be new
370+ var entry = await CreateNew ( ) ;
371+ var adoEventType = "AdoNewItem" ;
372+ _logTracer . WithTags ( notificationInfo ) . Event ( $ "{ adoEventType } { entry . Id : Tag:WorkItemId} ") ;
369373 }
370- } else {
371- // We never saw a work item like this before, it must be new
372- var entry = await CreateNew ( ) ;
373- var adoEventType = "AdoNewItem" ;
374- _logTracer . WithTags ( notificationInfo ) . Event ( $ "{ adoEventType } { entry . Id : Tag:WorkItemId} ") ;
375374 }
376375 }
377376
0 commit comments