mirror of
https://github.com/harness/drone.git
synced 2025-05-19 02:20:03 +08:00
feat: [code-1991]: adding merge conflict files to be seen in merge section (#2126)
This commit is contained in:
parent
1b244fe624
commit
16fa4e7acf
@ -250,6 +250,18 @@ export interface StringsMap {
|
||||
cloneText: string
|
||||
close: string
|
||||
closed: string
|
||||
'cmdlineInfo.content': string
|
||||
'cmdlineInfo.stepFive': string
|
||||
'cmdlineInfo.stepFiveSub': string
|
||||
'cmdlineInfo.stepFour': string
|
||||
'cmdlineInfo.stepFourSub': string
|
||||
'cmdlineInfo.stepOne': string
|
||||
'cmdlineInfo.stepOneSub': string
|
||||
'cmdlineInfo.stepThree': string
|
||||
'cmdlineInfo.stepThreeSub': string
|
||||
'cmdlineInfo.stepTwo': string
|
||||
'cmdlineInfo.stepTwoSub': string
|
||||
'cmdlineInfo.title': string
|
||||
code: string
|
||||
'codeOwner.approvalCompleted': string
|
||||
'codeOwner.changesRequested': string
|
||||
@ -259,6 +271,7 @@ export interface StringsMap {
|
||||
codeSearch: string
|
||||
codeSearchModal: string
|
||||
comingSoon: string
|
||||
commandLine: string
|
||||
comment: string
|
||||
commentDeleted: string
|
||||
commit: string
|
||||
@ -286,6 +299,7 @@ export interface StringsMap {
|
||||
confirmRepoVisButton: string
|
||||
confirmStrat: string
|
||||
confirmation: string
|
||||
conflictsFoundInThisBranch: string
|
||||
content: string
|
||||
contents: string
|
||||
contributor: string
|
||||
@ -802,6 +816,7 @@ export interface StringsMap {
|
||||
'pr.titlePlaceHolder': string
|
||||
'pr.toggleComments': string
|
||||
'pr.unified': string
|
||||
'pr.useCmdLineToResolveConflicts': string
|
||||
'prChecks.error': string
|
||||
'prChecks.failure': string
|
||||
'prChecks.killed': string
|
||||
@ -973,6 +988,7 @@ export interface StringsMap {
|
||||
status: string
|
||||
'step.select': string
|
||||
'stepCategory.select': string
|
||||
stepNum: string
|
||||
submitReview: string
|
||||
success: string
|
||||
suggestion: string
|
||||
|
@ -252,6 +252,7 @@ webhook: Webhook
|
||||
diff: Diff
|
||||
draft: Draft
|
||||
conversation: Conversation
|
||||
commandLine: command line
|
||||
pr:
|
||||
toggleComments: Toggle comments
|
||||
suggestedChange: Suggested change
|
||||
@ -267,6 +268,7 @@ pr:
|
||||
expandFullFile: Expand all
|
||||
collapseFullFile: Collapse expanded lines
|
||||
ableToMerge: Able to merge.
|
||||
useCmdLineToResolveConflicts: Use the {cmd} to resolve conflicts
|
||||
cantBeMerged: This branch has conflicts with the {{name}} branch.
|
||||
cantMerge: Can't be merged. You can still create the pull request.
|
||||
failedToCreate: Failed to create Pull Request.
|
||||
@ -1043,6 +1045,7 @@ resolveComments: There are {{n}} unresolved comments
|
||||
view: View
|
||||
mergeCheckInProgress: Merge check in progress...
|
||||
allConflictsNeedToBeResolved: All conflicts have to be resolved before merging
|
||||
conflictsFoundInThisBranch: Conflicts found in this branch
|
||||
details: Details
|
||||
showCheckAll: Show all checks
|
||||
showLessCheck: Show less checks
|
||||
@ -1053,7 +1056,7 @@ customizeMergeCommitMessage: Customize merge commit message
|
||||
mergeStrategy: Merge strategy
|
||||
selectMergeStrat: Select merge strategy
|
||||
writeDownCommit: Write down commit message here
|
||||
prHasNoConflicts: This branch has no conflicts with {{name}} branch
|
||||
prHasNoConflicts: This branch has no conflicts with {name} branch
|
||||
checkStatus:
|
||||
succeeded: Succeeded in {time}
|
||||
failed: Failed in {time}
|
||||
@ -1181,3 +1184,17 @@ changesRequestedBy: CHANGES REQUESTED BY
|
||||
mergeBranchTitle: Merge branch {{branchName}} of {{repoPath}} (#{{prNum}})
|
||||
http: HTTP
|
||||
ssh: SSH
|
||||
stepNum: STEP {{num}}
|
||||
cmdlineInfo:
|
||||
title: Resolve conflicts via command line
|
||||
content: If the conflicts on this branch are too complex to resolve in the web editor, you can check it out via command line to resolve the conflicts
|
||||
stepOne: Clone the repository or update your local repository with the latest changes
|
||||
stepOneSub: git pull origin {target}
|
||||
stepTwo: Switch to the head branch of the pull request
|
||||
stepTwoSub: git checkout {source}
|
||||
stepThree: Merge the base branch into the head branch
|
||||
stepThreeSub: git merge {target}
|
||||
stepFour: Fix the conflicts and commit the result
|
||||
stepFourSub: See Resolving a merge conflict using the command line for step-by-step instruction on resolving merge conflicts
|
||||
stepFive: Push the changes
|
||||
stepFiveSub: git push -u origin {source}
|
||||
|
@ -38,11 +38,10 @@ import cx from 'classnames'
|
||||
import ReactTimeago from 'react-timeago'
|
||||
import type { OpenapiStatePullReqRequest, TypesPullReq, TypesRuleViolations } from 'services/code'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { CodeIcon, MergeStrategy, PullRequestFilterOption, PullRequestState } from 'utils/GitUtils'
|
||||
import { CodeIcon, MergeStrategy, PullRequestFilterOption, PullRequestState, dryMerge } from 'utils/GitUtils'
|
||||
import { useGetSpaceParam } from 'hooks/useGetSpaceParam'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import {
|
||||
dryMerge,
|
||||
extractInfoFromRuleViolationArr,
|
||||
getErrorMessage,
|
||||
inlineMergeFormRefType,
|
||||
@ -65,7 +64,8 @@ export const PullRequestActionsBox: React.FC<PullRequestActionsBoxProps> = ({
|
||||
onPRStateChanged,
|
||||
allowedStrategy,
|
||||
pullReqCommits,
|
||||
PRStateLoading
|
||||
PRStateLoading,
|
||||
setConflictingFiles
|
||||
}) => {
|
||||
const { getString } = useStrings()
|
||||
const { showError } = useToaster()
|
||||
@ -126,7 +126,8 @@ export const PullRequestActionsBox: React.FC<PullRequestActionsBoxProps> = ({
|
||||
setRuleViolationArr,
|
||||
setAllowedStrats,
|
||||
pullRequestSection,
|
||||
showError
|
||||
showError,
|
||||
setConflictingFiles
|
||||
) // eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [unchecked, pullReqMetadata?.source_sha])
|
||||
const [prMerged, setPrMerged] = useState(false)
|
||||
@ -144,7 +145,8 @@ export const PullRequestActionsBox: React.FC<PullRequestActionsBoxProps> = ({
|
||||
setRuleViolationArr,
|
||||
setAllowedStrats,
|
||||
pullRequestSection,
|
||||
showError
|
||||
showError,
|
||||
setConflictingFiles
|
||||
)
|
||||
}
|
||||
}, POLLING_INTERVAL) // Poll every 20 seconds
|
||||
|
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright 2023 Harness, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react'
|
||||
import { Color, FontVariation } from '@harnessio/design-system'
|
||||
import { Container, Layout, StringSubstitute, Text } from '@harnessio/uicore'
|
||||
import type { TypesPullReq } from 'services/code'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { CopyButton } from 'components/CopyButton/CopyButton'
|
||||
import { CodeIcon } from 'utils/GitUtils'
|
||||
import css from './PullRequestOverviewPanel.module.scss'
|
||||
|
||||
interface CommandLineInfoProps {
|
||||
pullReqMetadata: TypesPullReq
|
||||
}
|
||||
|
||||
const CommandLineInfo = (props: CommandLineInfoProps) => {
|
||||
const { pullReqMetadata } = props
|
||||
|
||||
const { getString } = useStrings()
|
||||
const stepOneCopy = getString('cmdlineInfo.stepOneSub').replace('{target}', pullReqMetadata.target_branch as string)
|
||||
const stepTwoCopy = getString('cmdlineInfo.stepTwoSub').replace('{source}', pullReqMetadata.source_branch as string)
|
||||
const stepThreeCopy = getString('cmdlineInfo.stepThreeSub').replace(
|
||||
'{target}',
|
||||
pullReqMetadata.target_branch as string
|
||||
)
|
||||
const stepFiveCopy = getString('cmdlineInfo.stepFiveSub').replace('{source}', pullReqMetadata.source_branch as string)
|
||||
return (
|
||||
<Container
|
||||
className={css.cmdInfoContainer}
|
||||
margin={{ top: 'small', bottom: 'small' }}
|
||||
padding={{ top: 'large', left: 'xxxlarge', right: 'xlarge', bottom: 'large' }}>
|
||||
<Layout.Vertical>
|
||||
<Container className={css.cmdTextTitleContainer}>
|
||||
<Text padding={{ bottom: 'xsmall' }} font={{ variation: FontVariation.H5 }}>
|
||||
{getString('cmdlineInfo.title')}
|
||||
</Text>
|
||||
</Container>
|
||||
<Text
|
||||
color={Color.GREY_450}
|
||||
className={css.stepText}
|
||||
font={{ variation: FontVariation.BODY2 }}
|
||||
padding={{ top: 'xsmall' }}>
|
||||
{getString('cmdlineInfo.content')}
|
||||
</Text>
|
||||
<Layout.Vertical>
|
||||
<Layout.Horizontal flex={{ alignItems: 'center', justifyContent: 'flex-start' }} padding={{ top: 'small' }}>
|
||||
<Text className={css.checkName} padding={{ right: 'small' }} font={{ variation: FontVariation.CARD_TITLE }}>
|
||||
{getString('stepNum', { num: 1 }).toUpperCase()}
|
||||
</Text>
|
||||
<Text color={Color.GREY_450} className={css.stepText} font={{ variation: FontVariation.BODY2 }}>
|
||||
{getString('cmdlineInfo.stepOne')}
|
||||
</Text>
|
||||
</Layout.Horizontal>
|
||||
<Layout.Horizontal margin={{ left: 'small' }} padding={{ top: 'xsmall', left: 'xxxlarge' }}>
|
||||
<Layout.Horizontal
|
||||
flex={{ justifyContent: 'space-between' }}
|
||||
className={css.blueCopyContainer}
|
||||
padding={{ top: 'small', left: 'medium', right: 'medium', bottom: 'small' }}>
|
||||
<Text className={css.stepFont}>
|
||||
<StringSubstitute
|
||||
str={getString('cmdlineInfo.stepOneSub')}
|
||||
vars={{
|
||||
target: pullReqMetadata.target_branch
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
<CopyButton
|
||||
className={css.copyIconContainer}
|
||||
content={stepOneCopy}
|
||||
icon={CodeIcon.Copy}
|
||||
color={Color.PRIMARY_7}
|
||||
iconProps={{ size: 14, color: Color.PRIMARY_7 }}
|
||||
background={Color.PRIMARY_1}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
</Layout.Horizontal>
|
||||
<Layout.Horizontal flex={{ alignItems: 'center', justifyContent: 'flex-start' }} padding={{ top: 'small' }}>
|
||||
<Text className={css.checkName} padding={{ right: 'small' }} font={{ variation: FontVariation.CARD_TITLE }}>
|
||||
{getString('stepNum', { num: 2 }).toUpperCase()}
|
||||
</Text>
|
||||
<Text color={Color.GREY_450} className={css.stepText} font={{ variation: FontVariation.BODY2 }}>
|
||||
{getString('cmdlineInfo.stepTwo')}
|
||||
</Text>
|
||||
</Layout.Horizontal>
|
||||
<Layout.Horizontal margin={{ left: 'small' }} padding={{ top: 'xsmall', left: 'xxxlarge' }}>
|
||||
<Layout.Horizontal
|
||||
flex={{ justifyContent: 'space-between' }}
|
||||
className={css.blueCopyContainer}
|
||||
padding={{ top: 'small', left: 'medium', right: 'medium', bottom: 'small' }}>
|
||||
<Text className={css.stepFont}>
|
||||
<StringSubstitute
|
||||
str={getString('cmdlineInfo.stepTwoSub')}
|
||||
vars={{
|
||||
source: pullReqMetadata.source_branch
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
<CopyButton
|
||||
className={css.copyIconContainer}
|
||||
content={stepTwoCopy}
|
||||
icon={CodeIcon.Copy}
|
||||
color={Color.PRIMARY_7}
|
||||
iconProps={{ size: 14, color: Color.PRIMARY_7 }}
|
||||
background={Color.PRIMARY_1}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
</Layout.Horizontal>
|
||||
|
||||
<Layout.Horizontal flex={{ alignItems: 'center', justifyContent: 'flex-start' }} padding={{ top: 'small' }}>
|
||||
<Text className={css.checkName} padding={{ right: 'small' }} font={{ variation: FontVariation.CARD_TITLE }}>
|
||||
{getString('stepNum', { num: 3 }).toUpperCase()}
|
||||
</Text>
|
||||
<Text color={Color.GREY_450} className={css.stepText} font={{ variation: FontVariation.BODY2 }}>
|
||||
{getString('cmdlineInfo.stepThree')}
|
||||
</Text>
|
||||
</Layout.Horizontal>
|
||||
<Layout.Horizontal margin={{ left: 'small' }} padding={{ top: 'xsmall', left: 'xxxlarge' }}>
|
||||
<Layout.Horizontal
|
||||
flex={{ justifyContent: 'space-between' }}
|
||||
className={css.blueCopyContainer}
|
||||
padding={{ top: 'small', left: 'medium', right: 'medium', bottom: 'small' }}>
|
||||
<Text className={css.stepFont}>
|
||||
<StringSubstitute
|
||||
str={getString('cmdlineInfo.stepThreeSub')}
|
||||
vars={{
|
||||
target: pullReqMetadata.target_branch
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
<CopyButton
|
||||
className={css.copyIconContainer}
|
||||
content={stepThreeCopy}
|
||||
icon={CodeIcon.Copy}
|
||||
color={Color.PRIMARY_7}
|
||||
iconProps={{ size: 14, color: Color.PRIMARY_7 }}
|
||||
background={Color.PRIMARY_1}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
</Layout.Horizontal>
|
||||
<Layout.Horizontal flex={{ alignItems: 'center', justifyContent: 'flex-start' }} padding={{ top: 'small' }}>
|
||||
<Text className={css.checkName} padding={{ right: 'small' }} font={{ variation: FontVariation.CARD_TITLE }}>
|
||||
{getString('stepNum', { num: 4 }).toUpperCase()}
|
||||
</Text>
|
||||
<Text color={Color.GREY_450} className={css.stepText} font={{ variation: FontVariation.BODY2 }}>
|
||||
{getString('cmdlineInfo.stepFour')}
|
||||
</Text>
|
||||
</Layout.Horizontal>
|
||||
<Layout.Horizontal margin={{ left: 'small' }} padding={{ top: 'xsmall', left: 'xxxlarge' }}>
|
||||
<Layout.Horizontal flex={{ justifyContent: 'space-between' }}>
|
||||
<Text
|
||||
padding={{ left: 'tiny' }}
|
||||
color={Color.GREY_450}
|
||||
className={css.stepText}
|
||||
font={{ variation: FontVariation.BODY2 }}>
|
||||
{getString('cmdlineInfo.stepFourSub')}
|
||||
</Text>
|
||||
</Layout.Horizontal>
|
||||
</Layout.Horizontal>
|
||||
<Layout.Horizontal flex={{ alignItems: 'center', justifyContent: 'flex-start' }} padding={{ top: 'small' }}>
|
||||
<Text className={css.checkName} padding={{ right: 'small' }} font={{ variation: FontVariation.CARD_TITLE }}>
|
||||
{getString('stepNum', { num: 5 }).toUpperCase()}
|
||||
</Text>
|
||||
<Text color={Color.GREY_450} className={css.stepText} font={{ variation: FontVariation.BODY2 }}>
|
||||
{getString('cmdlineInfo.stepFive')}
|
||||
</Text>
|
||||
</Layout.Horizontal>
|
||||
<Layout.Horizontal margin={{ left: 'small' }} padding={{ top: 'xsmall', left: 'xxxlarge' }}>
|
||||
<Layout.Horizontal
|
||||
flex={{ justifyContent: 'space-between' }}
|
||||
className={css.blueCopyContainer}
|
||||
padding={{ top: 'small', left: 'medium', right: 'medium', bottom: 'small' }}>
|
||||
<Text className={css.stepFont}>
|
||||
<StringSubstitute
|
||||
str={getString('cmdlineInfo.stepFiveSub')}
|
||||
vars={{
|
||||
source: pullReqMetadata.source_branch
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
<CopyButton
|
||||
className={css.copyIconContainer}
|
||||
content={stepFiveCopy}
|
||||
icon={CodeIcon.Copy}
|
||||
color={Color.PRIMARY_7}
|
||||
iconProps={{ size: 14, color: Color.PRIMARY_7 }}
|
||||
background={Color.PRIMARY_1}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
</Layout.Horizontal>
|
||||
</Layout.Vertical>
|
||||
</Layout.Vertical>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export default CommandLineInfo
|
@ -204,8 +204,9 @@
|
||||
|
||||
.gridContainer {
|
||||
display: grid !important;
|
||||
grid-template-columns: 1fr 1fr !important;
|
||||
grid-template-columns: 1fr minmax(0, 1fr) !important;
|
||||
position: relative !important;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.row {
|
||||
@ -225,6 +226,7 @@
|
||||
margin-left: var(--spacing-small) !important;
|
||||
grid-column: 2 !important;
|
||||
text-align: right !important;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* Pseudo-elements for placeholders to maintain grid structure */
|
||||
@ -251,3 +253,107 @@
|
||||
padding-right: unset !important;
|
||||
}
|
||||
}
|
||||
.conflictingFilesTable {
|
||||
.row {
|
||||
font-size: 12px !important;
|
||||
box-shadow: unset !important;
|
||||
border-bottom: 1px solid rgb(217, 218, 229, 0.6) !important;
|
||||
padding: var(--spacing-small) !important;
|
||||
margin-bottom: unset !important;
|
||||
background: #f6f8fa !important;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
[class*='TableV2--header'] {
|
||||
border-bottom: 1px solid rgb(217, 218, 229, 0.6) !important;
|
||||
padding-top: var(--spacing-small) !important;
|
||||
padding-left: var(--spacing-medium) !important;
|
||||
padding-right: var(--spacing-medium) !important;
|
||||
padding-bottom: var(--spacing-xsmall) !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
.conflictingFileName {
|
||||
font-family: 'Roboto Mono' !important;
|
||||
}
|
||||
[class*='TableV2--cell'] {
|
||||
p {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.bp3-icon-double-caret-vertical {
|
||||
fill: var(--grey-200) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.conflictingContainer {
|
||||
border-top: 1px solid var(--grey-100) !important;
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
padding: var(--spacing-5) 2rem !important;
|
||||
padding-right: 4.05rem !important;
|
||||
background: #f6f8fa !important;
|
||||
max-height: 150px;
|
||||
overflow: auto !important;
|
||||
}
|
||||
|
||||
.cmdText {
|
||||
color: var(--primary-7) !important;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.cmdInfoContainer {
|
||||
background: var(--primary-bg) !important;
|
||||
border: 1px solid var(--grey-100) !important;
|
||||
|
||||
.cmdTextTitleContainer {
|
||||
border-bottom: 1px solid var(--grey-100) !important;
|
||||
> p {
|
||||
font-size: 14px !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.copyIconContainer {
|
||||
background-color: var(--primary-1) !important;
|
||||
color: var(--primary-7) !important;
|
||||
border-radius: 4px !important;
|
||||
--button-height: unset !important;
|
||||
padding: unset !important ;
|
||||
--padding-right: 2px !important;
|
||||
padding-left: 4px !important;
|
||||
min-width: unset !important;
|
||||
padding-bottom: 1px !important;
|
||||
--background-color: var(--primary-7);
|
||||
--text-color: var(--primary-7) !important;
|
||||
}
|
||||
|
||||
.blueCopyContainer {
|
||||
border: 0.5px solid var(--primary-3) !important;
|
||||
background: var(--primary-1) !important;
|
||||
width: 70% !important;
|
||||
}
|
||||
|
||||
.stepFont {
|
||||
font-size: 12px !important;
|
||||
color: var(--black) !important;
|
||||
font-family: 'Courier New', Courier, monospace !important;
|
||||
}
|
||||
|
||||
.stepText {
|
||||
font-size: 12px !important;
|
||||
font-weight: 400 !important;
|
||||
}
|
||||
.conflictingFileName {
|
||||
font-family: 'Roboto Mono' !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
/* eslint-disable */
|
||||
// This is an auto-generated file
|
||||
export declare const blueCopyContainer: string
|
||||
export declare const blueText: string
|
||||
export declare const borderContainer: string
|
||||
export declare const borderRadius: string
|
||||
@ -23,7 +24,14 @@ export declare const buttonPadding: string
|
||||
export declare const changeContainerPadding: string
|
||||
export declare const checkContainerPadding: string
|
||||
export declare const checkName: string
|
||||
export declare const cmdInfoContainer: string
|
||||
export declare const cmdText: string
|
||||
export declare const cmdTextTitleContainer: string
|
||||
export declare const codeOwnerContainer: string
|
||||
export declare const conflictingContainer: string
|
||||
export declare const conflictingFileName: string
|
||||
export declare const conflictingFilesTable: string
|
||||
export declare const copyIconContainer: string
|
||||
export declare const details: string
|
||||
export declare const executionIcon: string
|
||||
export declare const greyContainer: string
|
||||
@ -48,6 +56,8 @@ export declare const sectionTitle: string
|
||||
export declare const showMore: string
|
||||
export declare const statusCircleContainer: string
|
||||
export declare const statusIcon: string
|
||||
export declare const stepFont: string
|
||||
export declare const stepText: string
|
||||
export declare const successIcon: string
|
||||
export declare const textSize: string
|
||||
export declare const timeoutIcon: string
|
||||
|
@ -28,8 +28,8 @@ import type {
|
||||
TypesRuleViolations
|
||||
} from 'services/code'
|
||||
import { PanelSectionOutletPosition } from 'pages/PullRequest/PullRequestUtils'
|
||||
import { MergeCheckStatus, PRMergeOption, dryMerge } from 'utils/Utils'
|
||||
import { PullRequestState } from 'utils/GitUtils'
|
||||
import { MergeCheckStatus, PRMergeOption } from 'utils/Utils'
|
||||
import { PullRequestState, dryMerge } from 'utils/GitUtils'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import type { PRChecksDecisionResult } from 'hooks/usePRChecksDecision'
|
||||
import { useGetRepositoryMetadata } from 'hooks/useGetRepositoryMetadata'
|
||||
@ -79,6 +79,7 @@ const PullRequestOverviewPanel = (props: PullRequestOverviewPanelProps) => {
|
||||
() => pullReqMetadata.merge_check_status === MergeCheckStatus.UNCHECKED && !isClosed,
|
||||
[pullReqMetadata, isClosed]
|
||||
)
|
||||
const [conflictingFiles, setConflictingFiles] = useState<string[]>()
|
||||
const [ruleViolation, setRuleViolation] = useState(false)
|
||||
const [ruleViolationArr, setRuleViolationArr] = useState<{ data: { rule_violations: TypesRuleViolations[] } }>()
|
||||
const [requiresCommentApproval, setRequiresCommentApproval] = useState(false)
|
||||
@ -172,6 +173,7 @@ const PullRequestOverviewPanel = (props: PullRequestOverviewPanelProps) => {
|
||||
setAllowedStrats,
|
||||
pullRequestSection,
|
||||
showError,
|
||||
setConflictingFiles,
|
||||
setRequiresCommentApproval,
|
||||
setAtLeastOneReviewerRule,
|
||||
setReqCodeOwnerApproval,
|
||||
@ -186,6 +188,8 @@ const PullRequestOverviewPanel = (props: PullRequestOverviewPanelProps) => {
|
||||
<Container margin={{ bottom: 'medium' }} className={css.mainContainer}>
|
||||
<Layout.Vertical>
|
||||
<PullRequestActionsBox
|
||||
conflictingFiles={conflictingFiles}
|
||||
setConflictingFiles={setConflictingFiles}
|
||||
repoMetadata={repoMetadata}
|
||||
pullReqMetadata={pullReqMetadata}
|
||||
onPRStateChanged={onPRStateChanged}
|
||||
@ -231,9 +235,12 @@ const PullRequestOverviewPanel = (props: PullRequestOverviewPanelProps) => {
|
||||
<ChecksSection pullReqMetadata={pullReqMetadata} repoMetadata={repoMetadata} />
|
||||
),
|
||||
[PanelSectionOutletPosition.MERGEABILITY]: !pullReqMetadata.merged && (
|
||||
<Container className={cx(css.sectionContainer, css.borderRadius)}>
|
||||
<MergeSection pullReqMetadata={pullReqMetadata} unchecked={unchecked} mergeable={mergeable} />
|
||||
</Container>
|
||||
<MergeSection
|
||||
pullReqMetadata={pullReqMetadata}
|
||||
unchecked={unchecked}
|
||||
mergeable={mergeable}
|
||||
conflictingFiles={conflictingFiles}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
|
@ -13,63 +13,156 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react'
|
||||
import React, { useMemo } from 'react'
|
||||
import { Color, FontVariation } from '@harnessio/design-system'
|
||||
import { Container, Layout, Text } from '@harnessio/uicore'
|
||||
import cx from 'classnames'
|
||||
import {
|
||||
Button,
|
||||
ButtonSize,
|
||||
ButtonVariation,
|
||||
Container,
|
||||
Layout,
|
||||
StringSubstitute,
|
||||
TableV2,
|
||||
Text,
|
||||
useToggle
|
||||
} from '@harnessio/uicore'
|
||||
import { Render } from 'react-jsx-match'
|
||||
import type { CellProps, Column } from 'react-table'
|
||||
import { Images } from 'images'
|
||||
import type { TypesPullReq } from 'services/code'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import Success from '../../../../../icons/code-success.svg?url'
|
||||
import Fail from '../../../../../icons/code-fail.svg?url'
|
||||
import CommandLineInfo from '../CommandLineInfo'
|
||||
import css from '../PullRequestOverviewPanel.module.scss'
|
||||
|
||||
interface MergeSectionProps {
|
||||
mergeable: boolean
|
||||
unchecked: boolean
|
||||
pullReqMetadata: TypesPullReq
|
||||
conflictingFiles: string[] | undefined
|
||||
}
|
||||
|
||||
interface ConflictingFilesInterface {
|
||||
name: string
|
||||
}
|
||||
const MergeSection = (props: MergeSectionProps) => {
|
||||
const { mergeable, unchecked, pullReqMetadata } = props
|
||||
const { mergeable, unchecked, pullReqMetadata, conflictingFiles } = props
|
||||
const { getString } = useStrings()
|
||||
|
||||
const [isExpanded, toggleExpanded] = useToggle(false)
|
||||
const [showCommandLineInfo, toggleShowCommandLineInfo] = useToggle(false)
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const columns: Column<any>[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
id: 'conflictingFiles',
|
||||
width: '45%',
|
||||
sort: true,
|
||||
Header: `Conflicting Files (${conflictingFiles?.length})`,
|
||||
accessor: 'conflictingFiles',
|
||||
Cell: ({ row }: CellProps<ConflictingFilesInterface>) => {
|
||||
return (
|
||||
<Text
|
||||
lineClamp={1}
|
||||
className={css.conflictingFileName}
|
||||
padding={{ left: 'small', right: 'small' }}
|
||||
color={Color.BLACK}>
|
||||
{row.original}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
}
|
||||
], // eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[conflictingFiles]
|
||||
)
|
||||
return (
|
||||
<Container>
|
||||
<Layout.Horizontal flex={{ alignItems: 'center', justifyContent: 'start' }}>
|
||||
{(unchecked && <img src={Images.PrUnchecked} width={25} height={25} />) || (
|
||||
<>
|
||||
{mergeable ? (
|
||||
<img alt={getString('success')} width={26} height={26} src={Success} />
|
||||
) : (
|
||||
<img alt={getString('failed')} width={26} height={26} src={Fail} />
|
||||
<Container className={cx(css.sectionContainer, css.borderRadius)}>
|
||||
<Layout.Horizontal flex={{ justifyContent: 'space-between' }}>
|
||||
<Layout.Horizontal flex={{ alignItems: 'center', justifyContent: 'start' }}>
|
||||
{(unchecked && <img src={Images.PrUnchecked} width={25} height={25} />) || (
|
||||
<>
|
||||
{mergeable ? (
|
||||
<img alt={getString('success')} width={26} height={26} src={Success} />
|
||||
) : (
|
||||
<img alt={getString('failed')} width={26} height={26} src={Fail} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{(unchecked && (
|
||||
<Layout.Vertical padding={{ left: 'medium' }}>
|
||||
<Text padding={{ bottom: 'xsmall' }} className={css.sectionTitle}>
|
||||
{getString('mergeCheckInProgress')}
|
||||
</Text>
|
||||
<Text className={css.sectionSubheader}> {getString('pr.checkingToMerge')}</Text>
|
||||
</Layout.Vertical>
|
||||
)) || (
|
||||
<Layout.Vertical>
|
||||
{!mergeable && (
|
||||
<Text className={css.sectionTitle} color={Color.RED_700} padding={{ left: 'medium', bottom: 'xsmall' }}>
|
||||
{getString('allConflictsNeedToBeResolved')}
|
||||
</Text>
|
||||
{(unchecked && (
|
||||
<Layout.Vertical padding={{ left: 'medium' }}>
|
||||
<Text padding={{ bottom: 'xsmall' }} className={css.sectionTitle}>
|
||||
{getString('mergeCheckInProgress')}
|
||||
</Text>
|
||||
<Text className={css.sectionSubheader}> {getString('pr.checkingToMerge')}</Text>
|
||||
</Layout.Vertical>
|
||||
)) || (
|
||||
<Layout.Vertical>
|
||||
{!mergeable && (
|
||||
<Text
|
||||
className={css.sectionTitle}
|
||||
color={Color.RED_700}
|
||||
padding={{ left: 'medium', bottom: 'xsmall' }}>
|
||||
{getString('conflictsFoundInThisBranch')}
|
||||
</Text>
|
||||
)}
|
||||
<Text
|
||||
flex
|
||||
className={mergeable ? css.sectionTitle : css.sectionSubheader}
|
||||
color={mergeable ? Color.GREEN_800 : Color.GREY_450}
|
||||
font={{ variation: FontVariation.BODY }}
|
||||
padding={{ left: 'medium' }}>
|
||||
<StringSubstitute
|
||||
str={mergeable ? getString('prHasNoConflicts') : getString('pr.useCmdLineToResolveConflicts')}
|
||||
vars={{
|
||||
name: pullReqMetadata.target_branch,
|
||||
cmd: (
|
||||
<Text
|
||||
onClick={toggleShowCommandLineInfo}
|
||||
padding={{ left: 'xsmall', right: 'xsmall' }}
|
||||
className={css.cmdText}>
|
||||
{getString('commandLine')}
|
||||
</Text>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
</Layout.Vertical>
|
||||
)}
|
||||
<Text
|
||||
className={mergeable ? css.sectionTitle : css.sectionSubheader}
|
||||
color={mergeable ? Color.GREEN_800 : Color.GREY_450}
|
||||
font={{ variation: FontVariation.BODY }}
|
||||
padding={{ left: 'medium' }}>
|
||||
{getString(mergeable ? 'prHasNoConflicts' : 'pr.cantBeMerged', { name: pullReqMetadata?.target_branch })}
|
||||
</Text>
|
||||
</Layout.Vertical>
|
||||
)}
|
||||
</Layout.Horizontal>
|
||||
</Layout.Horizontal>
|
||||
{!mergeable && (
|
||||
<Button
|
||||
padding={{ right: 'unset' }}
|
||||
className={cx(css.blueText, css.buttonPadding)}
|
||||
variation={ButtonVariation.LINK}
|
||||
size={ButtonSize.SMALL}
|
||||
text={getString(isExpanded ? 'showLessMatches' : 'showMoreText')}
|
||||
onClick={toggleExpanded}
|
||||
rightIcon={isExpanded ? 'main-chevron-up' : 'main-chevron-down'}
|
||||
iconProps={{ size: 10, margin: { left: 'xsmall' } }}
|
||||
/>
|
||||
)}
|
||||
</Layout.Horizontal>
|
||||
<Render when={showCommandLineInfo}>
|
||||
<CommandLineInfo pullReqMetadata={pullReqMetadata} />
|
||||
</Render>
|
||||
</Container>
|
||||
<Render when={isExpanded}>
|
||||
<Container className={css.conflictingContainer}>
|
||||
<Container padding={{ left: 'xxxlarge' }} className={css.greyContainer}>
|
||||
<TableV2
|
||||
className={css.conflictingFilesTable}
|
||||
sortable
|
||||
columns={columns}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
data={conflictingFiles as any}
|
||||
getRowClassName={() => css.row}
|
||||
/>
|
||||
</Container>
|
||||
</Container>
|
||||
</Render>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
// Last updated for git 2.29.0.
|
||||
|
||||
import type { IconName } from '@harnessio/icons'
|
||||
import type { MutateRequestOptions } from 'restful-react/dist/Mutate'
|
||||
import type {
|
||||
EnumWebhookTrigger,
|
||||
OpenapiContentInfo,
|
||||
@ -26,10 +27,11 @@ import type {
|
||||
OpenapiGetContentOutput,
|
||||
TypesCommit,
|
||||
TypesPullReq,
|
||||
TypesRepository
|
||||
TypesRepository,
|
||||
TypesRuleViolations
|
||||
} from 'services/code'
|
||||
import { getConfig } from 'services/config'
|
||||
import { getErrorMessage } from './Utils'
|
||||
import { PullRequestSection, getErrorMessage } from './Utils'
|
||||
|
||||
export interface GitInfoProps {
|
||||
repoMetadata: TypesRepository
|
||||
@ -456,3 +458,114 @@ export const getProviders = () =>
|
||||
Object.values(GitProviders).map(value => {
|
||||
return { value, label: value }
|
||||
})
|
||||
|
||||
export const codeOwnersNotFoundMessage = 'CODEOWNERS file not found'
|
||||
export const codeOwnersNotFoundMessage2 = `path "CODEOWNERS" not found`
|
||||
export const codeOwnersNotFoundMessage3 = `failed to find node 'CODEOWNERS' in 'main': failed to get tree node: failed to ls file: path "CODEOWNERS" not found`
|
||||
|
||||
export const dryMerge = (
|
||||
isMounted: React.MutableRefObject<boolean>,
|
||||
isClosed: boolean,
|
||||
pullReqMetadata: TypesPullReq,
|
||||
internalFlags: React.MutableRefObject<{
|
||||
dryRun: boolean
|
||||
}>,
|
||||
mergePR: (
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
data: any,
|
||||
mutateRequestOptions?:
|
||||
| MutateRequestOptions<
|
||||
{
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
[key: string]: any
|
||||
},
|
||||
unknown
|
||||
>
|
||||
| undefined // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
) => Promise<any>,
|
||||
setRuleViolation: (value: React.SetStateAction<boolean>) => void,
|
||||
setRuleViolationArr: (
|
||||
value: React.SetStateAction<
|
||||
| {
|
||||
data: {
|
||||
rule_violations: TypesRuleViolations[]
|
||||
}
|
||||
}
|
||||
| undefined
|
||||
>
|
||||
) => void,
|
||||
setAllowedStrats: (value: React.SetStateAction<string[]>) => void,
|
||||
pullRequestSection: string | undefined,
|
||||
showError: (message: React.ReactNode, timeout?: number | undefined, key?: string | undefined) => void,
|
||||
setConflictingFiles: React.Dispatch<React.SetStateAction<string[] | undefined>>,
|
||||
setRequiresCommentApproval?: (value: React.SetStateAction<boolean>) => void,
|
||||
setAtLeastOneReviewerRule?: (value: React.SetStateAction<boolean>) => void,
|
||||
setReqCodeOwnerApproval?: (value: React.SetStateAction<boolean>) => void,
|
||||
setMinApproval?: (value: React.SetStateAction<number>) => void,
|
||||
setReqCodeOwnerLatestApproval?: (value: React.SetStateAction<boolean>) => void,
|
||||
setMinReqLatestApproval?: (value: React.SetStateAction<number>) => void,
|
||||
setPRStateLoading?: (value: React.SetStateAction<boolean>) => void
|
||||
) => {
|
||||
if (isMounted.current && !isClosed && pullReqMetadata.state !== PullRequestState.MERGED) {
|
||||
// Use an internal flag to prevent flickering during the loading state of buttons
|
||||
internalFlags.current.dryRun = true
|
||||
mergePR({ bypass_rules: true, dry_run: true, source_sha: pullReqMetadata?.source_sha })
|
||||
.then(res => {
|
||||
if (isMounted.current) {
|
||||
if (res?.rule_violations?.length > 0) {
|
||||
setRuleViolation(true)
|
||||
setRuleViolationArr({ data: { rule_violations: res?.rule_violations } })
|
||||
setAllowedStrats(res.allowed_methods)
|
||||
setRequiresCommentApproval?.(res.requires_comment_resolution)
|
||||
setAtLeastOneReviewerRule?.(res.requires_no_change_requests)
|
||||
setReqCodeOwnerApproval?.(res.requires_code_owners_approval)
|
||||
setMinApproval?.(res.minimum_required_approvals_count)
|
||||
setReqCodeOwnerLatestApproval?.(res.requires_code_owners_approval_latest)
|
||||
setMinReqLatestApproval?.(res.minimum_required_approvals_count_latest)
|
||||
setConflictingFiles?.(res.conflict_files)
|
||||
} else {
|
||||
setRuleViolation(false)
|
||||
setAllowedStrats(res.allowed_methods)
|
||||
setRequiresCommentApproval?.(res.requires_comment_resolution)
|
||||
setAtLeastOneReviewerRule?.(res.requires_no_change_requests)
|
||||
setReqCodeOwnerApproval?.(res.requires_code_owners_approval)
|
||||
setMinApproval?.(res.minimum_required_approvals_count)
|
||||
setReqCodeOwnerLatestApproval?.(res.requires_code_owners_approval_latest)
|
||||
setMinReqLatestApproval?.(res.minimum_required_approvals_count_latest)
|
||||
setConflictingFiles?.(res.conflict_files)
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
if (isMounted.current) {
|
||||
if (err.status === 422) {
|
||||
setRuleViolation(true)
|
||||
setRuleViolationArr(err)
|
||||
setAllowedStrats(err.allowed_methods)
|
||||
setRequiresCommentApproval?.(err.requires_comment_resolution)
|
||||
setAtLeastOneReviewerRule?.(err.requires_no_change_requests)
|
||||
setReqCodeOwnerApproval?.(err.requires_code_owners_approval)
|
||||
setMinApproval?.(err.minimum_required_approvals_count)
|
||||
setReqCodeOwnerLatestApproval?.(err.requires_code_owners_approval_latest)
|
||||
setMinReqLatestApproval?.(err.minimum_required_approvals_count_latest)
|
||||
setConflictingFiles?.(err.conflict_files)
|
||||
} else if (
|
||||
getErrorMessage(err) === codeOwnersNotFoundMessage ||
|
||||
getErrorMessage(err) === codeOwnersNotFoundMessage2 ||
|
||||
getErrorMessage(err) === codeOwnersNotFoundMessage3 ||
|
||||
err.status === 423 // resource locked (merge / dry-run already ongoing)
|
||||
) {
|
||||
return
|
||||
} else if (pullRequestSection !== PullRequestSection.CONVERSATION) {
|
||||
return
|
||||
} else {
|
||||
showError(getErrorMessage(err))
|
||||
}
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
internalFlags.current.dryRun = false
|
||||
setPRStateLoading?.(false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -23,16 +23,14 @@ import type { editor } from 'monaco-editor'
|
||||
import type { EditorView } from '@codemirror/view'
|
||||
import type { FormikProps } from 'formik'
|
||||
import type { SelectOption } from '@harnessio/uicore'
|
||||
import type { MutateRequestOptions } from 'restful-react/dist/Mutate'
|
||||
import type {
|
||||
EnumMergeMethod,
|
||||
TypesRuleViolations,
|
||||
TypesViolation,
|
||||
TypesCodeOwnerEvaluationEntry,
|
||||
TypesPullReq,
|
||||
TypesListCommitResponse
|
||||
} from 'services/code'
|
||||
import { PullRequestState, type GitInfoProps } from './GitUtils'
|
||||
import type { GitInfoProps } from './GitUtils'
|
||||
|
||||
export enum ACCESS_MODES {
|
||||
VIEW,
|
||||
@ -160,6 +158,8 @@ export interface PullRequestActionsBoxProps extends Pick<GitInfoProps, 'repoMeta
|
||||
allowedStrategy: string[]
|
||||
pullReqCommits: TypesListCommitResponse | undefined
|
||||
PRStateLoading: boolean
|
||||
conflictingFiles: string[] | undefined
|
||||
setConflictingFiles: React.Dispatch<React.SetStateAction<string[] | undefined>>
|
||||
}
|
||||
|
||||
export interface PRMergeOption extends SelectOption {
|
||||
@ -731,109 +731,3 @@ export function removeSpecificTextOptimized(
|
||||
viewRef?.current?.dispatch({ changes })
|
||||
}
|
||||
}
|
||||
export const codeOwnersNotFoundMessage = 'CODEOWNERS file not found'
|
||||
export const codeOwnersNotFoundMessage2 = `path "CODEOWNERS" not found`
|
||||
export const codeOwnersNotFoundMessage3 = `failed to find node 'CODEOWNERS' in 'main': failed to get tree node: failed to ls file: path "CODEOWNERS" not found`
|
||||
|
||||
export const dryMerge = (
|
||||
isMounted: React.MutableRefObject<boolean>,
|
||||
isClosed: boolean,
|
||||
pullReqMetadata: TypesPullReq,
|
||||
internalFlags: React.MutableRefObject<{
|
||||
dryRun: boolean
|
||||
}>,
|
||||
mergePR: (
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
data: any,
|
||||
mutateRequestOptions?:
|
||||
| MutateRequestOptions<
|
||||
{
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
[key: string]: any
|
||||
},
|
||||
unknown
|
||||
>
|
||||
| undefined // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
) => Promise<any>,
|
||||
setRuleViolation: (value: React.SetStateAction<boolean>) => void,
|
||||
setRuleViolationArr: (
|
||||
value: React.SetStateAction<
|
||||
| {
|
||||
data: {
|
||||
rule_violations: TypesRuleViolations[]
|
||||
}
|
||||
}
|
||||
| undefined
|
||||
>
|
||||
) => void,
|
||||
setAllowedStrats: (value: React.SetStateAction<string[]>) => void,
|
||||
pullRequestSection: string | undefined,
|
||||
showError: (message: React.ReactNode, timeout?: number | undefined, key?: string | undefined) => void,
|
||||
setRequiresCommentApproval?: (value: React.SetStateAction<boolean>) => void,
|
||||
setAtLeastOneReviewerRule?: (value: React.SetStateAction<boolean>) => void,
|
||||
setReqCodeOwnerApproval?: (value: React.SetStateAction<boolean>) => void,
|
||||
setMinApproval?: (value: React.SetStateAction<number>) => void,
|
||||
setReqCodeOwnerLatestApproval?: (value: React.SetStateAction<boolean>) => void,
|
||||
setMinReqLatestApproval?: (value: React.SetStateAction<number>) => void,
|
||||
setPRStateLoading?: (value: React.SetStateAction<boolean>) => void
|
||||
) => {
|
||||
if (isMounted.current && !isClosed && pullReqMetadata.state !== PullRequestState.MERGED) {
|
||||
// Use an internal flag to prevent flickering during the loading state of buttons
|
||||
internalFlags.current.dryRun = true
|
||||
mergePR({ bypass_rules: true, dry_run: true, source_sha: pullReqMetadata?.source_sha })
|
||||
.then(res => {
|
||||
if (isMounted.current) {
|
||||
if (res?.rule_violations?.length > 0) {
|
||||
setRuleViolation(true)
|
||||
setRuleViolationArr({ data: { rule_violations: res?.rule_violations } })
|
||||
setAllowedStrats(res.allowed_methods)
|
||||
setRequiresCommentApproval?.(res.requires_comment_resolution)
|
||||
setAtLeastOneReviewerRule?.(res.requires_no_change_requests)
|
||||
setReqCodeOwnerApproval?.(res.requires_code_owners_approval)
|
||||
setMinApproval?.(res.minimum_required_approvals_count)
|
||||
setReqCodeOwnerLatestApproval?.(res.requires_code_owners_approval_latest)
|
||||
setMinReqLatestApproval?.(res.minimum_required_approvals_count_latest)
|
||||
} else {
|
||||
setRuleViolation(false)
|
||||
setAllowedStrats(res.allowed_methods)
|
||||
setRequiresCommentApproval?.(res.requires_comment_resolution)
|
||||
setAtLeastOneReviewerRule?.(res.requires_no_change_requests)
|
||||
setReqCodeOwnerApproval?.(res.requires_code_owners_approval)
|
||||
setMinApproval?.(res.minimum_required_approvals_count)
|
||||
setReqCodeOwnerLatestApproval?.(res.requires_code_owners_approval_latest)
|
||||
setMinReqLatestApproval?.(res.minimum_required_approvals_count_latest)
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
if (isMounted.current) {
|
||||
if (err.status === 422) {
|
||||
setRuleViolation(true)
|
||||
setRuleViolationArr(err)
|
||||
setAllowedStrats(err.allowed_methods)
|
||||
setRequiresCommentApproval?.(err.requires_comment_resolution)
|
||||
setAtLeastOneReviewerRule?.(err.requires_no_change_requests)
|
||||
setReqCodeOwnerApproval?.(err.requires_code_owners_approval)
|
||||
setMinApproval?.(err.minimum_required_approvals_count)
|
||||
setReqCodeOwnerLatestApproval?.(err.requires_code_owners_approval_latest)
|
||||
setMinReqLatestApproval?.(err.minimum_required_approvals_count_latest)
|
||||
} else if (
|
||||
getErrorMessage(err) === codeOwnersNotFoundMessage ||
|
||||
getErrorMessage(err) === codeOwnersNotFoundMessage2 ||
|
||||
getErrorMessage(err) === codeOwnersNotFoundMessage3 ||
|
||||
err.status === 423 // resource locked (merge / dry-run already ongoing)
|
||||
) {
|
||||
return
|
||||
} else if (pullRequestSection !== PullRequestSection.CONVERSATION) {
|
||||
return
|
||||
} else {
|
||||
showError(getErrorMessage(err))
|
||||
}
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
internalFlags.current.dryRun = false
|
||||
setPRStateLoading?.(false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user