mirror of
https://github.com/harness/drone.git
synced 2025-05-10 22:21:22 +08:00
run pipeline integration
This commit is contained in:
parent
7735f2b7a7
commit
b0a4946d80
@ -39,7 +39,7 @@ const PluginCategories: PluginInterface[] = [
|
||||
{ category: PluginCategory.Drone, name: 'Drone', description: 'Run Drone plugins', icon: 'ci-infra' }
|
||||
]
|
||||
|
||||
const pluginSpecMock = {
|
||||
const dronePluginSpecMock = {
|
||||
inputs: {
|
||||
channel: {
|
||||
type: 'string'
|
||||
@ -61,6 +61,14 @@ const pluginSpecMock = {
|
||||
]
|
||||
}
|
||||
|
||||
const runStepSpec = {
|
||||
inputs: {
|
||||
script: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface PluginsPanelInterface {
|
||||
onPluginAddUpdate?: (isUpdate: boolean, pluginFormData: Record<string, any>) => void
|
||||
}
|
||||
@ -101,6 +109,9 @@ export const PluginsPanel = ({ onPluginAddUpdate }: PluginsPanelInterface): JSX.
|
||||
setCategory(category)
|
||||
if (category === PluginCategory.Drone) {
|
||||
setPanelView(PluginPanelView.Listing)
|
||||
} else if (category === PluginCategory.Harness) {
|
||||
setPlugin({ uid: getString('run') })
|
||||
setPanelView(PluginPanelView.Configuration)
|
||||
}
|
||||
}}
|
||||
key={category}
|
||||
@ -187,58 +198,57 @@ export const PluginsPanel = ({ onPluginAddUpdate }: PluginsPanelInterface): JSX.
|
||||
}
|
||||
|
||||
const renderPluginConfigForm = useCallback((): JSX.Element => {
|
||||
const { uid, spec } = plugin || {}
|
||||
if (spec) {
|
||||
// let specAsObj = {}
|
||||
// try {
|
||||
// specAsObj = parse(spec)
|
||||
// } catch (e) {
|
||||
// // ignore error
|
||||
// }
|
||||
const inputs = get(pluginSpecMock, 'inputs', {})
|
||||
return (
|
||||
<Layout.Vertical
|
||||
spacing="medium"
|
||||
margin={{ left: 'xxlarge', top: 'large', right: 'xxlarge', bottom: 'xxlarge' }}
|
||||
height="95%">
|
||||
<Layout.Horizontal spacing="small" flex={{ justifyContent: 'flex-start' }}>
|
||||
<Icon
|
||||
name="arrow-left"
|
||||
size={18}
|
||||
onClick={() => {
|
||||
setPlugin(undefined)
|
||||
// TODO obtain plugin input spec by parsing YAML
|
||||
const inputs = get(category === PluginCategory.Drone ? dronePluginSpecMock : runStepSpec, 'inputs', {})
|
||||
return (
|
||||
<Layout.Vertical
|
||||
spacing="medium"
|
||||
margin={{ left: 'xxlarge', top: 'large', right: 'xxlarge', bottom: 'xxlarge' }}
|
||||
height="95%">
|
||||
<Layout.Horizontal spacing="small" flex={{ justifyContent: 'flex-start' }}>
|
||||
<Icon
|
||||
name="arrow-left"
|
||||
size={18}
|
||||
onClick={() => {
|
||||
setPlugin(undefined)
|
||||
if (category === PluginCategory.Drone) {
|
||||
setPanelView(PluginPanelView.Listing)
|
||||
}}
|
||||
className={css.arrow}
|
||||
/>
|
||||
} else if (category === PluginCategory.Harness) {
|
||||
setPanelView(PluginPanelView.Category)
|
||||
}
|
||||
}}
|
||||
className={css.arrow}
|
||||
/>
|
||||
{plugin?.uid ? (
|
||||
<Text font={{ variation: FontVariation.H5 }}>
|
||||
{getString('addLabel')} {uid}
|
||||
{getString('addLabel')} {plugin.uid} {getString('plugins.stepLabel')}
|
||||
</Text>
|
||||
</Layout.Horizontal>
|
||||
<Container className={css.form}>
|
||||
<Formik
|
||||
initialValues={{}}
|
||||
onSubmit={formData => {
|
||||
onPluginAddUpdate?.(false, formData)
|
||||
}}>
|
||||
<FormikForm>
|
||||
<Layout.Vertical flex={{ alignItems: 'flex-start' }} height="100%">
|
||||
<Layout.Vertical width="100%">
|
||||
{Object.keys(inputs).map((field: string) => {
|
||||
const fieldType = get(inputs, `${field}.type`, '') as 'string'
|
||||
return renderPluginFormField({ name: field, type: fieldType })
|
||||
})}
|
||||
</Layout.Vertical>
|
||||
<Button variation={ButtonVariation.PRIMARY} text={getString('addLabel')} type="submit" />
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</Layout.Horizontal>
|
||||
<Container className={css.form}>
|
||||
<Formik
|
||||
initialValues={{}}
|
||||
onSubmit={formData => {
|
||||
onPluginAddUpdate?.(false, formData)
|
||||
}}>
|
||||
<FormikForm>
|
||||
<Layout.Vertical flex={{ alignItems: 'flex-start' }} height="100%">
|
||||
<Layout.Vertical width="100%">
|
||||
{Object.keys(inputs).map((field: string) => {
|
||||
const fieldType = get(inputs, `${field}.type`, '') as 'string'
|
||||
return renderPluginFormField({ name: field, type: fieldType })
|
||||
})}
|
||||
</Layout.Vertical>
|
||||
</FormikForm>
|
||||
</Formik>
|
||||
</Container>
|
||||
</Layout.Vertical>
|
||||
)
|
||||
}
|
||||
return <></>
|
||||
}, [plugin])
|
||||
<Button variation={ButtonVariation.PRIMARY} text={getString('addLabel')} type="submit" />
|
||||
</Layout.Vertical>
|
||||
</FormikForm>
|
||||
</Formik>
|
||||
</Container>
|
||||
</Layout.Vertical>
|
||||
)
|
||||
}, [plugin, category])
|
||||
|
||||
const renderPluginsPanel = useCallback((): JSX.Element => {
|
||||
switch (panelView) {
|
||||
@ -251,7 +261,7 @@ export const PluginsPanel = ({ onPluginAddUpdate }: PluginsPanelInterface): JSX.
|
||||
default:
|
||||
return <></>
|
||||
}
|
||||
}, [loading, plugins, panelView])
|
||||
}, [loading, plugins, panelView, category])
|
||||
|
||||
return (
|
||||
<Container className={css.main}>
|
||||
|
103
web/src/components/RunPipelineModal/RunPipelineModal.tsx
Normal file
103
web/src/components/RunPipelineModal/RunPipelineModal.tsx
Normal file
@ -0,0 +1,103 @@
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import * as yup from 'yup'
|
||||
import { FontVariation } from '@harnessio/design-system'
|
||||
import {
|
||||
Button,
|
||||
ButtonVariation,
|
||||
Dialog,
|
||||
FormInput,
|
||||
Formik,
|
||||
FormikForm,
|
||||
Layout,
|
||||
Text,
|
||||
useToaster
|
||||
} from '@harnessio/uicore'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { useModalHook } from 'hooks/useModalHook'
|
||||
import type { OpenapiCreateExecutionRequest, TypesExecution, TypesRepository } from 'services/code'
|
||||
import { useMutate } from 'restful-react'
|
||||
import { getErrorMessage } from 'utils/Utils'
|
||||
import { useHistory } from 'react-router'
|
||||
import { useAppContext } from 'AppContext'
|
||||
|
||||
interface FormData {
|
||||
branch: string
|
||||
}
|
||||
|
||||
const useRunPipelineModal = () => {
|
||||
const { routes } = useAppContext()
|
||||
const { getString } = useStrings()
|
||||
const { showError } = useToaster()
|
||||
const history = useHistory()
|
||||
const [repo, setRepo] = useState<TypesRepository>()
|
||||
const [pipeline, setPipeline] = useState<string>('')
|
||||
const repoPath = useMemo(() => repo?.path || '', [repo])
|
||||
|
||||
const { mutate: startExecution } = useMutate<TypesExecution>({
|
||||
verb: 'POST',
|
||||
path: `/api/v1/repos/${repoPath}/+/pipelines/${pipeline}/executions`
|
||||
})
|
||||
|
||||
const runPipeline = (_formData: FormData): void => {
|
||||
try {
|
||||
const payload: OpenapiCreateExecutionRequest = {
|
||||
status: ''
|
||||
}
|
||||
startExecution(payload, { pathParams: { path: `/api/v1/repos/${repoPath}/+/pipelines/${pipeline}/executions` } })
|
||||
.then(() => {
|
||||
history.push(routes.toCODEExecutions({ repoPath, pipeline }))
|
||||
hideModal()
|
||||
})
|
||||
.catch(error => {
|
||||
showError(getErrorMessage(error), 0, 'pipelines.failedToRunPipeline')
|
||||
})
|
||||
} catch (exception) {
|
||||
showError(getErrorMessage(exception), 0, 'pipelines.failedToRunPipeline')
|
||||
}
|
||||
}
|
||||
|
||||
const [openModal, hideModal] = useModalHook(() => {
|
||||
const onClose = () => {
|
||||
hideModal()
|
||||
}
|
||||
return (
|
||||
<Dialog isOpen enforceFocus={false} onClose={onClose} title={getString('pipelines.run')}>
|
||||
<Formik
|
||||
formName="run-pipeline-form"
|
||||
initialValues={{ branch: repo?.default_branch || '' }}
|
||||
validationSchema={yup.object().shape({
|
||||
branch: yup
|
||||
.string()
|
||||
.trim()
|
||||
.required(`${getString('branch')} ${getString('isRequired')}`)
|
||||
})}
|
||||
onSubmit={runPipeline}
|
||||
enableReinitialize>
|
||||
<FormikForm>
|
||||
<Layout.Vertical spacing="medium">
|
||||
<FormInput.Text
|
||||
name="branch"
|
||||
label={<Text font={{ variation: FontVariation.FORM_LABEL }}>{getString('branch')}</Text>}
|
||||
/>
|
||||
<Layout.Horizontal spacing="medium">
|
||||
<Button variation={ButtonVariation.PRIMARY} type="submit" text={getString('pipelines.run')} />
|
||||
<Button variation={ButtonVariation.SECONDARY} text={getString('cancel')} onClick={onClose} />
|
||||
</Layout.Horizontal>
|
||||
</Layout.Vertical>
|
||||
</FormikForm>
|
||||
</Formik>
|
||||
</Dialog>
|
||||
)
|
||||
}, [repo?.default_branch, pipeline])
|
||||
|
||||
return {
|
||||
openModal: ({ repoMetadata, pipeline }: { repoMetadata: TypesRepository; pipeline: string }) => {
|
||||
setRepo(repoMetadata)
|
||||
setPipeline(pipeline)
|
||||
openModal()
|
||||
},
|
||||
hideModal
|
||||
}
|
||||
}
|
||||
|
||||
export default useRunPipelineModal
|
@ -323,6 +323,7 @@ export interface StringsMap {
|
||||
'pipelines.enterPipelineName': string
|
||||
'pipelines.enterYAMLPath': string
|
||||
'pipelines.failedToCreatePipeline': string
|
||||
'pipelines.failedToRunPipeline': string
|
||||
'pipelines.name': string
|
||||
'pipelines.newPipelineButton': string
|
||||
'pipelines.noData': string
|
||||
@ -330,6 +331,7 @@ export interface StringsMap {
|
||||
'pipelines.saveAndRun': string
|
||||
'pipelines.yamlPath': string
|
||||
'plugins.addAPlugin': string
|
||||
'plugins.stepLabel': string
|
||||
'plugins.title': string
|
||||
'pr.ableToMerge': string
|
||||
'pr.addDescription': string
|
||||
|
@ -636,6 +636,7 @@ pipelines:
|
||||
saveAndRun: Save and Run
|
||||
editPipeline: Edit pipeline {{pipeline}}
|
||||
run: Run pipeline
|
||||
failedToRunPipeline: Failed to run pipeline
|
||||
executions:
|
||||
noData: There are no executions :(
|
||||
newExecutionButton: Run Pipeline
|
||||
@ -657,3 +658,4 @@ run: Run
|
||||
plugins:
|
||||
title: Plugins
|
||||
addAPlugin: Add a {{category}} plugin
|
||||
stepLabel: step
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import { useMutate } from 'restful-react'
|
||||
import { Link, useParams } from 'react-router-dom'
|
||||
import { Drawer } from '@blueprintjs/core'
|
||||
import { Container, PageHeader, PageBody, Button, Layout, ButtonVariation, Text, useToaster } from '@harnessio/uicore'
|
||||
import { Icon } from '@harnessio/icons'
|
||||
import { Color } from '@harnessio/design-system'
|
||||
@ -10,6 +9,7 @@ import { useStrings } from 'framework/strings'
|
||||
import { useGetRepositoryMetadata } from 'hooks/useGetRepositoryMetadata'
|
||||
import MonacoSourceCodeEditor from 'components/SourceCodeEditor/MonacoSourceCodeEditor'
|
||||
import { PluginsPanel } from 'components/PluginsPanel/PluginsPanel'
|
||||
import useRunPipelineModal from 'components/RunPipelineModal/RunPipelineModal'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import type { CODEProps } from 'RouteDefinitions'
|
||||
import { getErrorMessage } from 'utils/Utils'
|
||||
@ -24,7 +24,7 @@ const NewPipeline = (): JSX.Element => {
|
||||
const { repoMetadata } = useGetRepositoryMetadata()
|
||||
const { showError } = useToaster()
|
||||
const [pipelineAsYAML, setPipelineAsYaml] = useState<string>('')
|
||||
const [showDrawer, setShowDrawer] = useState<boolean>(false)
|
||||
const { openModal: openRunPipelineModal } = useRunPipelineModal()
|
||||
const repoPath = useMemo(() => repoMetadata?.path || '', [repoMetadata])
|
||||
|
||||
const { mutate, loading } = useMutate<RepoCommitFilesResponse>({
|
||||
@ -36,14 +36,18 @@ const NewPipeline = (): JSX.Element => {
|
||||
try {
|
||||
const data: OpenapiCommitFilesRequest = {
|
||||
actions: [{ action: 'CREATE', path: `sample_${new Date().getTime()}.txt`, payload: pipelineAsYAML }],
|
||||
branch: 'main',
|
||||
branch: repoMetadata?.default_branch,
|
||||
new_branch: '',
|
||||
title: `Create pipeline ${pipeline}`,
|
||||
message: ''
|
||||
}
|
||||
|
||||
mutate(data)
|
||||
.then(() => setShowDrawer(true))
|
||||
.then(() => {
|
||||
if (repoMetadata && pipeline) {
|
||||
openRunPipelineModal({ repoMetadata, pipeline })
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showError(getErrorMessage(error), 0, 'pipelines.failedToSavePipeline')
|
||||
})
|
||||
@ -54,20 +58,6 @@ const NewPipeline = (): JSX.Element => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{showDrawer && (
|
||||
<Drawer isOpen={showDrawer} title={getString('pipelines.run')} onClose={() => setShowDrawer(false)}>
|
||||
<Layout.Vertical padding="xlarge" flex={{ justifyContent: 'flex-end' }} className={css.drawer}>
|
||||
<Layout.Horizontal spacing="medium" flex={{ justifyContent: 'flex-start' }} width="100%">
|
||||
<Button variation={ButtonVariation.PRIMARY} text={getString('run')} />
|
||||
<Button
|
||||
variation={ButtonVariation.SECONDARY}
|
||||
text={getString('cancel')}
|
||||
onClick={() => setShowDrawer(false)}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
</Layout.Vertical>
|
||||
</Drawer>
|
||||
)}
|
||||
<Container className={css.main}>
|
||||
<PageHeader
|
||||
title={getString('pipelines.editPipeline', { pipeline })}
|
||||
|
@ -8,6 +8,7 @@ import type { OpenapiCreatePipelineRequest, TypesPipeline, TypesRepository } fro
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import { getErrorMessage } from 'utils/Utils'
|
||||
|
||||
interface FormData {
|
||||
name: string
|
||||
branch: string
|
||||
|
Loading…
Reference in New Issue
Block a user