@@ -540,25 +540,44 @@ function setupTimeline(timelineEvents: TimelineEventData[], notes: MergeRequestN
540540
541541type calcTimelineArgs = {
542542 authorExternalId : extract . MergeRequest [ 'authorExternalId' ] ,
543+ createdAt : extract . MergeRequest [ 'createdAt' ] | null ,
543544}
544545
545- export function calculateTimeline ( timelineMapKeys : TimelineMapKey [ ] , timelineMap : Map < TimelineMapKey , MergeRequestNoteData | TimelineEventData > , { authorExternalId } : calcTimelineArgs ) {
546-
547- const committedEvents = timelineMapKeys . filter ( key => key . type === 'committed' ) ;
548- committedEvents . sort ( ( a , b ) => a . timestamp . getTime ( ) - b . timestamp . getTime ( ) ) ;
549546
550- const firstCommitEvent = committedEvents [ 0 ] || null ;
551- const lastCommitEvent = committedEvents [ committedEvents . length - 1 ] || null ;
547+ function getStartedCodingAt ( timelineMapKeys : TimelineMapKey [ ] , createdAt : Date | null ) {
548+ const firstCommitEvent = timelineMapKeys . find ( key => key . type === 'committed' ) ;
549+
550+ if ( ! firstCommitEvent ) return null ;
551+
552+ if ( ! createdAt ) {
553+ return firstCommitEvent . timestamp ;
554+ }
555+
556+ return firstCommitEvent . timestamp < createdAt ? firstCommitEvent . timestamp : createdAt ;
557+ }
552558
553- const startedCodingAt = firstCommitEvent ? firstCommitEvent . timestamp : null ;
559+ function getMergedAt ( timelineMapKeys : TimelineMapKey [ ] ) {
560+ const firstMergedEvent = timelineMapKeys . find ( key => key . type === 'merged' ) ;
554561
555- const mergedEvents = timelineMapKeys . filter ( key => key . type === 'merged' ) ;
556- mergedEvents . sort ( ( a , b ) => a . timestamp . getTime ( ) - b . timestamp . getTime ( ) ) ;
562+ if ( firstMergedEvent ) {
563+ return firstMergedEvent . timestamp ;
564+ }
565+
566+ return null ;
567+ }
568+
569+ export function calculateTimeline ( timelineMapKeys : TimelineMapKey [ ] , timelineMap : Map < TimelineMapKey , MergeRequestNoteData | TimelineEventData > , { authorExternalId, createdAt } : calcTimelineArgs ) {
570+
571+ const sortedTimelineMapKeys = [ ...timelineMapKeys ]
572+ sortedTimelineMapKeys . sort ( ( a , b ) => a . timestamp . getTime ( ) - b . timestamp . getTime ( ) ) ;
573+
574+ const committedEvents = sortedTimelineMapKeys . filter ( key => key . type === 'committed' ) ;
575+ const lastCommitEvent = committedEvents [ committedEvents . length - 1 ] || null ;
557576
558- const mergedAt = mergedEvents [ 0 ] ?. timestamp || null ;
577+ const startedCodingAt = getStartedCodingAt ( committedEvents , createdAt ) ;
578+ const mergedAt = getMergedAt ( sortedTimelineMapKeys ) ;
559579
560- const readyForReviewEvents = timelineMapKeys . filter ( key => key . type === 'ready_for_review' || key . type === 'review_requested' ) ;
561- readyForReviewEvents . sort ( ( a , b ) => a . timestamp . getTime ( ) - b . timestamp . getTime ( ) ) ;
580+ const readyForReviewEvents = sortedTimelineMapKeys . filter ( key => key . type === 'ready_for_review' || key . type === 'review_requested' ) ;
562581 const lastReadyForReviewEvent = readyForReviewEvents [ readyForReviewEvents . length - 1 ] || null ;
563582
564583 const startedPickupAt = ( ( ) => {
@@ -567,8 +586,7 @@ export function calculateTimeline(timelineMapKeys: TimelineMapKey[], timelineMap
567586 }
568587 if ( lastReadyForReviewEvent === null && lastCommitEvent ) {
569588 // problematic code: everything below is problematic
570- const reviewedEventsBeforeLastCommitEvent = timelineMapKeys . filter ( key => key . type === 'reviewed' && key . timestamp < lastCommitEvent . timestamp ) ;
571- reviewedEventsBeforeLastCommitEvent . sort ( ( a , b ) => a . timestamp . getTime ( ) - b . timestamp . getTime ( ) ) ;
589+ const reviewedEventsBeforeLastCommitEvent = sortedTimelineMapKeys . filter ( key => key . type === 'reviewed' && key . timestamp < lastCommitEvent . timestamp ) ;
572590 const firstReviewedEventBeforeLastCommitEvent = reviewedEventsBeforeLastCommitEvent [ 0 ] ;
573591 if ( firstReviewedEventBeforeLastCommitEvent ) {
574592 return [ ...committedEvents ] . reverse ( ) . find ( event => event . timestamp < firstReviewedEventBeforeLastCommitEvent . timestamp ) ?. timestamp || null ;
@@ -578,13 +596,12 @@ export function calculateTimeline(timelineMapKeys: TimelineMapKey[], timelineMap
578596 }
579597 if ( lastReadyForReviewEvent && lastCommitEvent ) {
580598 // problematic code: there could be a commit between last commit and lastReadyForReviewEvent
581- const reviewedEventsAfterLastReadyForReviewEvent = timelineMapKeys . filter (
599+ const reviewedEventsAfterLastReadyForReviewEvent = sortedTimelineMapKeys . filter (
582600 key =>
583601 key . type === 'reviewed'
584602 && key . timestamp > lastReadyForReviewEvent . timestamp
585603 && key . timestamp < lastCommitEvent . timestamp
586604 ) ;
587- reviewedEventsAfterLastReadyForReviewEvent . sort ( ( a , b ) => a . timestamp . getTime ( ) - b . timestamp . getTime ( ) ) ;
588605 const firstReviewedEventAfterLastReadyForReviewEvent = reviewedEventsAfterLastReadyForReviewEvent [ 0 ]
589606
590607 if ( firstReviewedEventAfterLastReadyForReviewEvent ) {
@@ -617,6 +634,7 @@ export function calculateTimeline(timelineMapKeys: TimelineMapKey[], timelineMap
617634 continue ;
618635 }
619636
637+ // Edge-case: what if note is before first review event ?
620638 const afterStartedPickupAt = startedPickupAt ? noteEvent . timestamp > startedPickupAt : true ;
621639 const beforeMergedEvent = mergedAt ? noteEvent . timestamp < mergedAt : true ;
622640 const isAuthorReviewer = eventData . authorExternalId === authorExternalId ;
@@ -674,6 +692,7 @@ function runTimeline(mergeRequestData: MergeRequestData, timelineEvents: Timelin
674692 timelineMapKeys ,
675693 timelineMap ,
676694 {
695+ createdAt : mergeRequestData . openedAt ,
677696 authorExternalId : mergeRequestData . authorExternalId ,
678697 } ) ;
679698
0 commit comments