feat: [CDE-265]: SCM API Integration (#2610)

* feat: [CDE-265]: SCM API Integration
pull/3545/head
Deepesh Kumar 2024-08-29 05:20:59 +00:00 committed by Harness
parent 74e00cbcdf
commit bea4048d0e
10 changed files with 815 additions and 182 deletions

View File

@ -51,3 +51,29 @@
} }
} }
} }
.customTextInput {
:global {
[class*='TextInput--main'] {
margin-bottom: 0 !important;
height: inherit !important;
width: fit-content !important;
flex-grow: 1 !important;
border: none !important;
outline: none !important;
}
.bp3-input {
border: none !important;
outline: none !important;
padding-top: 0 !important;
padding-bottom: 0 !important;
background: transparent !important;
font-size: 14px !important;
}
.bp3-input:hover {
box-shadow: none !important;
}
}
}

View File

@ -16,6 +16,7 @@
/* eslint-disable */ /* eslint-disable */
// This is an auto-generated file // This is an auto-generated file
export declare const customTextInput: string
export declare const formFields: string export declare const formFields: string
export declare const leftElementClassName: string export declare const leftElementClassName: string
export declare const repoInput: string export declare const repoInput: string

View File

@ -14,22 +14,21 @@
* limitations under the License. * limitations under the License.
*/ */
import React, { useCallback, useEffect, useState } from 'react' import React, { useCallback, useEffect, useRef, useState } from 'react'
import cx from 'classnames' import { Container, FormikForm, Layout, Text, TextInput } from '@harnessio/uicore'
import { Container, FormikForm, FormInput, Layout } from '@harnessio/uicore' import { debounce, defaultTo, get } from 'lodash-es'
import { Color } from '@harnessio/design-system'
import { Icon } from '@harnessio/icons'
import { debounce, get } from 'lodash-es'
import { useFormikContext } from 'formik' import { useFormikContext } from 'formik'
import { Repository } from 'iconoir-react' import { GitFork, Repository } from 'iconoir-react'
import { Menu, MenuItem } from '@blueprintjs/core'
import { Color } from '@harnessio/design-system'
import { useStrings } from 'framework/strings' import { useStrings } from 'framework/strings'
import type { OpenapiCreateGitspaceRequest } from 'cde-gitness/services' import type { OpenapiCreateGitspaceRequest } from 'services/cde'
import { BranchInput } from 'cde-gitness/components/BranchInput/BranchInput' import { useListRepos, useListBranches, useRepoLookupForGitspace } from 'services/cde'
import { useRepoLookupForGitspace } from 'services/cde'
import { useGetCDEAPIParams } from 'cde-gitness/hooks/useGetCDEAPIParams' import { useGetCDEAPIParams } from 'cde-gitness/hooks/useGetCDEAPIParams'
import type { RepoQueryParams } from 'cde-gitness/pages/GitspaceCreate/CDECreateGitspace' import { scmOptions, SCMType, type RepoQueryParams } from 'cde-gitness/pages/GitspaceCreate/CDECreateGitspace'
import { useQueryParams } from 'hooks/useQueryParams' import { useQueryParams } from 'hooks/useQueryParams'
import { getRepoIdFromURL, getRepoNameFromURL, isValidUrl } from './CDEAnyGitImport.utils' import { getRepoIdFromURL, getRepoNameFromURL, isValidUrl } from './CDEAnyGitImport.utils'
import { GitspaceSelect } from '../GitspaceSelect/GitspaceSelect'
import css from './CDEAnyGitImport.module.scss' import css from './CDEAnyGitImport.module.scss'
enum RepoCheckStatus { enum RepoCheckStatus {
@ -40,15 +39,49 @@ enum RepoCheckStatus {
export const CDEAnyGitImport = () => { export const CDEAnyGitImport = () => {
const { getString } = useStrings() const { getString } = useStrings()
const repoQueryParams = useQueryParams<RepoQueryParams>() const repoQueryParams = useQueryParams<RepoQueryParams>()
const { setValues, setFieldError, values } = useFormikContext<OpenapiCreateGitspaceRequest>() const { setValues, setFieldError, values } = useFormikContext<OpenapiCreateGitspaceRequest>()
const { accountIdentifier = '', orgIdentifier = '', projectIdentifier = '' } = useGetCDEAPIParams() const { accountIdentifier = '', orgIdentifier = '', projectIdentifier = '' } = useGetCDEAPIParams()
const [searchTerm, setSearchTerm] = useState(values?.code_repo_url as string)
const [searchBranch, setSearchBranch] = useState(values?.branch as string)
const { mutate, loading } = useRepoLookupForGitspace({ const { mutate, loading } = useRepoLookupForGitspace({
accountIdentifier, accountIdentifier,
orgIdentifier, orgIdentifier,
projectIdentifier projectIdentifier
}) })
const { data: repoData, loading: repoLoading } = useListRepos({
accountIdentifier,
orgIdentifier,
projectIdentifier,
gitspace_identifier: '',
queryParams: {
search_term: searchTerm,
repo_type: values?.code_repo_type as string
},
debounce: 1000
})
const {
data: branchData,
loading: branchLoading,
refetch: refetchBranch
} = useListBranches({
accountIdentifier,
orgIdentifier,
projectIdentifier,
gitspace_identifier: '',
queryParams: {
search_term: searchBranch,
repo_type: values.code_repo_type || '',
repo_url: values.code_repo_url || ''
},
debounce: 1000,
lazy: true
})
const [repoCheckState, setRepoCheckState] = useState<RepoCheckStatus | undefined>() const [repoCheckState, setRepoCheckState] = useState<RepoCheckStatus | undefined>()
useEffect(() => { useEffect(() => {
@ -63,6 +96,12 @@ export const CDEAnyGitImport = () => {
} }
}, [values.code_repo_url, repoQueryParams.codeRepoURL]) }, [values.code_repo_url, repoQueryParams.codeRepoURL])
useEffect(() => {
if (searchBranch) {
refetchBranch()
}
}, [searchBranch])
const onChange = useCallback( const onChange = useCallback(
debounce(async (url: string, skipBranchUpdate?: boolean) => { debounce(async (url: string, skipBranchUpdate?: boolean) => {
let errorMessage = '' let errorMessage = ''
@ -103,15 +142,6 @@ export const CDEAnyGitImport = () => {
}) })
setRepoCheckState(RepoCheckStatus.Valid) setRepoCheckState(RepoCheckStatus.Valid)
} }
} else {
if (url?.trim()?.length) {
errorMessage = 'Invalid URL Format'
setRepoCheckState(RepoCheckStatus.InValid)
} else {
if (repoCheckState) {
setRepoCheckState(undefined)
}
}
} }
} catch (err) { } catch (err) {
errorMessage = get(err, 'message') || '' errorMessage = get(err, 'message') || ''
@ -121,43 +151,142 @@ export const CDEAnyGitImport = () => {
[repoCheckState, values?.code_repo_type] [repoCheckState, values?.code_repo_type]
) )
const branchRef = useRef<HTMLInputElement | null | undefined>()
const repoRef = useRef<HTMLInputElement | null | undefined>()
const scmOption = scmOptions.find(item => item.value === values.code_repo_type) as SCMType
return ( return (
<FormikForm> <FormikForm>
<Layout.Horizontal spacing="medium"> <Layout.Horizontal spacing="medium">
<Container width="63%" className={css.formFields}> <Container width="63%" className={css.formFields}>
<FormInput.Text <GitspaceSelect
name="code_repo_url" text={
inputGroup={{ <Container flex={{ alignItems: 'center' }} className={css.customTextInput}>
leftElement: (
<Container flex={{ alignItems: 'center' }}>
<Repository height={32} width={32} /> <Repository height={32} width={32} />
</Container> <TextInput
), inputRef={ref => (repoRef.current = ref)}
className: css.leftElementClassName, value={searchTerm}
rightElement: ( placeholder="enter url or type reop name"
<Container height={50} width={25} flex={{ alignItems: 'center' }}>
{loading ? (
<Icon name="loading" />
) : repoCheckState ? (
repoCheckState === RepoCheckStatus.Valid ? (
<Icon name="tick-circle" color={Color.GREEN_450} />
) : (
<Icon name="warning-sign" color={Color.ERROR} />
)
) : undefined}
</Container>
)
}}
placeholder={getString('cde.repository.repositoryURL')}
className={cx(css.repoInput)}
onChange={async event => { onChange={async event => {
const target = event.target as HTMLInputElement const target = event.target as HTMLInputElement
setSearchTerm(target?.value?.trim() || '')
await onChange(target.value) await onChange(target.value)
}} }}
/> />
</Container> </Container>
}
tooltipProps={{ isOpen: repoRef.current?.onfocus }}
rightIcon={
loading || repoLoading
? 'loading'
: repoCheckState
? repoCheckState === RepoCheckStatus.Valid
? 'tick-circle'
: 'warning-sign'
: 'chevron-down'
}
withoutCurrentColor
formikName="code_repo_url"
renderMenu={
<Menu>
{repoData?.repositories?.length ? (
repoData?.repositories?.map(item => {
return (
<MenuItem
key={item.name}
disabled={repoLoading}
text={
<Layout.Horizontal
spacing="large"
flex={{ justifyContent: 'flex-start', alignItems: 'center' }}>
<img
height={26}
width={26}
src={defaultTo(scmOption?.icon, '')}
style={{ marginRight: '10px' }}
/>
<Layout.Vertical>
<Text color={Color.BLACK}>{item.name}</Text>
<Text font={{ size: 'small' }}>{item.clone_url}</Text>
</Layout.Vertical>
</Layout.Horizontal>
}
onClick={() => {
setSearchTerm(item.name as string)
setValues((prvValues: any) => {
return {
...prvValues,
code_repo_url: item.clone_url,
branch: item.default_branch,
identifier: getRepoIdFromURL(item.clone_url),
name: getRepoNameFromURL(item.clone_url),
code_repo_type: values?.code_repo_type
}
})
setSearchBranch(item.default_branch as string)
refetchBranch()
}}
/>
)
})
) : loading || repoLoading ? (
<MenuItem text={<Text>Fetching Repositories</Text>} />
) : (
<MenuItem text={<Text>No Repositories Found</Text>} />
)}
</Menu>
}
/>
</Container>
<Container width="35%" className={css.formFields}> <Container width="35%" className={css.formFields}>
<BranchInput /> <GitspaceSelect
text={
<Container flex={{ alignItems: 'center' }} className={css.customTextInput}>
<GitFork height={32} width={32} />
<TextInput
inputRef={ref => (branchRef.current = ref)}
value={searchBranch}
placeholder="enter branch name"
onChange={async event => {
const target = event.target as HTMLInputElement
setSearchBranch(target?.value?.trim() || '')
}}
/>
</Container>
}
tooltipProps={{ isOpen: branchRef.current?.onfocus }}
rightIcon={loading || branchLoading ? 'loading' : 'chevron-down'}
withoutCurrentColor
formikName="branch"
renderMenu={
<Menu>
{(branchData as unknown as { branches: { name: string }[] })?.branches?.length ? (
(branchData as unknown as { branches: { name: string }[] })?.branches?.map(item => {
return (
<MenuItem
key={item.name}
text={<Text>{item.name}</Text>}
onClick={() => {
setSearchBranch(item.name as string)
setValues((prvValues: any) => {
return {
...prvValues,
branch: item.name
}
})
}}
/>
)
})
) : loading || repoLoading ? (
<MenuItem text={<Text>Fetching Branches</Text>} />
) : (
<MenuItem text={<Text>No Branches Found</Text>} />
)}
</Menu>
}
/>
</Container> </Container>
</Layout.Horizontal> </Layout.Horizontal>
</FormikForm> </FormikForm>

View File

@ -0,0 +1,165 @@
/*
* Copyright 2024 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, { useCallback, useEffect, useState } from 'react'
import cx from 'classnames'
import { Container, FormikForm, FormInput, Layout } from '@harnessio/uicore'
import { Color } from '@harnessio/design-system'
import { Icon } from '@harnessio/icons'
import { debounce, get } from 'lodash-es'
import { useFormikContext } from 'formik'
import { Repository } from 'iconoir-react'
import { useStrings } from 'framework/strings'
import type { OpenapiCreateGitspaceRequest } from 'cde-gitness/services'
import { BranchInput } from 'cde-gitness/components/BranchInput/BranchInput'
import { useRepoLookupForGitspace } from 'services/cde'
import { useGetCDEAPIParams } from 'cde-gitness/hooks/useGetCDEAPIParams'
import type { RepoQueryParams } from 'cde-gitness/pages/GitspaceCreate/CDECreateGitspace'
import { useQueryParams } from 'hooks/useQueryParams'
import { getRepoIdFromURL, getRepoNameFromURL, isValidUrl } from './CDEAnyGitImport.utils'
import css from './CDEAnyGitImport.module.scss'
enum RepoCheckStatus {
Valid = 'valid',
InValid = 'InValid'
}
export const CDEUnknownSCM = () => {
const { getString } = useStrings()
const repoQueryParams = useQueryParams<RepoQueryParams>()
const { setValues, setFieldError, values } = useFormikContext<OpenapiCreateGitspaceRequest>()
const { accountIdentifier = '', orgIdentifier = '', projectIdentifier = '' } = useGetCDEAPIParams()
const { mutate, loading } = useRepoLookupForGitspace({
accountIdentifier,
orgIdentifier,
projectIdentifier
})
const [repoCheckState, setRepoCheckState] = useState<RepoCheckStatus | undefined>()
useEffect(() => {
if (values?.code_repo_type) {
setRepoCheckState(undefined)
}
}, [values?.code_repo_type])
useEffect(() => {
if (values.code_repo_url === repoQueryParams.codeRepoURL && repoQueryParams.codeRepoURL) {
onChange(repoQueryParams.codeRepoURL as string, Boolean(repoQueryParams.branch))
}
}, [values.code_repo_url, repoQueryParams.codeRepoURL])
const onChange = useCallback(
debounce(async (url: string, skipBranchUpdate?: boolean) => {
let errorMessage = ''
try {
if (isValidUrl(url)) {
const response = (await mutate({ url, repo_type: values?.code_repo_type })) as {
is_private?: boolean
branch: string
url: string
}
if (!response?.branch) {
errorMessage = getString('cde.repository.privateRepoWarning')
setRepoCheckState(RepoCheckStatus.InValid)
setValues((prvValues: any) => {
return {
...prvValues,
code_repo_url: response.url,
branch: undefined,
identifier: undefined,
name: undefined,
code_repo_type: values?.code_repo_type
}
})
setTimeout(() => {
setFieldError('code_repo_url', errorMessage)
}, 500)
} else {
const branchValue = skipBranchUpdate ? {} : { branch: response.branch }
setValues((prvValues: any) => {
return {
...prvValues,
code_repo_url: response.url,
...branchValue,
identifier: getRepoIdFromURL(response.url),
name: getRepoNameFromURL(response.url),
code_repo_type: values?.code_repo_type
}
})
setRepoCheckState(RepoCheckStatus.Valid)
}
} else {
if (url?.trim()?.length) {
errorMessage = 'Invalid URL Format'
setRepoCheckState(RepoCheckStatus.InValid)
} else {
if (repoCheckState) {
setRepoCheckState(undefined)
}
}
}
} catch (err) {
errorMessage = get(err, 'message') || ''
}
setFieldError('code_repo_url', errorMessage)
}, 1000),
[repoCheckState, values?.code_repo_type]
)
return (
<FormikForm>
<Layout.Horizontal spacing="medium">
<Container width="63%" className={css.formFields}>
<FormInput.Text
name="code_repo_url"
inputGroup={{
leftElement: (
<Container flex={{ alignItems: 'center' }}>
<Repository height={32} width={32} />
</Container>
),
className: css.leftElementClassName,
rightElement: (
<Container height={50} width={25} flex={{ alignItems: 'center' }}>
{loading ? (
<Icon name="loading" />
) : repoCheckState ? (
repoCheckState === RepoCheckStatus.Valid ? (
<Icon name="tick-circle" color={Color.GREEN_450} />
) : (
<Icon name="warning-sign" color={Color.ERROR} />
)
) : undefined}
</Container>
)
}}
placeholder={getString('cde.repository.repositoryURL')}
className={cx(css.repoInput)}
onChange={async event => {
const target = event.target as HTMLInputElement
await onChange(target.value)
}}
/>
</Container>
<Container width="35%" className={css.formFields}>
<BranchInput />
</Container>
</Layout.Horizontal>
</FormikForm>
)
}

View File

@ -66,6 +66,4 @@ export const CDECustomDropdown = ({ label, menu, leftElement, overridePopOverWid
</Container> </Container>
</Layout.Horizontal> </Layout.Horizontal>
) )
return <div>CDECustomDropdown</div>
} }

View File

@ -53,7 +53,8 @@ export const CDESSHSelect = () => {
const { data, loading, refetch } = useListAggregatedTokens({ const { data, loading, refetch } = useListAggregatedTokens({
queryParams: { queryParams: {
accountIdentifier, accountIdentifier,
apiKeyType: 'SSH_KEY' apiKeyType: 'SSH_KEY',
parentIdentifier: currentUser.uid
} }
}) })
@ -65,7 +66,7 @@ export const CDESSHSelect = () => {
queryParams: { queryParams: {
accountIdentifier, accountIdentifier,
apiKeyType: 'SSH_KEY', apiKeyType: 'SSH_KEY',
parentIdentifier: currentUser.uid || 'cWQVVVCET4iwomT4hRoj4w', parentIdentifier: currentUser.uid,
apiKeyIdentifier: `cdesshkey` apiKeyIdentifier: `cdesshkey`
} }
}) })
@ -108,7 +109,7 @@ export const CDESSHSelect = () => {
tags: {}, tags: {},
accountIdentifier, accountIdentifier,
apiKeyIdentifier: `cdesshkey`, apiKeyIdentifier: `cdesshkey`,
parentIdentifier: currentUser.uid || 'cWQVVVCET4iwomT4hRoj4w', parentIdentifier: currentUser.uid,
apiKeyType: 'SSH_KEY', apiKeyType: 'SSH_KEY',
sshKeyContent: value.sshKeyValue, sshKeyContent: value.sshKeyValue,
sshKeyUsage: ['AUTH'], sshKeyUsage: ['AUTH'],

View File

@ -35,14 +35,18 @@ interface GitspaceSelectProps {
loading?: boolean loading?: boolean
buttonClassName?: string buttonClassName?: string
withoutCurrentColor?: boolean withoutCurrentColor?: boolean
hideMenu?: boolean
rightIcon?: IconName
} }
export const GitspaceSelect = ({ export const GitspaceSelect = ({
text, text,
icon, icon,
loading, loading,
hideMenu,
renderMenu, renderMenu,
disabled, disabled,
rightIcon,
overridePopOverWidth, overridePopOverWidth,
formikName, formikName,
tooltipProps, tooltipProps,
@ -54,7 +58,9 @@ export const GitspaceSelect = ({
const buttonRef = useRef<HTMLDivElement | null>(null) const buttonRef = useRef<HTMLDivElement | null>(null)
const [popoverWidth, setPopoverWidth] = useState(0) const [popoverWidth, setPopoverWidth] = useState(0)
const defaultTooltipProps = { const defaultTooltipProps = hideMenu
? {}
: {
tooltip: ( tooltip: (
<Container className={css.listContainer} width={overridePopOverWidth ? '100%' : popoverWidth}> <Container className={css.listContainer} width={overridePopOverWidth ? '100%' : popoverWidth}>
{renderMenu ? ( {renderMenu ? (
@ -98,7 +104,7 @@ export const GitspaceSelect = ({
<Button <Button
className={cx(css.button, buttonClassName, { [css.buttonWithoutIcon]: !icon })} className={cx(css.button, buttonClassName, { [css.buttonWithoutIcon]: !icon })}
text={text} text={text}
rightIcon={loading ? 'loading' : 'chevron-down'} rightIcon={rightIcon ? rightIcon : loading ? 'loading' : 'chevron-down'}
variation={ButtonVariation.TERTIARY} variation={ButtonVariation.TERTIARY}
iconProps={{ size: 14 }} iconProps={{ size: 14 }}
{...iconProp} {...iconProp}

View File

@ -34,16 +34,16 @@ import { CDEIDESelect } from 'cde-gitness/components/CDEIDESelect/CDEIDESelect'
import { SelectInfraProvider } from 'cde-gitness/components/SelectInfraProvider/SelectInfraProvider' import { SelectInfraProvider } from 'cde-gitness/components/SelectInfraProvider/SelectInfraProvider'
import { OpenapiCreateGitspaceRequest, useCreateGitspace } from 'services/cde' import { OpenapiCreateGitspaceRequest, useCreateGitspace } from 'services/cde'
import { useGetCDEAPIParams } from 'cde-gitness/hooks/useGetCDEAPIParams' import { useGetCDEAPIParams } from 'cde-gitness/hooks/useGetCDEAPIParams'
import { GitnessRepoImportForm } from 'cde-gitness/components/GitnessRepoImportForm/GitnessRepoImportForm'
import { EnumGitspaceCodeRepoType, StandaloneIDEType } from 'cde-gitness/constants' import { EnumGitspaceCodeRepoType, StandaloneIDEType } from 'cde-gitness/constants'
import { CDESSHSelect } from 'cde-gitness/components/CDESSHSelect/CDESSHSelect' import { CDESSHSelect } from 'cde-gitness/components/CDESSHSelect/CDESSHSelect'
import { useQueryParams } from 'hooks/useQueryParams' import { useQueryParams } from 'hooks/useQueryParams'
import { getRepoIdFromURL, getRepoNameFromURL } from 'cde-gitness/components/CDEAnyGitImport/CDEAnyGitImport.utils' import { getRepoIdFromURL, getRepoNameFromURL } from 'cde-gitness/components/CDEAnyGitImport/CDEAnyGitImport.utils'
import { CDEUnknownSCM } from 'cde-gitness/components/CDEAnyGitImport/CDEUnknownSCM'
import { gitnessFormInitialValues } from './GitspaceCreate.constants' import { gitnessFormInitialValues } from './GitspaceCreate.constants'
import { validateGitnessForm } from './GitspaceCreate.utils' import { validateGitnessForm } from './GitspaceCreate.utils'
import css from './GitspaceCreate.module.scss' import css from './GitspaceCreate.module.scss'
interface SCMType { export interface SCMType {
name: string name: string
value: EnumGitspaceCodeRepoType value: EnumGitspaceCodeRepoType
icon: string icon: string
@ -57,6 +57,14 @@ export interface RepoQueryParams {
codeRepoType?: EnumGitspaceCodeRepoType codeRepoType?: EnumGitspaceCodeRepoType
} }
export const scmOptions: SCMType[] = [
{ name: 'Harness Code', value: EnumGitspaceCodeRepoType.HARNESS_CODE, icon: harnessCode },
{ name: 'GitHub Cloud', value: EnumGitspaceCodeRepoType.GITHUB, icon: github },
{ name: 'GitLab Cloud', value: EnumGitspaceCodeRepoType.GITLAB, icon: gitlab },
{ name: 'Bitbucket', value: EnumGitspaceCodeRepoType.BITBUCKET, icon: bitbucket },
{ name: 'Any public Git repository', value: EnumGitspaceCodeRepoType.UNKNOWN, icon: genericGit }
]
export const CDECreateGitspace = () => { export const CDECreateGitspace = () => {
const { getString } = useStrings() const { getString } = useStrings()
const { routes, currentUserProfileURL, hooks, currentUser } = useAppContext() const { routes, currentUserProfileURL, hooks, currentUser } = useAppContext()
@ -70,14 +78,6 @@ export const CDECreateGitspace = () => {
const [repoURLviaQueryParam, setrepoURLviaQueryParam] = useState<RepoQueryParams>({ ...repoQueryParams }) const [repoURLviaQueryParam, setrepoURLviaQueryParam] = useState<RepoQueryParams>({ ...repoQueryParams })
const scmOptions: SCMType[] = [
{ name: 'Harness Code', value: EnumGitspaceCodeRepoType.HARNESS_CODE, icon: harnessCode },
{ name: 'GitHub Cloud', value: EnumGitspaceCodeRepoType.GITHUB, icon: github },
{ name: 'GitLab Cloud', value: EnumGitspaceCodeRepoType.GITLAB, icon: gitlab },
{ name: 'Bitbucket', value: EnumGitspaceCodeRepoType.BITBUCKET, icon: bitbucket },
{ name: 'Any public Git repository', value: EnumGitspaceCodeRepoType.UNKNOWN, icon: genericGit }
]
const { data: OauthSCMs } = useGetUserSourceCodeManagers({ const { data: OauthSCMs } = useGetUserSourceCodeManagers({
queryParams: { accountIdentifier, userIdentifier: currentUser?.uid } queryParams: { accountIdentifier, userIdentifier: currentUser?.uid }
}) })
@ -239,8 +239,8 @@ export const CDECreateGitspace = () => {
</Container> </Container>
<CDEAnyGitImport /> <CDEAnyGitImport />
</Layout.Vertical> </Layout.Vertical>
) : scmOption.name === 'Harness Code' ? ( ) : scmOption.value === EnumGitspaceCodeRepoType.UNKNOWN ? (
<GitnessRepoImportForm isCDE /> <CDEUnknownSCM />
) : ( ) : (
<CDEAnyGitImport /> <CDEAnyGitImport />
)} )}

View File

@ -69,8 +69,6 @@ export type EnumIDETypeType2 = 'vsCode' | 'vsCodeWeb'
export type EnumInfraProviderType = 'docker' | 'harness_gcp' | 'harness_cloud' export type EnumInfraProviderType = 'docker' | 'harness_gcp' | 'harness_cloud'
export type EnumProviderType = 'harnessGCP' | 'k8s' | 'harnessOVHCloud' | 'docker'
export interface InfraproviderResourceInput { export interface InfraproviderResourceInput {
cpu?: string | null cpu?: string | null
disk?: string | null disk?: string | null
@ -117,34 +115,10 @@ export interface OpenapiCreateInfraProviderConfigRequest {
type?: EnumInfraProviderType type?: EnumInfraProviderType
} }
export interface OpenapiCreateInfraProviderResponse {
created?: number
id?: string
metadata?: string
name?: string
space_path?: string
type?: EnumProviderType
updated?: number
}
export interface OpenapiCreateInfraProviderTemplateRequest { export interface OpenapiCreateInfraProviderTemplateRequest {
created?: number
data?: string data?: string
description?: string description?: string
identifier?: string identifier?: string
space_id?: number
space_path?: string
updated?: number
}
export interface OpenapiCreateInfraProviderTemplateResponse {
created?: number
data?: string
description?: string
identifier?: string
space_id?: number
space_path?: string
updated?: number
} }
export interface OpenapiGetCodeRepositoryRequest { export interface OpenapiGetCodeRepositoryRequest {
@ -159,6 +133,8 @@ export interface OpenapiGetCodeRepositoryResponse {
url?: string url?: string
} }
export type OpenapiGetGitspaceLogsResponse = string | null
export interface OpenapiGetGitspaceResponse { export interface OpenapiGetGitspaceResponse {
access_key?: string access_key?: string
access_type?: EnumGitspaceAccessTypeType2 access_type?: EnumGitspaceAccessTypeType2
@ -212,6 +188,10 @@ export interface ScmCodeRepositoryResponse {
url?: string url?: string
} }
export interface TypesBranchResponse {
name?: string
}
export interface TypesGitspaceConfig { export interface TypesGitspaceConfig {
branch?: string branch?: string
code_repo_is_private?: boolean code_repo_is_private?: boolean
@ -262,7 +242,7 @@ export interface TypesGitspaceEventResponse {
timestamp?: number timestamp?: number
} }
export interface TypesGitspaceInstance { export type TypesGitspaceInstance = {
access_key?: string | null access_key?: string | null
access_key_ref?: string | null access_key_ref?: string | null
access_type?: EnumGitspaceAccessType access_type?: EnumGitspaceAccessType
@ -277,7 +257,7 @@ export interface TypesGitspaceInstance {
tracked_changes?: string | null tracked_changes?: string | null
updated?: number updated?: number
url?: string | null url?: string | null
} } | null
export interface TypesInfraProviderConfig { export interface TypesInfraProviderConfig {
created?: number created?: number
@ -313,8 +293,29 @@ export interface TypesInfraProviderResource {
updated?: number updated?: number
} }
export interface TypesInfraProviderResourceType2 { export interface TypesInfraProviderTemplate {
[key: string]: any config_identifier?: string
created?: number
data?: string
description?: string
identifier?: string
space_id?: number
space_path?: string
updated?: number
}
export interface TypesListBranchesResponse {
branches?: TypesBranchResponse[] | null
}
export interface TypesListRepoResponse {
repositories?: TypesRepoResponse[] | null
}
export interface TypesRepoResponse {
clone_url?: string
default_branch?: string
name?: string
} }
export interface UsererrorError { export interface UsererrorError {
@ -904,6 +905,168 @@ export const useGetGitspaceEvents = ({
} }
) )
export interface ListBranchesQueryParams {
/**
* Repository type: github, gitlab, bitbucket, harness_code, unknown
*/
repo_type: string
/**
* Repository URL
*/
repo_url: string
/**
* Term to search
*/
search_term: string
}
export interface ListBranchesPathParams {
/**
* account identifier.
*/
accountIdentifier: string
/**
* org identifier.
*/
orgIdentifier: string
/**
* project identifier.
*/
projectIdentifier: string
/**
* gitspace identifier.
*/
gitspace_identifier: string
}
export type ListBranchesProps = Omit<
GetProps<TypesListRepoResponse, UsererrorError, ListBranchesQueryParams, ListBranchesPathParams>,
'path'
> &
ListBranchesPathParams
/**
* List repositories
*/
export const ListBranches = ({
accountIdentifier,
orgIdentifier,
projectIdentifier,
gitspace_identifier,
...props
}: ListBranchesProps) => (
<Get<TypesListRepoResponse, UsererrorError, ListBranchesQueryParams, ListBranchesPathParams>
path={`/accounts/${accountIdentifier}/orgs/${orgIdentifier}/projects/${projectIdentifier}/gitspaces/${gitspace_identifier}/list-branches`}
base={getConfig('cde/api/v1')}
{...props}
/>
)
export type UseListBranchesProps = Omit<
UseGetProps<TypesListRepoResponse, UsererrorError, ListBranchesQueryParams, ListBranchesPathParams>,
'path'
> &
ListBranchesPathParams
/**
* List repositories
*/
export const useListBranches = ({
accountIdentifier,
orgIdentifier,
projectIdentifier,
gitspace_identifier,
...props
}: UseListBranchesProps) =>
useGet<TypesListRepoResponse, UsererrorError, ListBranchesQueryParams, ListBranchesPathParams>(
(paramsInPath: ListBranchesPathParams) =>
`/accounts/${paramsInPath.accountIdentifier}/orgs/${paramsInPath.orgIdentifier}/projects/${paramsInPath.projectIdentifier}/gitspaces/list-branches`,
{
base: getConfig('cde/api/v1'),
pathParams: { accountIdentifier, orgIdentifier, projectIdentifier, gitspace_identifier },
...props
}
)
export interface ListReposQueryParams {
/**
* Repository type: github, gitlab, bitbucket, harness_code, unknown
*/
repo_type: string
/**
* Term to search
*/
search_term: string
}
export interface ListReposPathParams {
/**
* account identifier.
*/
accountIdentifier: string
/**
* org identifier.
*/
orgIdentifier: string
/**
* project identifier.
*/
projectIdentifier: string
/**
* gitspace identifier.
*/
gitspace_identifier: string
}
export type ListReposProps = Omit<
GetProps<TypesListRepoResponse, UsererrorError, ListReposQueryParams, ListReposPathParams>,
'path'
> &
ListReposPathParams
/**
* List repositories
*/
export const ListRepos = ({
accountIdentifier,
orgIdentifier,
projectIdentifier,
gitspace_identifier,
...props
}: ListReposProps) => (
<Get<TypesListRepoResponse, UsererrorError, ListReposQueryParams, ListReposPathParams>
path={`/accounts/${accountIdentifier}/orgs/${orgIdentifier}/projects/${projectIdentifier}/gitspaces/${gitspace_identifier}/list-repos`}
base={getConfig('cde/api/v1')}
{...props}
/>
)
export type UseListReposProps = Omit<
UseGetProps<TypesListRepoResponse, UsererrorError, ListReposQueryParams, ListReposPathParams>,
'path'
> &
ListReposPathParams
/**
* List repositories
*/
export const useListRepos = ({
accountIdentifier,
orgIdentifier,
projectIdentifier,
gitspace_identifier,
...props
}: UseListReposProps) =>
useGet<TypesListRepoResponse, UsererrorError, ListReposQueryParams, ListReposPathParams>(
(paramsInPath: ListReposPathParams) =>
`/accounts/${paramsInPath.accountIdentifier}/orgs/${paramsInPath.orgIdentifier}/projects/${paramsInPath.projectIdentifier}/gitspaces/list-repos`,
{
base: getConfig('cde/api/v1'),
pathParams: { accountIdentifier, orgIdentifier, projectIdentifier, gitspace_identifier },
...props
}
)
export interface GetGitspaceInstanceLogsPathParams { export interface GetGitspaceInstanceLogsPathParams {
/** /**
* account identifier. * account identifier.
@ -924,7 +1087,7 @@ export interface GetGitspaceInstanceLogsPathParams {
} }
export type GetGitspaceInstanceLogsProps = Omit< export type GetGitspaceInstanceLogsProps = Omit<
GetProps<string, unknown, void, GetGitspaceInstanceLogsPathParams>, GetProps<OpenapiGetGitspaceLogsResponse, unknown, void, GetGitspaceInstanceLogsPathParams>,
'path' 'path'
> & > &
GetGitspaceInstanceLogsPathParams GetGitspaceInstanceLogsPathParams
@ -939,7 +1102,7 @@ export const GetGitspaceInstanceLogs = ({
gitspace_identifier, gitspace_identifier,
...props ...props
}: GetGitspaceInstanceLogsProps) => ( }: GetGitspaceInstanceLogsProps) => (
<Get<string, unknown, void, GetGitspaceInstanceLogsPathParams> <Get<OpenapiGetGitspaceLogsResponse, unknown, void, GetGitspaceInstanceLogsPathParams>
path={`/accounts/${accountIdentifier}/orgs/${orgIdentifier}/projects/${projectIdentifier}/gitspaces/${gitspace_identifier}/logs`} path={`/accounts/${accountIdentifier}/orgs/${orgIdentifier}/projects/${projectIdentifier}/gitspaces/${gitspace_identifier}/logs`}
base={getConfig('cde/api/v1')} base={getConfig('cde/api/v1')}
{...props} {...props}
@ -947,7 +1110,7 @@ export const GetGitspaceInstanceLogs = ({
) )
export type UseGetGitspaceInstanceLogsProps = Omit< export type UseGetGitspaceInstanceLogsProps = Omit<
UseGetProps<string, unknown, void, GetGitspaceInstanceLogsPathParams>, UseGetProps<OpenapiGetGitspaceLogsResponse, unknown, void, GetGitspaceInstanceLogsPathParams>,
'path' 'path'
> & > &
GetGitspaceInstanceLogsPathParams GetGitspaceInstanceLogsPathParams
@ -962,7 +1125,7 @@ export const useGetGitspaceInstanceLogs = ({
gitspace_identifier, gitspace_identifier,
...props ...props
}: UseGetGitspaceInstanceLogsProps) => }: UseGetGitspaceInstanceLogsProps) =>
useGet<string, unknown, void, GetGitspaceInstanceLogsPathParams>( useGet<OpenapiGetGitspaceLogsResponse, unknown, void, GetGitspaceInstanceLogsPathParams>(
(paramsInPath: GetGitspaceInstanceLogsPathParams) => (paramsInPath: GetGitspaceInstanceLogsPathParams) =>
`/accounts/${paramsInPath.accountIdentifier}/orgs/${paramsInPath.orgIdentifier}/projects/${paramsInPath.projectIdentifier}/gitspaces/${paramsInPath.gitspace_identifier}/logs`, `/accounts/${paramsInPath.accountIdentifier}/orgs/${paramsInPath.orgIdentifier}/projects/${paramsInPath.projectIdentifier}/gitspaces/${paramsInPath.gitspace_identifier}/logs`,
{ {
@ -1134,7 +1297,7 @@ export interface ListInfraProvidersPathParams {
} }
export type ListInfraProvidersProps = Omit< export type ListInfraProvidersProps = Omit<
GetProps<OpenapiCreateInfraProviderResponse[], unknown, void, ListInfraProvidersPathParams>, GetProps<TypesInfraProviderConfig[], unknown, void, ListInfraProvidersPathParams>,
'path' 'path'
> & > &
ListInfraProvidersPathParams ListInfraProvidersPathParams
@ -1148,7 +1311,7 @@ export const ListInfraProviders = ({
projectIdentifier, projectIdentifier,
...props ...props
}: ListInfraProvidersProps) => ( }: ListInfraProvidersProps) => (
<Get<OpenapiCreateInfraProviderResponse[], unknown, void, ListInfraProvidersPathParams> <Get<TypesInfraProviderConfig[], unknown, void, ListInfraProvidersPathParams>
path={`/accounts/${accountIdentifier}/orgs/${orgIdentifier}/projects/${projectIdentifier}/infraproviders`} path={`/accounts/${accountIdentifier}/orgs/${orgIdentifier}/projects/${projectIdentifier}/infraproviders`}
base={getConfig('cde/api/v1')} base={getConfig('cde/api/v1')}
{...props} {...props}
@ -1156,7 +1319,7 @@ export const ListInfraProviders = ({
) )
export type UseListInfraProvidersProps = Omit< export type UseListInfraProvidersProps = Omit<
UseGetProps<OpenapiCreateInfraProviderResponse[], unknown, void, ListInfraProvidersPathParams>, UseGetProps<TypesInfraProviderConfig[], unknown, void, ListInfraProvidersPathParams>,
'path' 'path'
> & > &
ListInfraProvidersPathParams ListInfraProvidersPathParams
@ -1170,7 +1333,7 @@ export const useListInfraProviders = ({
projectIdentifier, projectIdentifier,
...props ...props
}: UseListInfraProvidersProps) => }: UseListInfraProvidersProps) =>
useGet<OpenapiCreateInfraProviderResponse[], unknown, void, ListInfraProvidersPathParams>( useGet<TypesInfraProviderConfig[], unknown, void, ListInfraProvidersPathParams>(
(paramsInPath: ListInfraProvidersPathParams) => (paramsInPath: ListInfraProvidersPathParams) =>
`/accounts/${paramsInPath.accountIdentifier}/orgs/${paramsInPath.orgIdentifier}/projects/${paramsInPath.projectIdentifier}/infraproviders`, `/accounts/${paramsInPath.accountIdentifier}/orgs/${paramsInPath.orgIdentifier}/projects/${paramsInPath.projectIdentifier}/infraproviders`,
{ base: getConfig('cde/api/v1'), pathParams: { accountIdentifier, orgIdentifier, projectIdentifier }, ...props } { base: getConfig('cde/api/v1'), pathParams: { accountIdentifier, orgIdentifier, projectIdentifier }, ...props }
@ -1348,7 +1511,7 @@ export interface CreateInfraProviderResourcePathParams {
} }
export type CreateInfraProviderResourceProps = Omit< export type CreateInfraProviderResourceProps = Omit<
MutateProps<TypesInfraProviderResourceType2[], unknown, void, void, CreateInfraProviderResourcePathParams>, MutateProps<TypesInfraProviderResource[], unknown, void, void, CreateInfraProviderResourcePathParams>,
'path' | 'verb' 'path' | 'verb'
> & > &
CreateInfraProviderResourcePathParams CreateInfraProviderResourcePathParams
@ -1363,7 +1526,7 @@ export const CreateInfraProviderResource = ({
infraprovider_identifier, infraprovider_identifier,
...props ...props
}: CreateInfraProviderResourceProps) => ( }: CreateInfraProviderResourceProps) => (
<Mutate<TypesInfraProviderResourceType2[], unknown, void, void, CreateInfraProviderResourcePathParams> <Mutate<TypesInfraProviderResource[], unknown, void, void, CreateInfraProviderResourcePathParams>
verb="POST" verb="POST"
path={`/accounts/${accountIdentifier}/orgs/${orgIdentifier}/projects/${projectIdentifier}/infraproviders/${infraprovider_identifier}/resources`} path={`/accounts/${accountIdentifier}/orgs/${orgIdentifier}/projects/${projectIdentifier}/infraproviders/${infraprovider_identifier}/resources`}
base={getConfig('cde/api/v1')} base={getConfig('cde/api/v1')}
@ -1372,7 +1535,7 @@ export const CreateInfraProviderResource = ({
) )
export type UseCreateInfraProviderResourceProps = Omit< export type UseCreateInfraProviderResourceProps = Omit<
UseMutateProps<TypesInfraProviderResourceType2[], unknown, void, void, CreateInfraProviderResourcePathParams>, UseMutateProps<TypesInfraProviderResource[], unknown, void, void, CreateInfraProviderResourcePathParams>,
'path' | 'verb' 'path' | 'verb'
> & > &
CreateInfraProviderResourcePathParams CreateInfraProviderResourcePathParams
@ -1387,7 +1550,7 @@ export const useCreateInfraProviderResource = ({
infraprovider_identifier, infraprovider_identifier,
...props ...props
}: UseCreateInfraProviderResourceProps) => }: UseCreateInfraProviderResourceProps) =>
useMutate<TypesInfraProviderResourceType2[], unknown, void, void, CreateInfraProviderResourcePathParams>( useMutate<TypesInfraProviderResource[], unknown, void, void, CreateInfraProviderResourcePathParams>(
'POST', 'POST',
(paramsInPath: CreateInfraProviderResourcePathParams) => (paramsInPath: CreateInfraProviderResourcePathParams) =>
`/accounts/${paramsInPath.accountIdentifier}/orgs/${paramsInPath.orgIdentifier}/projects/${paramsInPath.projectIdentifier}/infraproviders/${paramsInPath.infraprovider_identifier}/resources`, `/accounts/${paramsInPath.accountIdentifier}/orgs/${paramsInPath.orgIdentifier}/projects/${paramsInPath.projectIdentifier}/infraproviders/${paramsInPath.infraprovider_identifier}/resources`,

View File

@ -464,6 +464,148 @@ paths:
summary: Get gitspace events summary: Get gitspace events
tags: tags:
- gitspaces - gitspaces
/accounts/{accountIdentifier}/orgs/{orgIdentifier}/projects/{projectIdentifier}/gitspaces/{gitspace_identifier}/list-branches:
get:
operationId: listBranches
parameters:
- description: account identifier.
in: path
name: accountIdentifier
required: true
schema:
type: string
- description: org identifier.
in: path
name: orgIdentifier
required: true
schema:
type: string
- description: project identifier.
in: path
name: projectIdentifier
required: true
schema:
type: string
- description: gitspace identifier.
in: path
name: gitspace_identifier
required: true
schema:
type: string
- description: 'Repository type: github, gitlab, bitbucket, harness_code, unknown'
in: query
name: repo_type
required: true
schema:
type: string
- description: Repository URL
in: query
name: repo_url
required: true
schema:
type: string
- description: Term to search
in: query
name: search_term
required: true
schema:
type: string
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/TypesListRepoResponse'
description: OK
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/UsererrorError'
description: Bad Request
'404':
content:
application/json:
schema:
$ref: '#/components/schemas/UsererrorError'
description: Not Found
'500':
content:
application/json:
schema:
$ref: '#/components/schemas/UsererrorError'
description: Internal Server Error
summary: List repositories
tags:
- scm
/accounts/{accountIdentifier}/orgs/{orgIdentifier}/projects/{projectIdentifier}/gitspaces/{gitspace_identifier}/list-repos:
get:
operationId: listRepos
parameters:
- description: account identifier.
in: path
name: accountIdentifier
required: true
schema:
type: string
- description: org identifier.
in: path
name: orgIdentifier
required: true
schema:
type: string
- description: project identifier.
in: path
name: projectIdentifier
required: true
schema:
type: string
- description: gitspace identifier.
in: path
name: gitspace_identifier
required: true
schema:
type: string
- description: 'Repository type: github, gitlab, bitbucket, harness_code, unknown'
in: query
name: repo_type
required: true
schema:
type: string
- description: Term to search
in: query
name: search_term
required: true
schema:
type: string
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/TypesListRepoResponse'
description: OK
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/UsererrorError'
description: Bad Request
'404':
content:
application/json:
schema:
$ref: '#/components/schemas/UsererrorError'
description: Not Found
'500':
content:
application/json:
schema:
$ref: '#/components/schemas/UsererrorError'
description: Internal Server Error
summary: List repositories
tags:
- scm
/accounts/{accountIdentifier}/orgs/{orgIdentifier}/projects/{projectIdentifier}/gitspaces/{gitspace_identifier}/logs: /accounts/{accountIdentifier}/orgs/{orgIdentifier}/projects/{projectIdentifier}/gitspaces/{gitspace_identifier}/logs:
get: get:
operationId: getGitspaceInstanceLogs operationId: getGitspaceInstanceLogs
@ -497,7 +639,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
type: string $ref: '#/components/schemas/OpenapiGetGitspaceLogsResponse'
description: OK description: OK
summary: Get gitspace instance logs summary: Get gitspace instance logs
tags: tags:
@ -629,7 +771,7 @@ paths:
application/json: application/json:
schema: schema:
items: items:
$ref: '#/components/schemas/OpenapiCreateInfraProviderResponse' $ref: '#/components/schemas/TypesInfraProviderConfig'
type: array type: array
description: OK description: OK
summary: List infraproviders summary: List infraproviders
@ -785,7 +927,7 @@ paths:
application/json: application/json:
schema: schema:
items: items:
$ref: '#/components/schemas/TypesInfraProviderResourceType2' $ref: '#/components/schemas/TypesInfraProviderResource'
type: array type: array
description: Created description: Created
summary: Create InfraProvider Resource summary: Create InfraProvider Resource
@ -891,13 +1033,6 @@ components:
- harness_gcp - harness_gcp
- harness_cloud - harness_cloud
type: string type: string
EnumProviderType:
enum:
- harnessGCP
- k8s
- harnessOVHCloud
- docker
type: string
InfraproviderResourceInput: InfraproviderResourceInput:
properties: properties:
cpu: cpu:
@ -993,56 +1128,14 @@ components:
type: type:
$ref: '#/components/schemas/EnumInfraProviderType' $ref: '#/components/schemas/EnumInfraProviderType'
type: object type: object
OpenapiCreateInfraProviderResponse:
properties:
created:
type: integer
id:
type: string
metadata:
type: string
name:
type: string
space_path:
type: string
type:
$ref: '#/components/schemas/EnumProviderType'
updated:
type: integer
type: object
OpenapiCreateInfraProviderTemplateRequest: OpenapiCreateInfraProviderTemplateRequest:
properties: properties:
created:
type: integer
data: data:
type: string type: string
description: description:
type: string type: string
identifier: identifier:
type: string type: string
space_id:
type: integer
space_path:
type: string
updated:
type: integer
type: object
OpenapiCreateInfraProviderTemplateResponse:
properties:
created:
type: integer
data:
type: string
description:
type: string
identifier:
type: string
space_id:
type: integer
space_path:
type: string
updated:
type: integer
type: object type: object
OpenapiGetCodeRepositoryRequest: OpenapiGetCodeRepositoryRequest:
properties: properties:
@ -1062,6 +1155,9 @@ components:
url: url:
type: string type: string
type: object type: object
OpenapiGetGitspaceLogsResponse:
nullable: true
type: string
OpenapiGetGitspaceResponse: OpenapiGetGitspaceResponse:
properties: properties:
access_key: access_key:
@ -1149,6 +1245,11 @@ components:
url: url:
type: string type: string
type: object type: object
TypesBranchResponse:
properties:
name:
type: string
type: object
TypesGitspaceConfig: TypesGitspaceConfig:
properties: properties:
branch: branch:
@ -1243,6 +1344,7 @@ components:
type: integer type: integer
type: object type: object
TypesGitspaceInstance: TypesGitspaceInstance:
nullable: true
properties: properties:
access_key: access_key:
nullable: true nullable: true
@ -1349,7 +1451,49 @@ components:
updated: updated:
type: integer type: integer
type: object type: object
TypesInfraProviderResourceType2: TypesInfraProviderTemplate:
properties:
config_identifier:
type: string
created:
type: integer
data:
type: string
description:
type: string
identifier:
type: string
space_id:
type: integer
space_path:
type: string
updated:
type: integer
type: object
TypesListBranchesResponse:
properties:
branches:
items:
$ref: '#/components/schemas/TypesBranchResponse'
nullable: true
type: array
type: object
TypesListRepoResponse:
properties:
repositories:
items:
$ref: '#/components/schemas/TypesRepoResponse'
nullable: true
type: array
type: object
TypesRepoResponse:
properties:
clone_url:
type: string
default_branch:
type: string
name:
type: string
type: object type: object
UsererrorError: UsererrorError:
properties: properties: