mirror of
https://github.com/harness/drone.git
synced 2025-05-31 11:43:15 +00:00
fix: [CODE-2493] codeowners status in PR overview page (#2833)
* fix: [CODE-2493] resolve comments * fix: [CODE-2493] fix codeowners status in PR overview page
This commit is contained in:
parent
9a12d72a10
commit
32e817888a
@ -37,6 +37,7 @@ export interface StringsMap {
|
|||||||
applyChanges: string
|
applyChanges: string
|
||||||
approve: string
|
approve: string
|
||||||
approved: string
|
approved: string
|
||||||
|
approvedBy: string
|
||||||
artifacts: string
|
artifacts: string
|
||||||
ascending: string
|
ascending: string
|
||||||
assignPeople: string
|
assignPeople: string
|
||||||
@ -156,6 +157,7 @@ export interface StringsMap {
|
|||||||
changeRole: string
|
changeRole: string
|
||||||
changedSinceLastView: string
|
changedSinceLastView: string
|
||||||
changes: string
|
changes: string
|
||||||
|
changesRequested: string
|
||||||
changesRequestedBy: string
|
changesRequestedBy: string
|
||||||
'changesSection.approvalPending': string
|
'changesSection.approvalPending': string
|
||||||
'changesSection.changesAppByRev': string
|
'changesSection.changesAppByRev': string
|
||||||
@ -665,6 +667,8 @@ export interface StringsMap {
|
|||||||
optionalExtendedDescription: string
|
optionalExtendedDescription: string
|
||||||
overview: string
|
overview: string
|
||||||
owner: string
|
owner: string
|
||||||
|
owners: string
|
||||||
|
ownersHeading: string
|
||||||
pageLoading: string
|
pageLoading: string
|
||||||
pageNotFound: string
|
pageNotFound: string
|
||||||
'pageTitle.accessControl': string
|
'pageTitle.accessControl': string
|
||||||
|
@ -1167,11 +1167,15 @@ upload: Upload
|
|||||||
unorderedList: Unordered list
|
unorderedList: Unordered list
|
||||||
checklist: Check list
|
checklist: Check list
|
||||||
code: Code
|
code: Code
|
||||||
|
approvedBy: Approved By
|
||||||
|
ownersHeading: OWNERS
|
||||||
|
changesRequestedBy: Changes Requested By
|
||||||
|
changesRequested: changesRequested
|
||||||
|
owners: Owners
|
||||||
showMoreText: Show More
|
showMoreText: Show More
|
||||||
addOptionalCommitMessage: Add (optional) commit message
|
addOptionalCommitMessage: Add (optional) commit message
|
||||||
confirmStrat: 'Confirm {{strat}}'
|
confirmStrat: 'Confirm {{strat}}'
|
||||||
waiting: Waiting
|
waiting: Waiting
|
||||||
changesRequestedBy: CHANGES REQUESTED BY
|
|
||||||
mergeBranchTitle: Merge branch {{branchName}} of {{repoPath}} (#{{prNum}})
|
mergeBranchTitle: Merge branch {{branchName}} of {{repoPath}} (#{{prNum}})
|
||||||
http: HTTP
|
http: HTTP
|
||||||
ssh: SSH
|
ssh: SSH
|
||||||
|
@ -39,10 +39,12 @@ import { useShowRequestError } from 'hooks/useShowRequestError'
|
|||||||
import type { TypesCodeOwnerEvaluation, TypesCodeOwnerEvaluationEntry } from 'services/code'
|
import type { TypesCodeOwnerEvaluation, TypesCodeOwnerEvaluationEntry } from 'services/code'
|
||||||
import type { PRChecksDecisionResult } from 'hooks/usePRChecksDecision'
|
import type { PRChecksDecisionResult } from 'hooks/usePRChecksDecision'
|
||||||
import { CodeOwnerReqDecision, findChangeReqDecisions, findWaitingDecisions } from 'utils/Utils'
|
import { CodeOwnerReqDecision, findChangeReqDecisions, findWaitingDecisions } from 'utils/Utils'
|
||||||
|
import { PullReqReviewDecision } from '../PullRequestUtils'
|
||||||
import css from './CodeOwnersOverview.module.scss'
|
import css from './CodeOwnersOverview.module.scss'
|
||||||
|
|
||||||
interface ChecksOverviewProps extends Pick<GitInfoProps, 'repoMetadata' | 'pullReqMetadata'> {
|
interface ChecksOverviewProps extends Pick<GitInfoProps, 'repoMetadata' | 'pullReqMetadata'> {
|
||||||
prChecksDecisionResult: PRChecksDecisionResult
|
prChecksDecisionResult: PRChecksDecisionResult
|
||||||
|
reqCodeOwnerLatestApproval: boolean
|
||||||
codeOwners?: TypesCodeOwnerEvaluation
|
codeOwners?: TypesCodeOwnerEvaluation
|
||||||
standalone: boolean
|
standalone: boolean
|
||||||
}
|
}
|
||||||
@ -52,6 +54,7 @@ export function CodeOwnersOverview({
|
|||||||
repoMetadata,
|
repoMetadata,
|
||||||
pullReqMetadata,
|
pullReqMetadata,
|
||||||
prChecksDecisionResult,
|
prChecksDecisionResult,
|
||||||
|
reqCodeOwnerLatestApproval,
|
||||||
standalone
|
standalone
|
||||||
}: ChecksOverviewProps) {
|
}: ChecksOverviewProps) {
|
||||||
const { getString } = useStrings()
|
const { getString } = useStrings()
|
||||||
@ -61,7 +64,11 @@ export function CodeOwnersOverview({
|
|||||||
useShowRequestError(error)
|
useShowRequestError(error)
|
||||||
|
|
||||||
const changeReqEntries = findChangeReqDecisions(codeOwners?.evaluation_entries, CodeOwnerReqDecision.CHANGEREQ)
|
const changeReqEntries = findChangeReqDecisions(codeOwners?.evaluation_entries, CodeOwnerReqDecision.CHANGEREQ)
|
||||||
const waitingEntries = findWaitingDecisions(codeOwners?.evaluation_entries)
|
const waitingEntries = findWaitingDecisions(
|
||||||
|
codeOwners?.evaluation_entries,
|
||||||
|
pullReqMetadata,
|
||||||
|
reqCodeOwnerLatestApproval
|
||||||
|
)
|
||||||
|
|
||||||
const approvalEntries = findChangeReqDecisions(codeOwners?.evaluation_entries, CodeOwnerReqDecision.APPROVED)
|
const approvalEntries = findChangeReqDecisions(codeOwners?.evaluation_entries, CodeOwnerReqDecision.APPROVED)
|
||||||
|
|
||||||
@ -133,6 +140,7 @@ export function CodeOwnersOverview({
|
|||||||
|
|
||||||
interface CodeOwnerSectionsProps extends Pick<GitInfoProps, 'repoMetadata' | 'pullReqMetadata'> {
|
interface CodeOwnerSectionsProps extends Pick<GitInfoProps, 'repoMetadata' | 'pullReqMetadata'> {
|
||||||
data: TypesCodeOwnerEvaluation
|
data: TypesCodeOwnerEvaluation
|
||||||
|
reqCodeOwnerLatestApproval?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const CodeOwnerSections: React.FC<CodeOwnerSectionsProps> = ({ repoMetadata, pullReqMetadata, data }) => {
|
const CodeOwnerSections: React.FC<CodeOwnerSectionsProps> = ({ repoMetadata, pullReqMetadata, data }) => {
|
||||||
@ -145,7 +153,11 @@ const CodeOwnerSections: React.FC<CodeOwnerSectionsProps> = ({ repoMetadata, pul
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CodeOwnerSection: React.FC<CodeOwnerSectionsProps> = ({ data }) => {
|
export const CodeOwnerSection: React.FC<CodeOwnerSectionsProps> = ({
|
||||||
|
data,
|
||||||
|
pullReqMetadata,
|
||||||
|
reqCodeOwnerLatestApproval
|
||||||
|
}) => {
|
||||||
const { getString } = useStrings()
|
const { getString } = useStrings()
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = useMemo(
|
||||||
@ -155,11 +167,15 @@ export const CodeOwnerSection: React.FC<CodeOwnerSectionsProps> = ({ data }) =>
|
|||||||
id: 'CODE',
|
id: 'CODE',
|
||||||
width: '45%',
|
width: '45%',
|
||||||
sort: true,
|
sort: true,
|
||||||
Header: 'CODE',
|
Header: getString('code'),
|
||||||
accessor: 'CODE',
|
accessor: 'CODE',
|
||||||
Cell: ({ row }: CellProps<TypesCodeOwnerEvaluationEntry>) => {
|
Cell: ({ row }: CellProps<TypesCodeOwnerEvaluationEntry>) => {
|
||||||
return (
|
return (
|
||||||
<Text lineClamp={1} padding={{ left: 'small', right: 'small' }} color={Color.BLACK}>
|
<Text
|
||||||
|
lineClamp={1}
|
||||||
|
padding={{ left: 'small', right: 'small' }}
|
||||||
|
color={Color.BLACK}
|
||||||
|
flex={{ justifyContent: 'space-between' }}>
|
||||||
{row.original.pattern}
|
{row.original.pattern}
|
||||||
</Text>
|
</Text>
|
||||||
)
|
)
|
||||||
@ -169,7 +185,7 @@ export const CodeOwnerSection: React.FC<CodeOwnerSectionsProps> = ({ data }) =>
|
|||||||
id: 'Owners',
|
id: 'Owners',
|
||||||
width: '13%',
|
width: '13%',
|
||||||
sort: true,
|
sort: true,
|
||||||
Header: 'OWNERS',
|
Header: getString('ownersHeading'),
|
||||||
accessor: 'OWNERS',
|
accessor: 'OWNERS',
|
||||||
Cell: ({ row }: CellProps<TypesCodeOwnerEvaluationEntry>) => {
|
Cell: ({ row }: CellProps<TypesCodeOwnerEvaluationEntry>) => {
|
||||||
return (
|
return (
|
||||||
@ -233,7 +249,7 @@ export const CodeOwnerSection: React.FC<CodeOwnerSectionsProps> = ({ data }) =>
|
|||||||
accessor: 'ChangesRequested',
|
accessor: 'ChangesRequested',
|
||||||
Cell: ({ row }: CellProps<TypesCodeOwnerEvaluationEntry>) => {
|
Cell: ({ row }: CellProps<TypesCodeOwnerEvaluationEntry>) => {
|
||||||
const changeReqEvaluations = row?.original?.owner_evaluations?.filter(
|
const changeReqEvaluations = row?.original?.owner_evaluations?.filter(
|
||||||
evaluation => evaluation.review_decision === 'changereq'
|
evaluation => evaluation.review_decision === PullReqReviewDecision.CHANGEREQ
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<Layout.Horizontal className={css.ownerContainer} spacing="tiny">
|
<Layout.Horizontal className={css.ownerContainer} spacing="tiny">
|
||||||
@ -279,13 +295,15 @@ export const CodeOwnerSection: React.FC<CodeOwnerSectionsProps> = ({ data }) =>
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'approvedBy',
|
id: 'approvedBy',
|
||||||
Header: 'APPROVED BY',
|
Header: getString('approvedBy'),
|
||||||
sort: true,
|
sort: true,
|
||||||
width: '15%',
|
width: '15%',
|
||||||
accessor: 'APPROVED BY',
|
accessor: 'APPROVED BY',
|
||||||
Cell: ({ row }: CellProps<TypesCodeOwnerEvaluationEntry>) => {
|
Cell: ({ row }: CellProps<TypesCodeOwnerEvaluationEntry>) => {
|
||||||
const approvedEvaluations = row?.original?.owner_evaluations?.filter(
|
const approvedEvaluations = row?.original?.owner_evaluations?.filter(
|
||||||
evaluation => evaluation.review_decision === 'approved'
|
evaluation =>
|
||||||
|
evaluation.review_decision === PullReqReviewDecision.APPROVED &&
|
||||||
|
(reqCodeOwnerLatestApproval ? evaluation.review_sha === pullReqMetadata?.source_sha : true)
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<Layout.Horizontal className={css.ownerContainer} spacing="tiny">
|
<Layout.Horizontal className={css.ownerContainer} spacing="tiny">
|
||||||
|
@ -122,7 +122,11 @@ const ChangesSection = (props: ChangesSectionProps) => {
|
|||||||
}) // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
}) // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
.filter((entry: any) => entry !== null && entry !== undefined) // Filter out the null entries
|
.filter((entry: any) => entry !== null && entry !== undefined) // Filter out the null entries
|
||||||
|
|
||||||
const codeOwnerPendingEntries = findWaitingDecisions(codeOwners?.evaluation_entries)
|
const codeOwnerPendingEntries = findWaitingDecisions(
|
||||||
|
codeOwners?.evaluation_entries,
|
||||||
|
pullReqMetadata,
|
||||||
|
reqCodeOwnerLatestApproval
|
||||||
|
)
|
||||||
const approvedEvaluations = reviewers?.filter(evaluation => evaluation.review_decision === 'approved')
|
const approvedEvaluations = reviewers?.filter(evaluation => evaluation.review_decision === 'approved')
|
||||||
const latestApprovalArr = approvedEvaluations?.filter(
|
const latestApprovalArr = approvedEvaluations?.filter(
|
||||||
approved => !checkIfOutdatedSha(approved.sha, pullReqMetadata?.source_sha as string)
|
approved => !checkIfOutdatedSha(approved.sha, pullReqMetadata?.source_sha as string)
|
||||||
@ -610,7 +614,12 @@ const ChangesSection = (props: ChangesSectionProps) => {
|
|||||||
<Container
|
<Container
|
||||||
className={css.codeOwnerContainer}
|
className={css.codeOwnerContainer}
|
||||||
padding={{ top: 'small', bottom: 'small', left: 'xxxlarge', right: 'small' }}>
|
padding={{ top: 'small', bottom: 'small', left: 'xxxlarge', right: 'small' }}>
|
||||||
<CodeOwnerSection data={codeOwners} pullReqMetadata={pullReqMetadata} repoMetadata={repoMetadata} />
|
<CodeOwnerSection
|
||||||
|
data={codeOwners}
|
||||||
|
pullReqMetadata={pullReqMetadata}
|
||||||
|
repoMetadata={repoMetadata}
|
||||||
|
reqCodeOwnerLatestApproval={reqCodeOwnerLatestApproval}
|
||||||
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
)}
|
)}
|
||||||
</Render>
|
</Render>
|
||||||
|
@ -55,7 +55,7 @@ const PullRequestSideBar = (props: PullRequestSideBarProps) => {
|
|||||||
const { getString } = useStrings()
|
const { getString } = useStrings()
|
||||||
const { showError, showSuccess } = useToaster()
|
const { showError, showSuccess } = useToaster()
|
||||||
const generateReviewDecisionInfo = (
|
const generateReviewDecisionInfo = (
|
||||||
reviewDecision: EnumPullReqReviewDecision | PullReqReviewDecision.outdated
|
reviewDecision: EnumPullReqReviewDecision | PullReqReviewDecision.OUTDATED
|
||||||
): {
|
): {
|
||||||
name: IconName
|
name: IconName
|
||||||
color?: Color
|
color?: Color
|
||||||
@ -76,7 +76,7 @@ const PullRequestSideBar = (props: PullRequestSideBarProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (reviewDecision) {
|
switch (reviewDecision) {
|
||||||
case PullReqReviewDecision.changeReq:
|
case PullReqReviewDecision.CHANGEREQ:
|
||||||
info = {
|
info = {
|
||||||
name: 'error-transparent-no-outline',
|
name: 'error-transparent-no-outline',
|
||||||
color: Color.RED_700,
|
color: Color.RED_700,
|
||||||
@ -87,7 +87,7 @@ const PullRequestSideBar = (props: PullRequestSideBarProps) => {
|
|||||||
message: 'requested changes'
|
message: 'requested changes'
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case PullReqReviewDecision.approved:
|
case PullReqReviewDecision.APPROVED:
|
||||||
info = {
|
info = {
|
||||||
name: 'tick-circle',
|
name: 'tick-circle',
|
||||||
color: Color.GREEN_700,
|
color: Color.GREEN_700,
|
||||||
@ -97,7 +97,7 @@ const PullRequestSideBar = (props: PullRequestSideBarProps) => {
|
|||||||
message: 'approved changes'
|
message: 'approved changes'
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case PullReqReviewDecision.pending:
|
case PullReqReviewDecision.PENDING:
|
||||||
info = {
|
info = {
|
||||||
name: 'waiting',
|
name: 'waiting',
|
||||||
color: Color.GREY_700,
|
color: Color.GREY_700,
|
||||||
@ -107,7 +107,7 @@ const PullRequestSideBar = (props: PullRequestSideBarProps) => {
|
|||||||
message: 'pending review'
|
message: 'pending review'
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case PullReqReviewDecision.outdated:
|
case PullReqReviewDecision.OUTDATED:
|
||||||
info = {
|
info = {
|
||||||
name: 'dot',
|
name: 'dot',
|
||||||
color: Color.GREY_100,
|
color: Color.GREY_100,
|
||||||
@ -273,7 +273,7 @@ const PullRequestSideBar = (props: PullRequestSideBarProps) => {
|
|||||||
</Text>
|
</Text>
|
||||||
}
|
}
|
||||||
tooltipProps={{ isDark: true, interactionKind: PopoverInteractionKind.HOVER }}>
|
tooltipProps={{ isDark: true, interactionKind: PopoverInteractionKind.HOVER }}>
|
||||||
{updatedReviewDecision === PullReqReviewDecision.outdated ? (
|
{updatedReviewDecision === PullReqReviewDecision.OUTDATED ? (
|
||||||
<img className={css.svgOutdated} src={ignoreFailed} width={20} height={20} />
|
<img className={css.svgOutdated} src={ignoreFailed} width={20} height={20} />
|
||||||
) : (
|
) : (
|
||||||
<Icon {...omit(reviewerInfo, 'iconProps')} />
|
<Icon {...omit(reviewerInfo, 'iconProps')} />
|
||||||
@ -281,7 +281,7 @@ const PullRequestSideBar = (props: PullRequestSideBarProps) => {
|
|||||||
</Utils.WrapOptionalTooltip>
|
</Utils.WrapOptionalTooltip>
|
||||||
<Avatar
|
<Avatar
|
||||||
className={cx(css.reviewerAvatar, {
|
className={cx(css.reviewerAvatar, {
|
||||||
[css.iconPadding]: updatedReviewDecision !== PullReqReviewDecision.changeReq
|
[css.iconPadding]: updatedReviewDecision !== PullReqReviewDecision.CHANGEREQ
|
||||||
})}
|
})}
|
||||||
name={reviewer.reviewer.display_name}
|
name={reviewer.reviewer.display_name}
|
||||||
size="small"
|
size="small"
|
||||||
|
@ -49,10 +49,10 @@ export function isSystemComment(commentItems: CommentItem<TypesPullReqActivity>[
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum PullReqReviewDecision {
|
export enum PullReqReviewDecision {
|
||||||
approved = 'approved',
|
APPROVED = 'approved',
|
||||||
changeReq = 'changereq',
|
CHANGEREQ = 'changereq',
|
||||||
pending = 'pending',
|
PENDING = 'pending',
|
||||||
outdated = 'outdated'
|
OUTDATED = 'outdated'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const processReviewDecision = (
|
export const processReviewDecision = (
|
||||||
@ -60,8 +60,8 @@ export const processReviewDecision = (
|
|||||||
reviewedSHA?: string,
|
reviewedSHA?: string,
|
||||||
sourceSHA?: string
|
sourceSHA?: string
|
||||||
) =>
|
) =>
|
||||||
review_decision === PullReqReviewDecision.approved && reviewedSHA !== sourceSHA
|
review_decision === PullReqReviewDecision.APPROVED && reviewedSHA !== sourceSHA
|
||||||
? PullReqReviewDecision.outdated
|
? PullReqReviewDecision.OUTDATED
|
||||||
: review_decision
|
: review_decision
|
||||||
|
|
||||||
export function getActivePullReqPageSection(): PullRequestSection | undefined {
|
export function getActivePullReqPageSection(): PullRequestSection | undefined {
|
||||||
|
@ -28,8 +28,11 @@ import type {
|
|||||||
TypesCodeOwnerEvaluationEntry,
|
TypesCodeOwnerEvaluationEntry,
|
||||||
RepoRepositoryOutput,
|
RepoRepositoryOutput,
|
||||||
TypesLabel,
|
TypesLabel,
|
||||||
TypesLabelValue
|
TypesLabelValue,
|
||||||
|
TypesPullReq,
|
||||||
|
TypesOwnerEvaluation
|
||||||
} from 'services/code'
|
} from 'services/code'
|
||||||
|
import { PullReqReviewDecision } from 'pages/PullRequest/PullRequestUtils'
|
||||||
|
|
||||||
export enum ACCESS_MODES {
|
export enum ACCESS_MODES {
|
||||||
VIEW,
|
VIEW,
|
||||||
@ -290,18 +293,28 @@ export const findChangeReqDecisions = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const findWaitingDecisions = (entries: TypesCodeOwnerEvaluationEntry[] | null | undefined) => {
|
export const findWaitingDecisions = (
|
||||||
|
entries: TypesCodeOwnerEvaluationEntry[] | null | undefined,
|
||||||
|
pullReqMetadata: TypesPullReq,
|
||||||
|
reqCodeOwnerLatestApproval: boolean
|
||||||
|
) => {
|
||||||
if (entries === null || entries === undefined) {
|
if (entries === null || entries === undefined) {
|
||||||
return []
|
return []
|
||||||
} else {
|
} else {
|
||||||
return entries.filter((entry: TypesCodeOwnerEvaluationEntry) => {
|
return entries.filter((entry: TypesCodeOwnerEvaluationEntry) => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// skip entry if all the owners have not given any review_decision yet
|
||||||
const hasEmptyDecision = entry?.owner_evaluations?.some((evaluation: any) => evaluation?.review_decision === '')
|
const hasNoReview = entry?.owner_evaluations?.every(
|
||||||
const hasNoApprovedDecision = !entry?.owner_evaluations?.some(
|
(evaluation: TypesOwnerEvaluation | { review_decision: string }) => evaluation.review_decision === ''
|
||||||
evaluation => evaluation.review_decision === 'approved'
|
|
||||||
)
|
)
|
||||||
|
if (hasNoReview) return false
|
||||||
return hasEmptyDecision && hasNoApprovedDecision
|
// add entry to waiting decision array if approved changes are outdated or no approvals are found for the given entry
|
||||||
|
// ( this will hence include pending or change requested entries)
|
||||||
|
const hasApprovedDecision = entry?.owner_evaluations?.some(
|
||||||
|
evaluation =>
|
||||||
|
evaluation.review_decision === PullReqReviewDecision.APPROVED &&
|
||||||
|
(reqCodeOwnerLatestApproval ? evaluation.review_sha === pullReqMetadata.source_sha : true)
|
||||||
|
)
|
||||||
|
return !hasApprovedDecision
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user