[CODE-1116] UI : Protection rules integration with Branch Creation/Deletion and Commits (#824)

This commit is contained in:
Ritik Kapoor 2023-11-28 07:06:54 +00:00 committed by Harness
parent 5b16c72d4a
commit 274a5a01ab
16 changed files with 375 additions and 56 deletions

View File

@ -56,6 +56,18 @@
font-size: var(--form-input-font-size);
font-weight: 500;
}
.warningMessageLayout {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.warningMessage {
display: flex;
gap: 0.5rem;
align-items: center;
}
}
.newBranchContainer {

View File

@ -22,3 +22,5 @@ export declare const main: string
export declare const newBranch: string
export declare const newBranchContainer: string
export declare const radioGroup: string
export declare const warningMessage: string
export declare const warningMessageLayout: string

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import React, { useState } from 'react'
import React, { useEffect, useState } from 'react'
import { Dialog, Intent } from '@blueprintjs/core'
import * as yup from 'yup'
import {
@ -22,6 +22,7 @@ import {
ButtonProps,
Container,
Layout,
Text,
FlexExpander,
Formik,
FormikForm,
@ -32,10 +33,12 @@ import {
} from '@harnessio/uicore'
import { Icon } from '@harnessio/icons'
import cx from 'classnames'
import { FontVariation } from '@harnessio/design-system'
import { FontVariation, Color } from '@harnessio/design-system'
import { useMutate } from 'restful-react'
import { get } from 'lodash-es'
import { Render } from 'react-jsx-match'
import { useModalHook } from 'hooks/useModalHook'
import { useRuleViolationCheck } from 'hooks/useRuleViolationCheck'
import { String, useStrings } from 'framework/strings'
import { getErrorMessage } from 'utils/Utils'
import type { OpenapiCommitFilesRequest, TypesListCommitResponse } from 'services/code'
@ -82,10 +85,20 @@ export function useCommitModal({
const { getString } = useStrings()
const [targetBranchOption, setTargetBranchOption] = useState(CommitToGitRefOption.DIRECTLY)
const { showError, showSuccess } = useToaster()
const { violation, bypassable, bypassed, setAllStates, resetViolation } = useRuleViolationCheck()
const [disableCTA, setDisableCTA] = useState(false)
const { mutate, loading } = useMutate<TypesListCommitResponse>({
verb: 'POST',
path: `/api/v1/repos/${repoMetadata.path}/+/commits`
})
const { mutate: dryRunCall } = useMutate({
verb: 'POST',
path: `/api/v1/repos/${repoMetadata.path}/+/commits`
})
useEffect(() => {
dryRun(CommitToGitRefOption.DIRECTLY)
}, [])
const handleSubmit = (formData: FormData) => {
try {
@ -101,28 +114,73 @@ export function useCommitModal({
}
],
branch: gitRef,
new_branch: formData.newBranch,
new_branch: targetBranchOption === CommitToGitRefOption.NEW_BRANCH ? formData.newBranch : '',
title: formData.title || commitTitlePlaceHolder,
message: formData.message
message: formData.message,
bypass_rules: bypassed
}
mutate(data)
.then(response => {
hideModal()
onSuccess(response, formData.newBranch)
onSuccess(response, targetBranchOption === CommitToGitRefOption.NEW_BRANCH ? formData.newBranch : '')
if (commitAction === GitCommitAction.DELETE) {
showSuccess(getString('fileDeleted').replace('__path__', resourcePath))
}
})
.catch(_error => {
showError(getErrorMessage(_error), 0, getString('failedToCreateRepo'))
if (_error.status === 422) {
setAllStates({
violation: true,
bypassed: true,
bypassable: _error?.data?.violations[0]?.bypassable
})
} else showError(getErrorMessage(_error), 0, getString('failedToCreateRepo'))
})
} catch (exception) {
showError(getErrorMessage(exception), 0, getString('failedToCreateRepo'))
}
}
const dryRun = async (targetBranch: CommitToGitRefOption) => {
resetViolation()
setDisableCTA(false)
if (targetBranch === CommitToGitRefOption.DIRECTLY) {
try {
const data: OpenapiCommitFilesRequest = {
actions: [
{
action: commitAction,
path: oldResourcePath || resourcePath,
payload: `${oldResourcePath ? `file://${resourcePath}\n` : ''}${payload}`,
sha
}
],
branch: gitRef,
new_branch: '',
title: '',
message: '',
bypass_rules: false,
dry_run_rules: true
}
const response = await dryRunCall(data)
if (response?.rule_violations?.length) {
setAllStates({
violation: true,
bypassed: false,
bypassable: response?.rule_violations[0]?.bypassable
})
setDisableCTA(!response?.rule_violations[0]?.bypassable)
}
} catch (exception) {
showError(getErrorMessage(exception), 0, getString('failedToCreateRepo'))
}
}
}
return (
<Dialog
isOpen
@ -186,14 +244,43 @@ export function useCommitModal({
label=""
onChange={e => {
setTargetBranchOption(get(e.target, 'defaultValue') as unknown as CommitToGitRefOption)
dryRun(get(e.target, 'defaultValue') as unknown as CommitToGitRefOption)
}}
items={[
{
label: <String stringID="commitDirectlyTo" vars={{ gitRef }} useRichText />,
label: (
<Layout.Horizontal className={css.warningMessageLayout}>
<String stringID="commitDirectlyTo" vars={{ gitRef }} useRichText />
<Render when={violation && targetBranchOption === CommitToGitRefOption.DIRECTLY}>
<Layout.Horizontal className={css.warningMessage}>
<Icon intent={Intent.WARNING} name="danger-icon" size={16} />
<Text font={{ variation: FontVariation.BODY2 }} color={Color.RED_800}>
{bypassable
? getString('branchProtection.commitDirectlyBlockText')
: getString('branchProtection.commitNewBranchBlockText')}
</Text>
</Layout.Horizontal>
</Render>
</Layout.Horizontal>
),
value: CommitToGitRefOption.DIRECTLY
},
{
label: <String stringID="commitToNewBranch" useRichText />,
label: (
<Layout.Horizontal className={css.warningMessageLayout}>
<String stringID="commitToNewBranch" useRichText />
<Render when={violation && targetBranchOption === CommitToGitRefOption.NEW_BRANCH}>
<Layout.Horizontal className={css.warningMessage}>
<Icon intent={Intent.WARNING} name="danger-icon" size={16} />
<Text font={{ variation: FontVariation.BODY2 }} color={Color.RED_800}>
{bypassable
? getString('branchProtection.commitNewBranchAlertText')
: getString('branchProtection.commitNewBranchBlockText')}
</Text>
</Layout.Horizontal>
</Render>
</Layout.Horizontal>
),
value: CommitToGitRefOption.NEW_BRANCH
}
]}
@ -209,6 +296,9 @@ export function useCommitModal({
dataTooltipId: 'enterNewBranchName'
}}
inputGroup={{ autoFocus: true }}
onChange={() => {
setAllStates({ violation: false, bypassable: false, bypassed: false })
}}
/>
</Layout.Horizontal>
</Container>
@ -216,12 +306,22 @@ export function useCommitModal({
</Container>
<Layout.Horizontal spacing="small" padding={{ right: 'xxlarge', top: 'xxlarge', bottom: 'large' }}>
{!bypassable ? (
<Button
type="submit"
variation={ButtonVariation.PRIMARY}
text={getString('commit')}
disabled={loading}
disabled={loading || disableCTA}
/>
) : (
<Button
intent={Intent.DANGER}
disabled={loading}
type="submit"
variation={ButtonVariation.SECONDARY}
text={getString('branchProtection.commitNewBranchAlertBtn')}
/>
)}
<Button text={getString('cancel')} variation={ButtonVariation.LINK} onClick={hideModal} />
<FlexExpander />

View File

@ -30,6 +30,12 @@
margin-right: var(--spacing-10) !important;
}
.warningMessage {
display: flex;
gap: 0.5rem;
align-items: center;
}
// .branchSourceDesc {
// color: var(--grey-400) !important;
// font-size: var(--form-input-font-size) !important;

View File

@ -24,3 +24,4 @@ export declare const maxContainer: string
export declare const popoverContainer: string
export declare const selectContainer: string
export declare const title: string
export declare const warningMessage: string

View File

@ -29,13 +29,15 @@ import {
useToaster,
FormInput,
Label,
Text,
ButtonVariation,
StringSubstitute
} from '@harnessio/uicore'
import { Icon } from '@harnessio/icons'
import { FontVariation } from '@harnessio/design-system'
import { FontVariation, Color } from '@harnessio/design-system'
import { useMutate } from 'restful-react'
import { get } from 'lodash-es'
import { Render } from 'react-jsx-match'
import { useModalHook } from 'hooks/useModalHook'
import { useStrings } from 'framework/strings'
import { getErrorMessage, permissionProps } from 'utils/Utils'
@ -43,6 +45,7 @@ import { GitInfoProps, normalizeGitRef, isGitBranchNameValid } from 'utils/GitUt
import { BranchTagSelect } from 'components/BranchTagSelect/BranchTagSelect'
import type { RepoBranch } from 'services/code'
import { useGetSpaceParam } from 'hooks/useGetSpaceParam'
import { useRuleViolationCheck } from 'hooks/useRuleViolationCheck'
import { useAppContext } from 'AppContext'
import css from './CreateBranchModal.module.scss'
@ -79,6 +82,7 @@ export function useCreateBranchModal({
const { getString } = useStrings()
const [sourceBranch, setSourceBranch] = useState(suggestedSourceBranch || (repoMetadata.default_branch as string))
const { showError, showSuccess } = useToaster()
const { violation, bypassable, bypassed, setAllStates } = useRuleViolationCheck()
const { mutate: createBranch, loading } = useMutate<RepoBranch>({
verb: 'POST',
path: `/api/v1/repos/${repoMetadata.path}/+/branches`
@ -88,7 +92,8 @@ export function useCreateBranchModal({
try {
createBranch({
name,
target: normalizeGitRef(refIsATag ? `refs/tags/${sourceBranch}` : sourceBranch)
target: normalizeGitRef(refIsATag ? `refs/tags/${sourceBranch}` : sourceBranch),
bypass_rules: bypassed
})
.then(response => {
hideModal()
@ -106,7 +111,13 @@ export function useCreateBranchModal({
}
})
.catch(_error => {
showError(getErrorMessage(_error), 0, 'failedToCreateBranch')
if (_error.status === 422) {
setAllStates({
violation: true,
bypassed: true,
bypassable: _error?.data?.violations[0]?.bypassable
})
} else showError(getErrorMessage(_error), 0, 'failedToCreateBranch')
})
} catch (exception) {
showError(getErrorMessage(exception), 0, 'failedToCreateBranch')
@ -154,6 +165,9 @@ export function useCreateBranchModal({
dataTooltipId: 'repositoryBranchTextField'
}}
inputGroup={{ autoFocus: true }}
onChange={() => {
setAllStates({ violation: false, bypassable: false, bypassed: false })
}}
/>
<Container margin={{ top: 'medium' }}>
<Label className={css.label}>{getString('basedOn')}</Label>
@ -176,17 +190,37 @@ export function useCreateBranchModal({
spacing="small"
padding={{ right: 'xxlarge', top: 'xxlarge', bottom: 'large' }}
style={{ alignItems: 'center' }}>
{!bypassable ? (
<Button
type="submit"
text={getString('createBranch')}
variation={ButtonVariation.PRIMARY}
disabled={loading}
/>
) : (
<Button
intent={Intent.DANGER}
disabled={loading}
type="submit"
variation={ButtonVariation.SECONDARY}
text={getString('branchProtection.createBranchAlertBtn')}
/>
)}
<Button text={getString('cancel')} variation={ButtonVariation.LINK} onClick={hideModal} />
<FlexExpander />
{loading && <Icon intent={Intent.PRIMARY} name="steps-spinner" size={16} />}
</Layout.Horizontal>
<Render when={violation}>
<Layout.Horizontal className={css.warningMessage}>
<Icon intent={Intent.WARNING} name="danger-icon" size={16} />
<Text font={{ variation: FontVariation.BODY2 }} color={Color.RED_800}>
{bypassable
? getString('branchProtection.createBranchAlertText')
: getString('branchProtection.createBranchBlockText')}
</Text>
</Layout.Horizontal>
</Render>
</FormikForm>
</Formik>
</Container>

View File

@ -54,9 +54,19 @@ export interface StringsMap {
'branchProtection.blockBranchDeletion': string
'branchProtection.blockBranchDeletionText': string
'branchProtection.bypassList': string
'branchProtection.commitDirectlyBlockText': string
'branchProtection.commitNewBranchAlertBtn': string
'branchProtection.commitNewBranchAlertText': string
'branchProtection.commitNewBranchBlockText': string
'branchProtection.create': string
'branchProtection.createBranchAlertBtn': string
'branchProtection.createBranchAlertText': string
'branchProtection.createBranchBlockText': string
'branchProtection.createRule': string
'branchProtection.defaultBranch': string
'branchProtection.deleteBranchAlertBtn': string
'branchProtection.deleteBranchAlertText': string
'branchProtection.deleteBranchBlockText': string
'branchProtection.deleteProtectionRule': string
'branchProtection.deleteRule': string
'branchProtection.deleteText': string

View File

@ -24,22 +24,25 @@ import { useConfirmationDialog } from './useConfirmationDialog'
export interface UseConfirmActionDialogProps {
message: React.ReactElement
childtag?: React.ReactElement
intent?: Intent
title?: string
confirmText?: string
cancelText?: string
action: (params?: Unknown) => void
persistDialog?: boolean
}
/**
* @deprecated Use useConfirmAct() hook instead
*/
export const useConfirmAction = (props: UseConfirmActionDialogProps) => {
const { title, message, confirmText, cancelText, intent, action } = props
const { title, message, confirmText, cancelText, intent, childtag, action, persistDialog } = props
const { getString } = useStrings()
const [params, setParams] = useState<Unknown>()
const { openDialog } = useConfirmationDialog({
intent,
persistDialog: persistDialog,
titleText: title || getString('confirmation'),
contentText: message,
confirmButtonText: confirmText || getString('confirm'),
@ -49,7 +52,8 @@ export const useConfirmAction = (props: UseConfirmActionDialogProps) => {
if (isConfirmed) {
action(params)
}
}
},
children: childtag || <></>
})
const confirm = useCallback(
(_params?: Unknown) => {

View File

@ -33,6 +33,7 @@ export interface UseConfirmationDialogProps {
canEscapeKeyClose?: boolean
children?: JSX.Element
className?: string
persistDialog?: boolean
}
export interface UseConfirmationDialogReturn {
@ -54,7 +55,8 @@ export const useConfirmationDialog = (props: UseConfirmationDialogProps): UseCon
canOutsideClickClose,
canEscapeKeyClose,
children,
className
className,
persistDialog
} = props
const [showModal, hideModal] = useModalHook(() => {
@ -81,9 +83,10 @@ export const useConfirmationDialog = (props: UseConfirmationDialogProps): UseCon
const onClose = React.useCallback(
(isConfirmed: boolean): void => {
onCloseDialog?.(isConfirmed)
hideModal()
if (!isConfirmed) hideModal()
else if (persistDialog) showModal()
},
[hideModal, onCloseDialog]
[hideModal, onCloseDialog, persistDialog]
)
return {

View File

@ -0,0 +1,68 @@
import { useReducer } from 'react'
enum ActionTypes {
SET_VIOLATION = 'SET_VIOLATION',
SET_BYPASSED = 'SET_BYPASSED',
SET_BYPASSABLE = 'SET_BYPASSABLE',
SET_ALL_STATES = 'SET_ALL_STATES'
}
interface ViolationState {
violation: boolean
bypassable: boolean
bypassed: boolean
}
type ViolationAction =
| { type: ActionTypes.SET_VIOLATION; payload: boolean }
| { type: ActionTypes.SET_BYPASSED; payload: boolean }
| { type: ActionTypes.SET_BYPASSABLE; payload: boolean }
| { type: ActionTypes.SET_ALL_STATES; payload: Partial<ViolationState> }
const initialState: ViolationState = {
violation: false,
bypassable: false,
bypassed: false
}
const reducer = (state: ViolationState, action: ViolationAction): ViolationState => {
switch (action.type) {
case ActionTypes.SET_VIOLATION:
return { ...state, violation: action.payload }
case ActionTypes.SET_BYPASSABLE:
return { ...state, bypassed: action.payload }
case ActionTypes.SET_BYPASSED:
return { ...state, bypassable: action.payload }
case ActionTypes.SET_ALL_STATES:
return {
...state,
violation: action.payload.violation !== undefined ? action.payload.violation : state.violation,
bypassable: action.payload.bypassable !== undefined ? action.payload.bypassable : state.bypassable,
bypassed: action.payload.bypassed !== undefined ? action.payload.bypassed : state.bypassed
}
default:
return state
}
}
export const useRuleViolationCheck = () => {
const [state, dispatch] = useReducer(reducer, initialState)
const setViolation = (value: boolean) => dispatch({ type: ActionTypes.SET_VIOLATION, payload: value })
const setBypassable = (value: boolean) => dispatch({ type: ActionTypes.SET_BYPASSABLE, payload: value })
const setBypassed = (value: boolean) => dispatch({ type: ActionTypes.SET_BYPASSED, payload: value })
const setAllStates = (payload: Partial<ViolationState>) => {
dispatch({ type: ActionTypes.SET_ALL_STATES, payload })
}
const resetViolation = () => setAllStates({ violation: false, bypassable: false, bypassed: false })
return {
violation: state.violation,
setViolation,
bypassable: state.bypassable,
setBypassable,
bypassed: state.bypassed,
setBypassed,
setAllStates,
resetViolation
}
}

View File

@ -913,6 +913,16 @@ branchProtection:
mergePrAlertTitle: Merge pull request alert
mergePrAlertText: 'Merge cannot be completed. {{ruleCount}} branch rules failed: '
mergeCheckboxAlert: Bypass branch rules and merge
createBranchAlertBtn: Bypass rules and create branch
createBranchAlertText: Some rules will be bypassed by creating branch
createBranchBlockText: Some rules don't allow you to create branch
deleteBranchAlertBtn: Bypass rule and confirm delete
deleteBranchAlertText: Some rules will be bypassed while deleting branch
deleteBranchBlockText: Some rules don't allow you to delete branch
commitNewBranchAlertBtn: Bypass rules and commit via new branch
commitNewBranchAlertText: Some rules will be bypassed to commit by creating branch
commitNewBranchBlockText: Some rules don't allow you to create new branch for commit
commitDirectlyBlockText: Some rules don't allow you to commit directly
codeOwner:
title: Code Owner
changesRequested: '{count} {count|1:change,changes} requested'

View File

@ -80,6 +80,14 @@
}
}
.warningMessage {
order: 3;
display: flex !important;
gap: 0.5rem;
align-items: center;
margin-top: 1rem !important;
}
.popover {
:global {
.bp3-popover-content {

View File

@ -25,3 +25,4 @@ export declare const row: string
export declare const rowText: string
export declare const spacer: string
export declare const table: string
export declare const warningMessage: string

View File

@ -18,6 +18,7 @@ import React, { useEffect, useMemo, useState } from 'react'
import {
Container,
TableV2 as Table,
Layout,
Text,
Avatar,
Tag,
@ -25,8 +26,10 @@ import {
StringSubstitute,
useIsMounted
} from '@harnessio/uicore'
import { Icon } from '@harnessio/icons'
import { noop } from 'lodash-es'
import { Color, Intent } from '@harnessio/design-system'
import { Color, Intent, FontVariation } from '@harnessio/design-system'
import { Render } from 'react-jsx-match'
import type { CellProps, Column } from 'react-table'
import { Link, useHistory } from 'react-router-dom'
import cx from 'classnames'
@ -43,6 +46,7 @@ import type {
import { CommitActions } from 'components/CommitActions/CommitActions'
import { formatDate, getErrorMessage } from 'utils/Utils'
import { useConfirmAction } from 'hooks/useConfirmAction'
import { useRuleViolationCheck } from 'hooks/useRuleViolationCheck'
import { OptionsMenuButton } from 'components/OptionsMenuButton/OptionsMenuButton'
import { CommitDivergence } from 'components/CommitDivergence/CommitDivergence'
import { makeDiffRefs } from 'utils/GitUtils'
@ -167,19 +171,23 @@ export function BranchesContent({ repoMetadata, searchTerm = '', branches, onDel
id: 'action',
width: '30px',
Cell: ({ row }: CellProps<RepoBranch>) => {
const { violation, bypassable, bypassed, setAllStates } = useRuleViolationCheck()
const [persistModal, setPersistModal] = useState(true)
const { mutate: deleteBranch } = useMutate({
verb: 'DELETE',
path: `/api/v1/repos/${repoMetadata.path}/+/branches/${row.original.name}`
path: `/api/v1/repos/${repoMetadata.path}/+/branches/${row.original.name}?bypass_rules=${bypassed}`
})
const { showSuccess, showError } = useToaster()
const confirmDeleteBranch = useConfirmAction({
title: getString('deleteBranch'),
confirmText: getString('delete'),
confirmText: !bypassable ? getString('delete') : getString('branchProtection.deleteBranchAlertBtn'),
intent: Intent.DANGER,
message: <String useRichText stringID="deleteBranchConfirm" vars={{ name: row.original.name }} />,
persistDialog: persistModal,
action: async () => {
deleteBranch({})
.then(() => {
setPersistModal(false)
showSuccess(
<StringSubstitute
str={getString('branchDeleted')}
@ -192,9 +200,27 @@ export function BranchesContent({ repoMetadata, searchTerm = '', branches, onDel
onDeleteSuccess()
})
.catch(error => {
showError(getErrorMessage(error), 0, 'failedToDeleteBranch')
if (error.status === 422) {
setAllStates({
violation: true,
bypassed: true,
bypassable: error?.data?.violations[0]?.bypassable
})
}
} else showError(getErrorMessage(error), 0, 'failedToDeleteBranch')
})
},
childtag: (
<Render when={violation}>
<Layout.Horizontal className={css.warningMessage}>
<Icon intent={Intent.WARNING} name="danger-icon" size={16} />
<Text font={{ variation: FontVariation.BODY2 }} color={Color.RED_800}>
{bypassable
? getString('branchProtection.deleteBranchAlertText')
: getString('branchProtection.deleteBranchBlockText')}
</Text>
</Layout.Horizontal>
</Render>
)
})
return (

View File

@ -184,6 +184,8 @@ export interface OpenapiCommitFilesRequest {
message?: string
new_branch?: string
title?: string
bypass_rules?: boolean
dry_run_rules?: boolean
}
export type OpenapiContent = RepoFileContent | OpenapiDirContent | RepoSymlinkContent | RepoSubmoduleContent

View File

@ -867,7 +867,7 @@ paths:
application/json:
schema:
items:
$ref: '#/components/schemas/GitrpcBlamePart'
$ref: '#/components/schemas/GitBlamePart'
type: array
description: OK
'401':
@ -1047,6 +1047,13 @@ paths:
delete:
operationId: deleteBranch
parameters:
- description: Bypass rule violations if possible.
in: query
name: bypass_rules
required: false
schema:
default: false
type: boolean
- in: path
name: repo_ref
required: true
@ -1814,7 +1821,7 @@ paths:
application/json:
schema:
items:
$ref: '#/components/schemas/GitrpcFileDiff'
$ref: '#/components/schemas/GitFileDiff'
type: array
text/plain:
schema:
@ -4413,6 +4420,8 @@ paths:
$ref: '#/components/schemas/EnumRuleState'
type:
$ref: '#/components/schemas/OpenapiRuleType'
uid:
type: string
type: object
responses:
'200':
@ -4648,6 +4657,13 @@ paths:
delete:
operationId: deleteTag
parameters:
- description: Bypass rule violations if possible.
in: query
name: bypass_rules
required: false
schema:
default: false
type: boolean
- in: path
name: repo_ref
required: true
@ -6899,8 +6915,8 @@ components:
EnumMergeMethod:
enum:
- merge
- squash
- rebase
- squash
type: string
EnumParentResourceType:
enum:
@ -7000,22 +7016,22 @@ components:
- tag_deleted
- tag_updated
type: string
GitrpcBlamePart:
GitBlamePart:
properties:
commit:
$ref: '#/components/schemas/GitrpcCommit'
$ref: '#/components/schemas/GitCommit'
lines:
items:
type: string
nullable: true
type: array
type: object
GitrpcCommit:
GitCommit:
properties:
author:
$ref: '#/components/schemas/GitrpcSignature'
$ref: '#/components/schemas/GitSignature'
committer:
$ref: '#/components/schemas/GitrpcSignature'
$ref: '#/components/schemas/GitSignature'
message:
type: string
sha:
@ -7023,14 +7039,14 @@ components:
title:
type: string
type: object
GitrpcFileAction:
GitFileAction:
enum:
- CREATE
- UPDATE
- DELETE
- MOVE
type: string
GitrpcFileDiff:
GitFileDiff:
properties:
additions:
type: integer
@ -7056,30 +7072,30 @@ components:
sha:
type: string
status:
$ref: '#/components/schemas/GitrpcFileDiffStatus'
$ref: '#/components/schemas/GitFileDiffStatus'
type: object
GitrpcFileDiffStatus:
GitFileDiffStatus:
type: string
GitrpcIdentity:
GitIdentity:
properties:
email:
type: string
name:
type: string
type: object
GitrpcPathDetails:
GitPathDetails:
properties:
last_commit:
$ref: '#/components/schemas/GitrpcCommit'
$ref: '#/components/schemas/GitCommit'
path:
type: string
size:
type: integer
type: object
GitrpcSignature:
GitSignature:
properties:
identity:
$ref: '#/components/schemas/GitrpcIdentity'
$ref: '#/components/schemas/GitIdentity'
when:
format: date-time
type: string
@ -7191,6 +7207,10 @@ components:
type: array
branch:
type: string
bypass_rules:
type: boolean
dry_run_rules:
type: boolean
message:
type: string
new_branch:
@ -7227,6 +7247,8 @@ components:
type: string
OpenapiCreateBranchRequest:
properties:
bypass_rules:
type: boolean
name:
type: string
target:
@ -7318,6 +7340,8 @@ components:
type: object
OpenapiCreateTagRequest:
properties:
bypass_rules:
type: boolean
message:
type: string
name:
@ -7477,8 +7501,6 @@ components:
type: string
decision:
$ref: '#/components/schemas/EnumPullReqReviewDecision'
message:
type: string
type: object
OpenapiReviewerAddPullReqRequest:
properties:
@ -7518,8 +7540,6 @@ components:
properties:
is_draft:
type: boolean
message:
type: string
state:
$ref: '#/components/schemas/EnumPullReqState'
type: object
@ -7794,7 +7814,7 @@ components:
RepoCommitFileAction:
properties:
action:
$ref: '#/components/schemas/GitrpcFileAction'
$ref: '#/components/schemas/GitFileAction'
encoding:
$ref: '#/components/schemas/EnumContentEncodingType'
path:
@ -7861,7 +7881,7 @@ components:
properties:
details:
items:
$ref: '#/components/schemas/GitrpcPathDetails'
$ref: '#/components/schemas/GitPathDetails'
nullable: true
type: array
type: object
@ -7994,6 +8014,12 @@ components:
properties:
commit_id:
type: string
dry_run_rules:
type: boolean
rule_violations:
items:
$ref: '#/components/schemas/TypesRuleViolations'
type: array
type: object
TypesConnector:
properties:
@ -8159,6 +8185,10 @@ components:
type: object
TypesMergeResponse:
properties:
allowed_methods:
items:
$ref: '#/components/schemas/EnumMergeMethod'
type: array
branch_deleted:
type: boolean
conflict_files:
@ -8457,6 +8487,8 @@ components:
type: string
TypesRuleViolations:
properties:
bypassable:
type: boolean
bypassed:
type: boolean
rule: