Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 35 additions & 16 deletions packages/functions/transform/src/merge-request-metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -540,25 +540,44 @@ function setupTimeline(timelineEvents: TimelineEventData[], notes: MergeRequestN

type calcTimelineArgs = {
authorExternalId: extract.MergeRequest['authorExternalId'],
createdAt: extract.MergeRequest['createdAt'] | null,
}

export function calculateTimeline(timelineMapKeys: TimelineMapKey[], timelineMap: Map<TimelineMapKey, MergeRequestNoteData | TimelineEventData>, { authorExternalId }: calcTimelineArgs) {

const committedEvents = timelineMapKeys.filter(key => key.type === 'committed');
committedEvents.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());

const firstCommitEvent = committedEvents[0] || null;
const lastCommitEvent = committedEvents[committedEvents.length - 1] || null;
function getStartedCodingAt(timelineMapKeys: TimelineMapKey[], createdAt: Date | null) {
const firstCommitEvent = timelineMapKeys.find(key => key.type === 'committed');

if (!firstCommitEvent) return null;

if (!createdAt) {
return firstCommitEvent.timestamp;
}

return firstCommitEvent.timestamp < createdAt ? firstCommitEvent.timestamp : createdAt;
}

const startedCodingAt = firstCommitEvent ? firstCommitEvent.timestamp : null;
function getMergedAt(timelineMapKeys: TimelineMapKey[]) {
const firstMergedEvent = timelineMapKeys.find(key => key.type === 'merged');

const mergedEvents = timelineMapKeys.filter(key => key.type === 'merged');
mergedEvents.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
if (firstMergedEvent) {
return firstMergedEvent.timestamp;
}

return null;
}

export function calculateTimeline(timelineMapKeys: TimelineMapKey[], timelineMap: Map<TimelineMapKey, MergeRequestNoteData | TimelineEventData>, { authorExternalId, createdAt }: calcTimelineArgs) {

const sortedTimelineMapKeys = [...timelineMapKeys]
sortedTimelineMapKeys.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());

const committedEvents = sortedTimelineMapKeys.filter(key => key.type === 'committed');
const lastCommitEvent = committedEvents[committedEvents.length - 1] || null;

const mergedAt = mergedEvents[0]?.timestamp || null;
const startedCodingAt = getStartedCodingAt(committedEvents, createdAt);
const mergedAt = getMergedAt(sortedTimelineMapKeys);

const readyForReviewEvents = timelineMapKeys.filter(key => key.type === 'ready_for_review' || key.type === 'review_requested');
readyForReviewEvents.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
const readyForReviewEvents = sortedTimelineMapKeys.filter(key => key.type === 'ready_for_review' || key.type === 'review_requested');
const lastReadyForReviewEvent = readyForReviewEvents[readyForReviewEvents.length - 1] || null;

const startedPickupAt = (() => {
Expand All @@ -567,8 +586,7 @@ export function calculateTimeline(timelineMapKeys: TimelineMapKey[], timelineMap
}
if (lastReadyForReviewEvent === null && lastCommitEvent) {
// problematic code: everything below is problematic
const reviewedEventsBeforeLastCommitEvent = timelineMapKeys.filter(key => key.type === 'reviewed' && key.timestamp < lastCommitEvent.timestamp);
reviewedEventsBeforeLastCommitEvent.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
const reviewedEventsBeforeLastCommitEvent = sortedTimelineMapKeys.filter(key => key.type === 'reviewed' && key.timestamp < lastCommitEvent.timestamp);
const firstReviewedEventBeforeLastCommitEvent = reviewedEventsBeforeLastCommitEvent[0];
if (firstReviewedEventBeforeLastCommitEvent) {
return [...committedEvents].reverse().find(event => event.timestamp < firstReviewedEventBeforeLastCommitEvent.timestamp)?.timestamp || null;
Expand All @@ -578,13 +596,12 @@ export function calculateTimeline(timelineMapKeys: TimelineMapKey[], timelineMap
}
if (lastReadyForReviewEvent && lastCommitEvent) {
// problematic code: there could be a commit between last commit and lastReadyForReviewEvent
const reviewedEventsAfterLastReadyForReviewEvent = timelineMapKeys.filter(
const reviewedEventsAfterLastReadyForReviewEvent = sortedTimelineMapKeys.filter(
key =>
key.type === 'reviewed'
&& key.timestamp > lastReadyForReviewEvent.timestamp
&& key.timestamp < lastCommitEvent.timestamp
);
reviewedEventsAfterLastReadyForReviewEvent.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
const firstReviewedEventAfterLastReadyForReviewEvent = reviewedEventsAfterLastReadyForReviewEvent[0]

if (firstReviewedEventAfterLastReadyForReviewEvent) {
Expand Down Expand Up @@ -617,6 +634,7 @@ export function calculateTimeline(timelineMapKeys: TimelineMapKey[], timelineMap
continue;
}

// Edge-case: what if note is before first review event ?
const afterStartedPickupAt = startedPickupAt ? noteEvent.timestamp > startedPickupAt : true;
const beforeMergedEvent = mergedAt ? noteEvent.timestamp < mergedAt : true;
const isAuthorReviewer = eventData.authorExternalId === authorExternalId;
Expand Down Expand Up @@ -674,6 +692,7 @@ function runTimeline(mergeRequestData: MergeRequestData, timelineEvents: Timelin
timelineMapKeys,
timelineMap,
{
createdAt: mergeRequestData.openedAt,
authorExternalId: mergeRequestData.authorExternalId,
});

Expand Down
Loading