diff --git a/web/src/components/PluginsPanel/PluginsPanel.tsx b/web/src/components/PluginsPanel/PluginsPanel.tsx index 82002b53a..2dd15dfc7 100644 --- a/web/src/components/PluginsPanel/PluginsPanel.tsx +++ b/web/src/components/PluginsPanel/PluginsPanel.tsx @@ -207,7 +207,7 @@ export const PluginsPanel = ({ version = YamlVersion.V0, onPluginAddUpdate }: Pl case PluginCategory.Harness: constructedPayload = version === YamlVersion.V1 - ? { type: 'script', spec: constructedPayload } + ? { type: 'script', spec: { run: get(constructedPayload, 'script', '') } } : { name: 'run step', commands: [get(constructedPayload, 'script', '')] } } onPluginAddUpdate?.(isUpdate, constructedPayload) diff --git a/web/src/pages/AddUpdatePipeline/AddUpdatePipeline.tsx b/web/src/pages/AddUpdatePipeline/AddUpdatePipeline.tsx index 149d15418..0178947ca 100644 --- a/web/src/pages/AddUpdatePipeline/AddUpdatePipeline.tsx +++ b/web/src/pages/AddUpdatePipeline/AddUpdatePipeline.tsx @@ -31,27 +31,33 @@ import { getErrorMessage } from 'utils/Utils' import { decodeGitContent } from 'utils/GitUtils' import pipelineSchemaV1 from './schema/pipeline-schema-v1.json' import pipelineSchemaV0 from './schema/pipeline-schema-v0.json' -import { YamlVersion } from './Constants' +import { DRONE_CONFIG_YAML_FILE_SUFFIXES, YamlVersion } from './Constants' import css from './AddUpdatePipeline.module.scss' const StarterPipelineV1: Record = { version: 1, - stages: [ - { - type: 'ci', - spec: { - steps: [ - { - type: 'script', - spec: { - run: 'echo hello world' + kind: 'pipeline', + spec: { + stages: [ + { + name: 'build', + type: 'ci', + spec: { + steps: [ + { + name: 'build', + type: 'script', + spec: { + image: 'golang', + run: 'echo "hello world"' + } } - } - ] + ] + } } - } - ] + ] + } } const StarterPipelineV0: Record = { @@ -79,15 +85,13 @@ interface PipelineSaveAndRunOption { } const AddUpdatePipeline = (): JSX.Element => { - const version = YamlVersion.V0 const { routes } = useAppContext() const { getString } = useStrings() const { pipeline } = useParams() const { repoMetadata } = useGetRepositoryMetadata() const { showError, showSuccess, clear: clearToaster } = useToaster() - const [pipelineAsObj, setPipelineAsObj] = useState>( - version === YamlVersion.V0 ? StarterPipelineV0 : StarterPipelineV1 - ) + const [yamlVersion, setYAMLVersion] = useState() + const [pipelineAsObj, setPipelineAsObj] = useState>({}) const [pipelineAsYAML, setPipelineAsYaml] = useState('') const { openModal: openRunPipelineModal } = useRunPipelineModal() const repoPath = useMemo(() => repoMetadata?.path || '', [repoMetadata]) @@ -139,6 +143,15 @@ const AddUpdatePipeline = (): JSX.Element => { [pipelineYAMLFileContent?.content] ) + // set YAML version for Pipeline setup + useEffect(() => { + setYAMLVersion( + DRONE_CONFIG_YAML_FILE_SUFFIXES.map((suffix: string) => pipelineData?.config_path?.endsWith(suffix)) + ? YamlVersion.V0 + : YamlVersion.V1 + ) + }, [pipelineData]) + // check if file already exists and has some content useEffect(() => { setIsExistingPipeline(!isEmpty(originalPipelineYAMLFileContent) && !isUndefined(originalPipelineYAMLFileContent)) @@ -151,12 +164,12 @@ const AddUpdatePipeline = (): JSX.Element => { } else { // load with starter pipeline try { - setPipelineAsYaml(stringify(pipelineAsObj)) + setPipelineAsYaml(stringify(yamlVersion === YamlVersion.V1 ? StarterPipelineV1 : StarterPipelineV0)) } catch (ex) { // ignore exception } } - }, [isExistingPipeline, originalPipelineYAMLFileContent, pipelineAsObj]) + }, [yamlVersion, isExistingPipeline, originalPipelineYAMLFileContent, pipelineAsObj]) // find if editor content was modified useEffect(() => { @@ -206,7 +219,7 @@ const AddUpdatePipeline = (): JSX.Element => { const updatePipeline = (payload: Record): Record => { const pipelineAsObjClone = { ...pipelineAsObj } - const stepInsertPath = version === YamlVersion.V0 ? 'steps' : 'stages.0.spec.steps' + const stepInsertPath = yamlVersion === YamlVersion.V1 ? 'spec.stages.0.spec.steps' : 'steps' let existingSteps: [unknown] = get(pipelineAsObjClone, stepInsertPath, []) if (existingSteps.length > 0) { existingSteps.push(payload) @@ -309,13 +322,13 @@ const AddUpdatePipeline = (): JSX.Element => { setPipelineAsYaml(value)} /> - + diff --git a/web/src/pages/AddUpdatePipeline/Constants.ts b/web/src/pages/AddUpdatePipeline/Constants.ts index 818dba710..ed17db88d 100644 --- a/web/src/pages/AddUpdatePipeline/Constants.ts +++ b/web/src/pages/AddUpdatePipeline/Constants.ts @@ -5,3 +5,5 @@ export enum YamlVersion { export const DEFAULT_YAML_PATH_PREFIX = '.harness/' export const DEFAULT_YAML_PATH_SUFFIX = '.yaml' + +export const DRONE_CONFIG_YAML_FILE_SUFFIXES = ['.drone.yml', '.drone.yaml'] diff --git a/web/src/pages/AddUpdatePipeline/schema/pipeline-schema-v1.json b/web/src/pages/AddUpdatePipeline/schema/pipeline-schema-v1.json index 5a94510c4..381bd8121 100644 --- a/web/src/pages/AddUpdatePipeline/schema/pipeline-schema-v1.json +++ b/web/src/pages/AddUpdatePipeline/schema/pipeline-schema-v1.json @@ -1,18 +1,142 @@ { "definitions": { - "Pipeline": { - "title": "Pipeline", - "description": "Pipeline defines the pipeline execution.", + "Config": { + "title": "Config", + "description": "Config defines the a resource configuration.", "type": "object", "properties": { "version": { "description": "Version defines the schema version.", "type": ["string", "number"] }, - "name": { - "description": "Pipeline provides the pipeline name.", - "type": "string" + "kind": { + "type": "string", + "description": "Type defines the schema type.", + "enum": ["pipeline", "plugin", "template"] }, + "type": { + "type": "string", + "description": "Type defines the schema type.", + "enum": ["pipeline", "stage", "step"] + }, + "name": { + "type": "string", + "description": "Name defines an optional resource name." + } + }, + "required": ["kind"], + "oneOf": [ + { + "allOf": [ + { + "properties": { + "kind": { + "const": "pipeline" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/Pipeline" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "kind": { + "const": "template" + }, + "type": { + "const": "stage" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/TemplateStage" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "kind": { + "const": "template" + }, + "type": { + "const": "step" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/TemplateStep" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "kind": { + "const": "plugin" + }, + "type": { + "const": "step" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/PluginStep" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "kind": { + "const": "plugin" + }, + "type": { + "const": "stage" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/PluginStage" + } + } + } + ] + } + ], + "x-go-skip": true, + "x-file": "config.yaml" + }, + "Pipeline": { + "title": "Pipeline", + "description": "Pipeline defines the pipeline execution.", + "type": "object", + "properties": { "stages": { "type": "array", "description": "Stages defines a list of pipeline stages.", @@ -32,7 +156,7 @@ "description": "Options defines global configuration options." } }, - "required": ["version", "stages"], + "required": ["stages"], "examples": [ { "version": 1, @@ -105,8 +229,8 @@ "description": "The stage conditional logic.", "$ref": "#/definitions/When" }, - "on": { - "$ref": "#/definitions/On" + "failure": { + "$ref": "#/definitions/FailureList" } }, "oneOf": [ @@ -435,47 +559,26 @@ "x-go-skip": true, "x-file": "when_expr.yaml" }, - "On": { - "title": "On", - "type": "object", - "properties": { - "failure": { - "oneOf": [ - { - "$ref": "#/definitions/Failure" - }, - { - "type": "array", - "items": { - "$ref": "#/definitions/Failure" - } - } - ] + "FailureList": { + "title": "FailureList", + "oneOf": [ + { + "$ref": "#/definitions/Failure" + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/Failure" + } } - }, + ], "x-go-skip": true, - "x-file": "on.yaml" + "x-file": "failure_list.yaml" }, "Failure": { "title": "Failure", "type": "object", - "description": "Failure defines a failure strategy.", "properties": { - "type": { - "description": "Type defines the failure strategy type.", - "type": "string", - "enum": [ - "abort", - "ignore", - "manual-intervention", - "retry", - "success", - "stage-rollback", - "pipeline-rollback", - "retry-step-group", - "fail" - ] - }, "errors": { "description": "Errors specifies the types of errors.", "type": "array", @@ -497,9 +600,125 @@ "user-mark-fail" ] } + }, + "action": { + "$ref": "#/definitions/FailureAction" + } + }, + "x-file": "failure.yaml" + }, + "FailureAction": { + "title": "FailureAction", + "type": "object", + "description": "Failure defines a failure strategy.", + "properties": { + "type": { + "description": "Type defines the failure strategy type.", + "type": "string", + "enum": [ + "abort", + "fail", + "ignore", + "manual-intervention", + "pipeline-rollback", + "retry", + "retry-step-group", + "stage-rollback", + "success" + ] } }, "oneOf": [ + { + "allOf": [ + { + "properties": { + "type": { + "const": "success" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/EmptySpec" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "type": { + "const": "fail" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/EmptySpec" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "type": { + "const": "retry-step-group" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/EmptySpec" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "type": { + "const": "stage-rollback" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/EmptySpec" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "type": { + "const": "pipeline-rollback" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/EmptySpec" + } + } + } + ] + }, { "allOf": [ { @@ -573,7 +792,13 @@ ] } ], - "x-file": "failure.yaml" + "x-file": "failure_action.yaml" + }, + "EmptySpec": { + "title": "EmptySpec", + "type": "object", + "properties": {}, + "x-file": "empty_spec.yaml" }, "Abort": { "title": "Abort", @@ -611,18 +836,169 @@ } ] }, - "on": { - "$ref": "#/definitions/On" + "failure": { + "$ref": "#/definitions/RetryFailure" } }, "type": "object", "x-file": "failure_retry.yaml" }, + "RetryFailure": { + "title": "RetryFailure", + "type": "object", + "properties": { + "action": { + "$ref": "#/definitions/RetryFailureAction" + } + }, + "x-file": "retry_failure.yaml" + }, + "RetryFailureAction": { + "title": "RetryFailureAction", + "type": "object", + "description": "Failure action on failure for all retries", + "properties": { + "type": { + "description": "Type defines the failure strategy type.", + "type": "string", + "enum": ["abort", "fail", "ignore", "manual-intervention", "pipeline-rollback", "stage-rollback", "success"] + } + }, + "oneOf": [ + { + "allOf": [ + { + "properties": { + "type": { + "const": "success" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/EmptySpec" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "type": { + "const": "fail" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/EmptySpec" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "type": { + "const": "stage-rollback" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/EmptySpec" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "type": { + "const": "pipeline-rollback" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/EmptySpec" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "type": { + "const": "abort" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/Abort" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "type": { + "const": "ignore" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/Ignore" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "type": { + "const": "manual-intervention" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/ManualIntervention" + } + } + } + ] + } + ], + "x-file": "retry_failure_action.yaml" + }, "ManualIntervention": { "title": "ManualIntervention", "properties": { - "on": { - "$ref": "#/definitions/On" + "timeout_action": { + "$ref": "#/definitions/TimeoutAction" }, "timeout": { "format": "duration", @@ -633,6 +1009,129 @@ "type": "object", "x-file": "failure_manual.yaml" }, + "TimeoutAction": { + "title": "TimeoutAction", + "type": "object", + "description": "Manual intervention for timeout failure action", + "properties": { + "type": { + "description": "Type defines the failure strategy type.", + "type": "string", + "enum": ["abort", "ignore", "success", "stage-rollback", "pipeline-rollback", "fail"] + } + }, + "oneOf": [ + { + "allOf": [ + { + "properties": { + "type": { + "const": "success" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/EmptySpec" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "type": { + "const": "fail" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/EmptySpec" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "type": { + "const": "stage-rollback" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/EmptySpec" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "type": { + "const": "pipeline-rollback" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/EmptySpec" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "type": { + "const": "abort" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/Abort" + } + } + } + ] + }, + { + "allOf": [ + { + "properties": { + "type": { + "const": "ignore" + } + } + }, + { + "properties": { + "spec": { + "$ref": "#/definitions/Ignore" + } + } + } + ] + } + ], + "x-file": "timeout_action.yaml" + }, "StageCI": { "properties": { "cache": { @@ -1080,8 +1579,8 @@ "description": "The stage conditional logic.", "$ref": "#/definitions/When" }, - "on": { - "$ref": "#/definitions/On" + "failure": { + "$ref": "#/definitions/FailureList" } }, "oneOf": [ @@ -2138,6 +2637,10 @@ }, "description": "Enum defines a list of accepted input values.", "x-go-type": "[]string" + }, + "mask": { + "type": "boolean", + "description": "Mask indicates the input should be masked." } }, "x-file": "input.yaml" @@ -2362,11 +2865,115 @@ } }, "x-file": "status.yaml" + }, + "TemplateStage": { + "title": "TemplateStage", + "description": "TemplateStage defines a stage-level template", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The template name." + }, + "description": { + "type": "string", + "description": "The template description." + }, + "stage": { + "$ref": "#/definitions/Stage" + }, + "inputs": { + "type": "object", + "description": "Inputs defines the template input parameters.", + "additionalProperties": { + "$ref": "#/definitions/Input" + } + } + }, + "x-file": "template_stage.yaml" + }, + "TemplateStep": { + "title": "TemplateStep", + "description": "TemplateStep defines a step-level template", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The template name." + }, + "description": { + "type": "string", + "description": "The template description." + }, + "step": { + "$ref": "#/definitions/Step" + }, + "inputs": { + "type": "object", + "description": "Inputs defines the template input parameters.", + "additionalProperties": { + "$ref": "#/definitions/Input" + } + } + }, + "x-file": "template_step.yaml" + }, + "PluginStep": { + "title": "PluginStep", + "description": "PluginStep defines a step-level plugin", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The plugin name." + }, + "description": { + "type": "string", + "description": "The plugin description." + }, + "step": { + "$ref": "#/definitions/Step" + }, + "inputs": { + "type": "object", + "description": "Inputs defines the plugin input parameters.", + "additionalProperties": { + "$ref": "#/definitions/Input" + } + } + }, + "x-file": "plugin_step.yaml" + }, + "PluginStage": { + "title": "PluginStage", + "description": "PluginStage defines a stage-level plugin", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The plugin name." + }, + "description": { + "type": "string", + "description": "The plugin description." + }, + "stage": { + "$ref": "#/definitions/Stage" + }, + "inputs": { + "type": "object", + "description": "Inputs defines the plugin input parameters.", + "additionalProperties": { + "$ref": "#/definitions/Input" + } + } + }, + "x-file": "plugin_stage.yaml" } }, "oneOf": [ { - "$ref": "#/definitions/Pipeline" + "$ref": "#/definitions/Config" } ] }