@@ -157,8 +157,28 @@ def get_time_to_first_attention(self, item):
157
157
reaction_dates = [str_to_datetime (reaction ['created_at' ]) for reaction in item ['award_emoji_data' ]
158
158
if item ['author' ]['username' ] != reaction ['user' ]['username' ]]
159
159
reaction_dates .extend (comments_dates )
160
+
160
161
if reaction_dates :
161
162
return min (reaction_dates )
163
+
164
+ return None
165
+
166
+ def get_time_to_merge_request_response (self , item ):
167
+ """Get the first date at which a review was made on the PR by someone
168
+ other than the user who created the PR
169
+ """
170
+ review_dates = []
171
+
172
+ for comment in item ['notes_data' ]:
173
+ # skip comments of the pull request creator
174
+ if item ['author' ]['username' ] == comment ['author' ]['username' ]:
175
+ continue
176
+
177
+ review_dates .append (str_to_datetime (comment ['created_at' ]))
178
+
179
+ if review_dates :
180
+ return min (review_dates )
181
+
162
182
return None
163
183
164
184
def __get_reactions (self , item ):
@@ -266,8 +286,112 @@ def __get_rich_issue(self, item):
266
286
if self .sortinghat :
267
287
item [self .get_field_date ()] = rich_issue [self .get_field_date ()]
268
288
rich_issue .update (self .get_item_sh (item , self .issue_roles ))
289
+
269
290
return rich_issue
270
291
292
+ def __get_rich_merge (self , item ):
293
+ rich_mr = {}
294
+
295
+ self .copy_raw_fields (self .RAW_FIELDS_COPY , item , rich_mr )
296
+ # The real data
297
+ merge_request = item ['data' ]
298
+
299
+ rich_mr ['time_to_close_days' ] = \
300
+ get_time_diff_days (merge_request ['created_at' ], merge_request ['closed_at' ])
301
+
302
+ if merge_request ['state' ] != 'closed' :
303
+ rich_mr ['time_open_days' ] = \
304
+ get_time_diff_days (pull_request ['created_at' ], datetime_utcnow ().replace (tzinfo = None ))
305
+ else :
306
+ rich_mr ['time_open_days' ] = rich_mr ['time_to_close_days' ]
307
+
308
+ rich_mr ['user_login' ] = merge_request ['author' ]['username' ]
309
+
310
+ user = merge_request .get ('author' , None )
311
+ if user is not None and user :
312
+ rich_mr ['user_name' ] = user ['name' ]
313
+ rich_mr ['author_name' ] = user ['name' ]
314
+ rich_mr ["user_domain" ] = self .get_email_domain (user ['email' ]) if user ['email' ] else None
315
+ rich_mr ['user_org' ] = user .get ('company' , None )
316
+ rich_mr ['user_location' ] = user .get ('location' , None )
317
+ rich_mr ['user_geolocation' ] = None
318
+ else :
319
+ rich_mr ['user_name' ] = None
320
+ rich_mr ["user_domain" ] = None
321
+ rich_mr ['user_org' ] = None
322
+ rich_mr ['user_location' ] = None
323
+ rich_mr ['user_geolocation' ] = None
324
+ rich_mr ['author_name' ] = None
325
+
326
+ merged_by = merge_request .get ('merged_by' , None )
327
+ if merged_by is not None and merged_by :
328
+ rich_mr ['merge_author_login' ] = merged_by ['login' ]
329
+ rich_mr ['merge_author_name' ] = merged_by ['name' ]
330
+ rich_mr ["merge_author_domain" ] = self .get_email_domain (merged_by ['email' ]) if merged_by ['email' ] else None
331
+ rich_mr ['merge_author_org' ] = merged_by .get ('company' , None )
332
+ rich_mr ['merge_author_location' ] = merged_by .get ('location' , None )
333
+ rich_mr ['merge_author_geolocation' ] = None
334
+ else :
335
+ rich_mr ['merge_author_name' ] = None
336
+ rich_mr ['merge_author_login' ] = None
337
+ rich_mr ["merge_author_domain" ] = None
338
+ rich_mr ['merge_author_org' ] = None
339
+ rich_mr ['merge_author_location' ] = None
340
+ rich_mr ['merge_author_geolocation' ] = None
341
+
342
+ rich_mr ['id' ] = merge_request ['id' ]
343
+ rich_mr ['merge_id' ] = merge_request ['id' ]
344
+ rich_mr ['merge_id_in_repo' ] = merge_request ['web_url' ].split ("/" )[- 1 ]
345
+ rich_mr ['repository' ] = self .get_project_repository (rich_mr )
346
+ rich_mr ['merge_title' ] = merge_request ['title' ]
347
+ rich_mr ['merge_title_analyzed' ] = merge_request ['title' ]
348
+ rich_mr ['merge_state' ] = merge_request ['state' ]
349
+ rich_mr ['merge_created_at' ] = merge_request ['created_at' ]
350
+ rich_mr ['merge_updated_at' ] = merge_request ['updated_at' ]
351
+ rich_mr ['merge_status' ] = merge_request ['merge_status' ]
352
+ rich_mr ['merge_merged_at' ] = merge_request ['merged_at' ]
353
+ rich_mr ['merge_closed_at' ] = merge_request ['closed_at' ]
354
+ rich_mr ['url' ] = merge_request ['web_url' ]
355
+ rich_mr ['merge_url' ] = merge_request ['web_url' ]
356
+
357
+ # extract reactions and add it to enriched item
358
+ # rich_mr.update(self.__get_reactions(merge_request))
359
+
360
+ rich_mr ['merge_labels' ] = merge_request ['labels' ]
361
+ rich_mr ['item_type' ] = MERGE_TYPE
362
+
363
+ rich_mr ['gitlab_repo' ] = rich_mr ['repository' ].replace (GITLAB , '' )
364
+ rich_mr ['gitlab_repo' ] = re .sub ('.git$' , '' , rich_mr ['gitlab_repo' ])
365
+
366
+ # GMD code development metrics
367
+ rich_mr ['code_merge_duration' ] = get_time_diff_days (merge_request ['created_at' ],
368
+ merge_request ['merged_at' ])
369
+ rich_mr ['num_versions' ] = len (merge_request ['versions_data' ])
370
+
371
+ rich_mr ['time_to_merge_request_response' ] = None
372
+ if merge_request ['notes_data' ] != 0 :
373
+ min_review_date = self .get_time_to_merge_request_response (pull_request )
374
+ rich_pr ['time_to_merge_request_response' ] = \
375
+ get_time_diff_days (str_to_datetime (pull_request ['created_at' ]), min_review_date )
376
+
377
+ if self .prjs_map :
378
+ rich_mr .update (self .get_item_project (rich_mr ))
379
+
380
+ if 'project' in item :
381
+ rich_mr ['project' ] = item ['project' ]
382
+
383
+ rich_mr .update (self .get_grimoire_fields (merge_request ['created_at' ], MERGE_TYPE ))
384
+
385
+ # due to backtrack compatibility, `is_gitlabcomments_*` is replaced with `is_gitlab_*`
386
+ rich_mr .pop ('is_gitlabcomments_{}' .format (MERGE_TYPE ))
387
+ rich_mr ['is_gitlab_{}' .format (MERGE_TYPE )] = 1
388
+
389
+ if self .sortinghat :
390
+ item [self .get_field_date ()] = rich_mr [self .get_field_date ()]
391
+ rich_mr .update (self .get_item_sh (item , self .mr_roles ))
392
+
393
+ return rich_mr
394
+
271
395
@metadata
272
396
def get_rich_item (self , item ):
273
397
rich_item = {}
@@ -318,9 +442,70 @@ def get_rich_issue_comments(self, comments, eitem):
318
442
319
443
ecomment ['comment_updated_at' ] = comment ['updated_at' ]
320
444
445
+ # Add id info to allow to coexistence of items of different types in the same index
446
+ ecomment ['id' ] = '{}_review_comment_{}' .format (eitem ['id' ], comment ['id' ])
447
+ ecomment .update (self .get_grimoire_fields (comment ['updated_at' ], ISSUE_COMMENT_TYPE ))
448
+
449
+ # due to backtrack compatibility, `is_gitlabcomments_*` is replaced with `is_gitlab_*`
450
+ ecomment .pop ('is_gitlabcomments_{}' .format (ISSUE_COMMENT_TYPE ))
451
+ ecomment ['is_gitlab_{}' .format (ISSUE_COMMENT_TYPE )] = 1
452
+ ecomment ['is_gitlab_comment' ] = 1
453
+
454
+ if self .sortinghat :
455
+ ecomment .update (self .get_item_sh (comment , self .comment_roles , 'updated_at' ))
456
+
457
+ if self .prjs_map :
458
+ ecomment .update (self .get_item_project (ecomment ))
459
+
460
+ if 'project' in eitem :
461
+ ecomment ['project' ] = eitem ['project' ]
462
+
463
+ self .add_repository_labels (ecomment )
464
+ self .add_metadata_filter_raw (ecomment )
465
+ self .add_gelk_metadata (ecomment )
466
+
467
+ ecomments .append (ecomment )
468
+
469
+ return ecomments
470
+
471
+ def get_rich_merge_reviews (self , comments , eitem ):
472
+ ecomments = []
473
+
474
+ for comment in comments :
475
+ ecomment = {}
476
+
477
+ self .copy_raw_fields (self .RAW_FIELDS_COPY , eitem , ecomment )
478
+ # Copy data from the enriched pull
479
+ ecomment ['merge_labels' ] = eitem ['merge_labels' ]
480
+ ecomment ['merge_id' ] = eitem ['merge_id' ]
481
+ ecomment ['merge_id_in_repo' ] = eitem ['merge_id_in_repo' ]
482
+ ecomment ['merge_title' ] = eitem ['merge_title' ]
483
+ ecomment ['merge_url' ] = eitem ['merge_url' ]
484
+ ecomment ['merge_state' ] = eitem ['merge_state' ]
485
+ ecomment ['merge_created_at' ] = eitem ['merge_created_at' ]
486
+ ecomment ['merge_updated_at' ] = eitem ['merge_updated_at' ]
487
+ ecomment ['merge_merged_at' ] = eitem ['merge_merged_at' ]
488
+ ecomment ['merge_closed_at' ] = eitem ['merge_closed_at' ]
489
+ ecomment ['merge_status' ] = eitem ['merge_status' ]
490
+ ecomment ['gitlab_repo' ] = eitem ['gitlab_repo' ]
491
+ ecomment ['repository' ] = eitem ['repository' ]
492
+ ecomment ['item_type' ] = COMMENT_TYPE
493
+ ecomment ['sub_type' ] = REVIEW_COMMENT_TYPE
494
+
495
+ # Copy data from the raw comment
496
+ ecomment ['body' ] = comment ['body' ][:self .KEYWORD_MAX_LENGTH ]
497
+ ecomment ['body_analyzed' ] = comment ['body' ]
498
+ # ecomment['url'] = comment['html_url']
499
+
500
+ # extract reactions and add it to enriched item
501
+ # ecomment.update(self.__get_reactions(comment))
502
+
503
+ ecomment ['comment_updated_at' ] = comment ['updated_at' ]
504
+
321
505
# Add id info to allow to coexistence of items of different types in the same index
322
506
ecomment ['id' ] = '{}_review_comment_{}' .format (eitem ['id' ], comment ['id' ])
323
507
ecomment .update (self .get_grimoire_fields (comment ['updated_at' ], REVIEW_COMMENT_TYPE ))
508
+
324
509
# due to backtrack compatibility, `is_gitlabcomments_*` is replaced with `is_gitlab_*`
325
510
ecomment .pop ('is_gitlabcomments_{}' .format (REVIEW_COMMENT_TYPE ))
326
511
ecomment ['is_gitlab_{}' .format (REVIEW_COMMENT_TYPE )] = 1
@@ -353,6 +538,16 @@ def enrich_issue(self, item, eitem):
353
538
354
539
return eitems
355
540
541
+ def enrich_merge (self , item , eitem ):
542
+ eitems = []
543
+
544
+ comments = item ['data' ].get ('notes_data' , [])
545
+ if comments :
546
+ rich_item_comments = self .get_rich_merge_reviews (comments , eitem )
547
+ eitems .extend (rich_item_comments )
548
+
549
+ return eitems
550
+
356
551
def enrich_items (self , ocean_backend ):
357
552
items_to_enrich = []
358
553
num_items = 0
0 commit comments