From f4a21bda0e1d349b70e37630a0165a411c797468 Mon Sep 17 00:00:00 2001 From: Leon Zolati Date: Wed, 14 Jun 2023 13:39:54 +1000 Subject: [PATCH] IE-229 + bug fix: fixed the issue of subtasks worklogs not being accounted for --- lib/src/services/jira.test.ts | 5 ++- lib/src/services/jira.ts | 41 +++++++++++++++++++----- lib/src/services/jira_api.ts | 20 +++++++++++- lib/src/services/test_data/issue_data.ts | 3 +- 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/lib/src/services/jira.test.ts b/lib/src/services/jira.test.ts index 4eb87a6..ec5067e 100644 --- a/lib/src/services/jira.test.ts +++ b/lib/src/services/jira.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable functional/prefer-immutable-types */ import { mostRecentIssueComment, mostRecentIssueTransition, @@ -181,7 +182,7 @@ describe("finding the most recent work date", () => { // Given an issue. // When the time it was last worked is found. - const lastWorked = issueLastWorked(issue); + const lastWorked = issueLastWorked(issue, []); // Then it should match the expected value. expect(lastWorked).toEqual(expected); @@ -312,6 +313,7 @@ describe("enhancing issues", () => { // When it is enhanced const enhanced = enhancedIssue( issue, + [], "viewlink", fieldName, "not_reason", @@ -343,6 +345,7 @@ describe("enhancing issues", () => { // When it is enhanced const enhanced = enhancedIssue( issue, + [], "viewlink", "not_quality", fieldName, diff --git a/lib/src/services/jira.ts b/lib/src/services/jira.ts index 5d06da8..d3d06b8 100644 --- a/lib/src/services/jira.ts +++ b/lib/src/services/jira.ts @@ -1,4 +1,5 @@ -/* eslint functional/prefer-immutable-types: ["error", { "enforcement": "ReadonlyDeep" }] */ +/* eslint-disable functional/type-declaration-immutability */ +/* eslint-disable functional/prefer-immutable-types */ /* eslint-disable spellcheck/spell-checker */ import * as T from "io-ts"; import * as ITT from "io-ts-types"; @@ -152,6 +153,12 @@ export const BaseIssue = T.readonly( ) ), duedate: nullOrMissingToUndefined(readonlyDateFromDate), + subtasks: T.readonlyArray( + T.type({ + id: T.string, + key: T.string, + }) + ), }) ), T.readonly( @@ -442,12 +449,26 @@ export const mostRecentIssueComment = ( * @returns the most recent worklog, or undefined if no work has been logged. */ export const mostRecentIssueWorklog = ( - issue: Issue + issue: Issue, + issues: readonly Issue[] ): IssueWorklog | undefined => { - const worklogs = - issue.fields.worklog === undefined ? [] : issue.fields.worklog.worklogs; + const subtaskWorklogs = issue.fields.subtasks.reduce( + (acc: IssueWorklog[], subtask) => { + const subtaskIssue = issues.find( + (subtaskIssue) => subtaskIssue.key === subtask.key + ); + const work = subtaskIssue?.fields.worklog?.worklogs; + + return work === undefined ? acc : acc.concat(work); + }, + [] + ); - return [...worklogs].sort((a, b) => + const allWorklogs: IssueWorklog[] = ( + issue.fields.worklog?.worklogs ?? [] + ).concat(subtaskWorklogs); + + return [...allWorklogs].sort((a, b) => compareDesc(a.started.valueOf(), b.started.valueOf()) )[0]; }; @@ -458,12 +479,15 @@ export const mostRecentIssueWorklog = ( * @param issue the issue. * @returns the time that the issue was last worked, or undefined if it has never been worked. */ -export const issueLastWorked = (issue: Issue): ReadonlyDate | undefined => { +export const issueLastWorked = ( + issue: Issue, + issues: readonly Issue[] +): ReadonlyDate | undefined => { const mostRecentTransition = mostRecentIssueTransition(issue); const mostRecentComment = mostRecentIssueComment(issue); - const mostRecentWorklog = mostRecentIssueWorklog(issue); + const mostRecentWorklog = mostRecentIssueWorklog(issue, issues); return [ mostRecentTransition?.created, @@ -476,6 +500,7 @@ export const issueLastWorked = (issue: Issue): ReadonlyDate | undefined => { export const enhancedIssue = ( issue: Issue, + issues: readonly Issue[], viewLink: string, qualityFieldName: string, qualityReasonFieldName: string, @@ -488,7 +513,7 @@ export const enhancedIssue = ( const released = issue.fields.fixVersions.some((version) => version.released); - const lastWorked = issueLastWorked(issue); + const lastWorked = issueLastWorked(issue, issues); // eslint-disable-next-line @typescript-eslint/consistent-type-assertions const quality = issue.fields[qualityFieldName] as string | undefined; diff --git a/lib/src/services/jira_api.ts b/lib/src/services/jira_api.ts index 9178497..f0f534b 100644 --- a/lib/src/services/jira_api.ts +++ b/lib/src/services/jira_api.ts @@ -1,3 +1,4 @@ +/* eslint-disable functional/prefer-immutable-types */ /* eslint functional/prefer-immutable-types: ["error", { "enforcement": "ReadonlyDeep" }] */ /* eslint-disable spellcheck/spell-checker */ import { Either } from "fp-ts/lib/Either"; @@ -628,6 +629,7 @@ const jiraClient = ( qualityReasonField: string, customFieldNames: readonly string[], descriptionFields: ReadonlyRecord + // eslint-disable-next-line sonarjs/cognitive-complexity ): Promise> => { const fetchIssues = TE.tryCatch( // eslint-disable-next-line functional/functional-parameters, functional/prefer-immutable-types @@ -728,6 +730,7 @@ const jiraClient = ( ); return enhancedIssue( issue, + issues, issueLink(issue), qualityField, qualityReasonField, @@ -782,10 +785,25 @@ const jiraClient = ( compareDesc(w1.started.valueOf(), w2.started.valueOf()) )[0]; + const relevantKeys: string[] = mostRecentWorklogLoaded + ? [] + : issue.fields.subtasks + .reduce((acc: string[], cur) => acc.concat([cur.key]), []) + .concat([issue.key]); + + const worklogs: TE.TaskEither[] = + relevantKeys.map((key) => fetchMostRecentWorklogs(key)); + + const worklog: TE.TaskEither = pipe( + worklogs, + TE.sequenceArray, + TE.map((x): readonly IssueWorklog[] => x.flat()) + ); + return pipe( mostRecentWorklogLoaded ? TE.right(issue.fields.worklog.worklogs) - : fetchMostRecentWorklogs(issue.key), + : worklog, // eslint-disable-next-line functional/prefer-immutable-types TE.map((worklogs) => ({ ...issue, diff --git a/lib/src/services/test_data/issue_data.ts b/lib/src/services/test_data/issue_data.ts index 664a1a1..622a849 100644 --- a/lib/src/services/test_data/issue_data.ts +++ b/lib/src/services/test_data/issue_data.ts @@ -1,4 +1,4 @@ -/* eslint functional/prefer-immutable-types: ["error", { "enforcement": "ReadonlyDeep" }] */ +/* eslint-disable functional/prefer-immutable-types */ /* eslint-disable spellcheck/spell-checker */ import type { EnhancedIssue, Issue, IssueWorklog } from "../jira"; import { readonlyDate } from "readonly-types"; @@ -42,6 +42,7 @@ export const issue: Issue = { total: 0, startAt: 0, }, + subtasks: [], duedate: undefined, worklog: { worklogs: [],