diff --git a/src/k8s/groups/Tekton/PipelineRun/utils/createCleanPipelineRunInstance/index.test.ts b/src/k8s/groups/Tekton/PipelineRun/utils/createCleanPipelineRunInstance/index.test.ts new file mode 100644 index 00000000..a11912e8 --- /dev/null +++ b/src/k8s/groups/Tekton/PipelineRun/utils/createCleanPipelineRunInstance/index.test.ts @@ -0,0 +1,119 @@ +import { createCleanPipelineRunInstance } from './index'; + +describe('testing createCleanPipelineRunInstance', () => { + it('should return valid kube object', () => { + const object = createCleanPipelineRunInstance({ + pipelineRunTemplate: { + apiVersion: 'tekton.dev/v1', + kind: 'PipelineRun', + // @ts-ignore + metadata: { + annotations: { + 'argocd.argoproj.io/compare-options': 'IgnoreExtraneous', + }, + generateName: 'clean-$(tt.params.CDPIPELINE)-$(tt.params.CDSTAGE)-', + labels: { + 'app.edp.epam.com/cdpipeline': '$(tt.params.CDPIPELINE)', + 'app.edp.epam.com/cdstage': '$(tt.params.CDPIPELINE)-$(tt.params.CDSTAGE)', + 'app.edp.epam.com/pipelinetype': 'clean', + }, + }, + spec: { + params: [ + { + name: 'CDSTAGE', + value: '$(tt.params.CDSTAGE)', + }, + { + name: 'CDPIPELINE', + value: '$(tt.params.CDPIPELINE)', + }, + ], + pipelineRef: { + name: 'clean', + }, + taskRunTemplate: { + serviceAccountName: 'tekton', + }, + timeouts: { + pipeline: '1h00m0s', + }, + }, + }, + CDPipeline: { + apiVersion: 'v2.edp.epam.com/v1', + kind: 'CDPipeline', + // @ts-ignore + metadata: { + name: 'test-pipe', + namespace: 'test-namespace', + }, + spec: { + applications: ['test-app-1', 'test-app-2'], + applicationsToPromote: ['test-app-1', 'test-app-2'], + deploymentType: 'container', + inputDockerStreams: ['test-app-1-main', 'test-app-2-main'], + name: 'test-pipe', + }, + }, + stage: { + apiVersion: 'v2.edp.epam.com/v1', + kind: 'Stage', + // @ts-ignore + metadata: { + name: 'test-pipe-sit', + namespace: 'test-namespace', + }, + spec: { + cdPipeline: 'test-pipe', + cleanTemplate: 'clean', + clusterName: 'in-cluster', + description: 'sit', + name: 'sit', + namespace: 'test-namespace-test-pipe-sit', + order: 0, + qualityGates: [ + { + autotestName: null, + branchName: null, + qualityGateType: 'manual', + stepName: 'sit', + }, + ], + source: { + // @ts-ignore + library: { + name: 'default', + }, + type: 'default', + }, + triggerTemplate: 'deploy', + triggerType: 'Manual', + }, + }, + }); + + expect(object).toEqual({ + apiVersion: 'tekton.dev/v1', + kind: 'PipelineRun', + metadata: { + annotations: { 'argocd.argoproj.io/compare-options': 'IgnoreExtraneous' }, + generateName: 'clean-test-pipe-sit-', + labels: { + 'app.edp.epam.com/cdpipeline': 'test-pipe', + 'app.edp.epam.com/cdstage': 'test-pipe-sit', + 'app.edp.epam.com/pipelinetype': 'clean', + }, + }, + spec: { + params: [ + { name: 'CDSTAGE', value: 'sit' }, + { name: 'CDPIPELINE', value: 'test-pipe' }, + ], + pipelineRef: { name: 'clean' }, + taskRunTemplate: { serviceAccountName: 'tekton' }, + timeouts: { pipeline: '1h00m0s' }, + }, + }); + }); +}); diff --git a/src/k8s/groups/Tekton/PipelineRun/utils/createCleanPipelineRunInstance/index.ts b/src/k8s/groups/Tekton/PipelineRun/utils/createCleanPipelineRunInstance/index.ts new file mode 100644 index 00000000..609c17f6 --- /dev/null +++ b/src/k8s/groups/Tekton/PipelineRun/utils/createCleanPipelineRunInstance/index.ts @@ -0,0 +1,45 @@ +import { PIPELINE_TYPES } from '../../../../../../constants/pipelineTypes'; +import { CDPipelineKubeObjectInterface } from '../../../../EDP/CDPipeline/types'; +import { StageKubeObjectInterface } from '../../../../EDP/Stage/types'; +import { + PIPELINE_RUN_LABEL_SELECTOR_CDPIPELINE, + PIPELINE_RUN_LABEL_SELECTOR_CDSTAGE, + PIPELINE_RUN_LABEL_SELECTOR_PIPELINE_TYPE, +} from '../../labels'; +import { PipelineRunKubeObjectInterface } from '../../types'; + +export const createCleanPipelineRunInstance = ({ + CDPipeline, + stage, + pipelineRunTemplate, +}: { + CDPipeline: CDPipelineKubeObjectInterface; + stage: StageKubeObjectInterface; + pipelineRunTemplate: PipelineRunKubeObjectInterface; +}): PipelineRunKubeObjectInterface => { + const base = { ...pipelineRunTemplate }; + + base.metadata.generateName = `clean-${CDPipeline.metadata.name}-${stage.spec.name}-`; + + base.metadata.labels[PIPELINE_RUN_LABEL_SELECTOR_CDPIPELINE] = CDPipeline.metadata.name; + base.metadata.labels[PIPELINE_RUN_LABEL_SELECTOR_CDSTAGE] = stage.metadata.name; + base.metadata.labels[PIPELINE_RUN_LABEL_SELECTOR_PIPELINE_TYPE] = PIPELINE_TYPES.CLEAN; + + for (const param of base.spec.params) { + switch (param.name) { + case 'CDSTAGE': + param.value = stage.spec.name; + break; + case 'CDPIPELINE': + param.value = CDPipeline.metadata.name; + break; + case 'KUBECONFIG_SECRET_NAME': + param.value = stage.spec.clusterName; + break; + default: + break; + } + } + + return base; +}; diff --git a/src/k8s/groups/Tekton/PipelineRun/utils/createDeployPipelineRunInstance/index.test.ts b/src/k8s/groups/Tekton/PipelineRun/utils/createDeployPipelineRunInstance/index.test.ts new file mode 100644 index 00000000..2aa6bb04 --- /dev/null +++ b/src/k8s/groups/Tekton/PipelineRun/utils/createDeployPipelineRunInstance/index.test.ts @@ -0,0 +1,143 @@ +import { createDeployPipelineRunInstance } from './index'; + +describe('testing createDeployPipelineRunInstance', () => { + it('should return valid kube object', () => { + const object = createDeployPipelineRunInstance({ + pipelineRunTemplate: { + apiVersion: 'tekton.dev/v1', + kind: 'PipelineRun', + // @ts-ignore + metadata: { + annotations: { + 'argocd.argoproj.io/compare-options': 'IgnoreExtraneous', + }, + generateName: 'deploy-$(tt.params.CDPIPELINE)-$(tt.params.CDSTAGE)-', + labels: { + 'app.edp.epam.com/cdpipeline': '$(tt.params.CDPIPELINE)', + 'app.edp.epam.com/cdstage': '$(tt.params.CDPIPELINE)-$(tt.params.CDSTAGE)', + 'app.edp.epam.com/pipelinetype': 'deploy', + }, + }, + spec: { + params: [ + { + name: 'APPLICATIONS_PAYLOAD', + value: '$(tt.params.APPLICATIONS_PAYLOAD)', + }, + { + name: 'CDSTAGE', + value: '$(tt.params.CDSTAGE)', + }, + { + name: 'CDPIPELINE', + value: '$(tt.params.CDPIPELINE)', + }, + { + name: 'KUBECONFIG_SECRET_NAME', + value: '$(tt.params.KUBECONFIG_SECRET_NAME)', + }, + ], + pipelineRef: { + name: 'deploy', + }, + taskRunTemplate: { + serviceAccountName: 'tekton', + }, + timeouts: { + pipeline: '1h00m0s', + }, + }, + }, + CDPipeline: { + apiVersion: 'v2.edp.epam.com/v1', + kind: 'CDPipeline', + // @ts-ignore + metadata: { + name: 'test-pipe', + namespace: 'test-namespace', + }, + spec: { + applications: ['test-app-1', 'test-app-2'], + applicationsToPromote: ['test-app-1', 'test-app-2'], + deploymentType: 'container', + inputDockerStreams: ['test-app-1-main', 'test-app-2-main'], + name: 'test-pipe', + }, + }, + stage: { + apiVersion: 'v2.edp.epam.com/v1', + kind: 'Stage', + // @ts-ignore + metadata: { + name: 'test-pipe-sit', + namespace: 'test-namespace', + }, + spec: { + cdPipeline: 'test-pipe', + cleanTemplate: 'clean', + clusterName: 'in-cluster', + description: 'sit', + name: 'sit', + namespace: 'test-namespace-test-pipe-sit', + order: 0, + qualityGates: [ + { + autotestName: null, + branchName: null, + qualityGateType: 'manual', + stepName: 'sit', + }, + ], + source: { + // @ts-ignore + library: { + name: 'default', + }, + type: 'default', + }, + triggerTemplate: 'deploy', + triggerType: 'Manual', + }, + }, + appPayload: { + 'test-app-1': { + customValues: false, + imageTag: '0.1.0-SNAPSHOT', + }, + 'test-app-2': { + customValues: false, + imageTag: '0.1.0-SNAPSHOT', + }, + }, + }); + + expect(object).toEqual({ + apiVersion: 'tekton.dev/v1', + kind: 'PipelineRun', + metadata: { + annotations: { 'argocd.argoproj.io/compare-options': 'IgnoreExtraneous' }, + generateName: 'deploy-test-pipe-sit', + labels: { + 'app.edp.epam.com/cdpipeline': 'test-pipe', + 'app.edp.epam.com/cdstage': 'test-pipe-sit', + 'app.edp.epam.com/pipelinetype': 'deploy', + }, + }, + spec: { + params: [ + { + name: 'APPLICATIONS_PAYLOAD', + value: + '{"test-app-1":{"customValues":false,"imageTag":"0.1.0-SNAPSHOT"},"test-app-2":{"customValues":false,"imageTag":"0.1.0-SNAPSHOT"}}', + }, + { name: 'CDSTAGE', value: 'sit' }, + { name: 'CDPIPELINE', value: 'test-pipe' }, + { name: 'KUBECONFIG_SECRET_NAME', value: 'in-cluster' }, + ], + pipelineRef: { name: 'deploy' }, + taskRunTemplate: { serviceAccountName: 'tekton' }, + timeouts: { pipeline: '1h00m0s' }, + }, + }); + }); +}); diff --git a/src/k8s/groups/Tekton/PipelineRun/utils/createDeployPipelineRunInstance/index.ts b/src/k8s/groups/Tekton/PipelineRun/utils/createDeployPipelineRunInstance/index.ts new file mode 100644 index 00000000..6807b46d --- /dev/null +++ b/src/k8s/groups/Tekton/PipelineRun/utils/createDeployPipelineRunInstance/index.ts @@ -0,0 +1,56 @@ +import { PIPELINE_TYPES } from '../../../../../../constants/pipelineTypes'; +import { CDPipelineKubeObjectInterface } from '../../../../EDP/CDPipeline/types'; +import { StageKubeObjectInterface } from '../../../../EDP/Stage/types'; +import { + PIPELINE_RUN_LABEL_SELECTOR_CDPIPELINE, + PIPELINE_RUN_LABEL_SELECTOR_CDSTAGE, + PIPELINE_RUN_LABEL_SELECTOR_PIPELINE_TYPE, +} from '../../labels'; +import { PipelineRunKubeObjectInterface } from '../../types'; + +export const createDeployPipelineRunInstance = ({ + CDPipeline, + stage, + pipelineRunTemplate, + appPayload, +}: { + CDPipeline: CDPipelineKubeObjectInterface; + stage: StageKubeObjectInterface; + pipelineRunTemplate: PipelineRunKubeObjectInterface; + appPayload: Record< + string, + { + imageTag: string; + customValues: boolean; + } + >; +}): PipelineRunKubeObjectInterface => { + const base = { ...pipelineRunTemplate }; + + base.metadata.generateName = `deploy-${CDPipeline.metadata.name}-${stage.spec.name}`; + + base.metadata.labels[PIPELINE_RUN_LABEL_SELECTOR_CDPIPELINE] = CDPipeline.metadata.name; + base.metadata.labels[PIPELINE_RUN_LABEL_SELECTOR_CDSTAGE] = stage.metadata.name; + base.metadata.labels[PIPELINE_RUN_LABEL_SELECTOR_PIPELINE_TYPE] = PIPELINE_TYPES.DEPLOY; + + for (const param of base.spec.params) { + switch (param.name) { + case 'CDSTAGE': + param.value = stage.spec.name; + break; + case 'CDPIPELINE': + param.value = CDPipeline.metadata.name; + break; + case 'APPLICATIONS_PAYLOAD': + param.value = JSON.stringify(appPayload); + break; + case 'KUBECONFIG_SECRET_NAME': + param.value = stage.spec.clusterName; + break; + default: + break; + } + } + + return base; +}; diff --git a/src/pages/stage-details/components/Applications/hooks/useConfigurationHandlers.ts b/src/pages/stage-details/components/Applications/hooks/useConfigurationHandlers.ts index 1d338691..297401c4 100644 --- a/src/pages/stage-details/components/Applications/hooks/useConfigurationHandlers.ts +++ b/src/pages/stage-details/components/Applications/hooks/useConfigurationHandlers.ts @@ -2,14 +2,10 @@ import React from 'react'; import { FieldValues, useFormContext } from 'react-hook-form'; import { CRUD_TYPES } from '../../../../../constants/crudTypes'; import { useRequestStatusMessages } from '../../../../../hooks/useResourceRequestStatusMessages'; -import { editResource } from '../../../../../k8s/common/editResource'; import { useCreateCleanPipelineRun } from '../../../../../k8s/groups/Tekton/PipelineRun/hooks/useCreateCleanPipelineRun'; import { useCreateDeployPipelineRun } from '../../../../../k8s/groups/Tekton/PipelineRun/hooks/useCreateDeployPipelineRun'; -import { - PIPELINE_RUN_LABEL_SELECTOR_CDPIPELINE, - PIPELINE_RUN_LABEL_SELECTOR_CDSTAGE, - PIPELINE_RUN_LABEL_SELECTOR_PIPELINE_TYPE, -} from '../../../../../k8s/groups/Tekton/PipelineRun/labels'; +import { createCleanPipelineRunInstance } from '../../../../../k8s/groups/Tekton/PipelineRun/utils/createCleanPipelineRunInstance'; +import { createDeployPipelineRunInstance } from '../../../../../k8s/groups/Tekton/PipelineRun/utils/createDeployPipelineRunInstance'; import { useDialogContext } from '../../../../../providers/Dialog/hooks'; import { ConfirmDialog } from '../../../../../widgets/dialogs/Confirm'; import { IMAGE_TAG_POSTFIX, VALUES_OVERRIDE_POSTFIX } from '../../../constants'; @@ -31,68 +27,6 @@ const createApplicationPayload = (imageTag: string, customValues: boolean) => ({ customValues, }); -const newDeployPipelineRunNames = { - generateName: { - name: 'generateName', - path: ['metadata', 'generateName'], - }, - CDPipelineLabel: { - name: 'CDPipelineLabel', - path: ['metadata', 'labels', PIPELINE_RUN_LABEL_SELECTOR_CDPIPELINE], - }, - stageLabel: { - name: 'stageLabel', - path: ['metadata', 'labels', PIPELINE_RUN_LABEL_SELECTOR_CDSTAGE], - }, - pipelineTypeLabel: { - name: 'pipelineTypeLabel', - path: ['metadata', 'labels', PIPELINE_RUN_LABEL_SELECTOR_PIPELINE_TYPE], - }, - applicationsPayloadParam: { - name: 'applicationsPayloadParam', - path: ['spec', 'params', '0'], - }, - stageParam: { - name: 'stageParam', - path: ['spec', 'params', '1'], - }, - CDPipelineParam: { - name: 'CDPipelineParam', - path: ['spec', 'params', '2'], - }, - kubeConfigSecretParam: { - name: 'kubeConfigSecretParam', - path: ['spec', 'params', '3'], - }, -}; - -const newCleanPipelineRunNames = { - generateName: { - name: 'generateName', - path: ['metadata', 'generateName'], - }, - CDPipelineLabel: { - name: 'CDPipelineLabel', - path: ['metadata', 'labels', PIPELINE_RUN_LABEL_SELECTOR_CDPIPELINE], - }, - stageLabel: { - name: 'stageLabel', - path: ['metadata', 'labels', PIPELINE_RUN_LABEL_SELECTOR_CDSTAGE], - }, - pipelineTypeLabel: { - name: 'pipelineTypeLabel', - path: ['metadata', 'labels', PIPELINE_RUN_LABEL_SELECTOR_PIPELINE_TYPE], - }, - stageParam: { - name: 'stageParam', - path: ['spec', 'params', '0'], - }, - CDPipelineParam: { - name: 'CDPipelineParam', - path: ['spec', 'params', '1'], - }, -}; - export const useConfigurationHandlers = ({ values, selected, @@ -259,10 +193,18 @@ export const useConfigurationHandlers = ({ return; } - const appPayload = enrichedApplicationsWithArgoApplications.reduce((acc, cur) => { + const appPayload = enrichedApplicationsWithArgoApplications.reduce< + Record< + string, + { + imageTag: string; + customValues: boolean; + } + > + >((acc, cur) => { const appName = cur.application.metadata.name; - const imageTagFieldValue = values[`${appName}${IMAGE_TAG_POSTFIX}`]; - const valuesOverrideFieldValue = values[`${appName}${VALUES_OVERRIDE_POSTFIX}`]; + const imageTagFieldValue = values[`${appName}${IMAGE_TAG_POSTFIX}`] as string; + const valuesOverrideFieldValue = values[`${appName}${VALUES_OVERRIDE_POSTFIX}`] as boolean; const { value: tagValue } = parseTagLabelValue(imageTagFieldValue); @@ -270,32 +212,12 @@ export const useConfigurationHandlers = ({ return acc; }, {}); - // todo: refactor this hardcode - const newDeployPipelineRun = editResource( - newDeployPipelineRunNames, - deployPipelineRunTemplate, - { - generateName: `deploy-${CDPipeline.data.metadata.name}-${stage.spec.name}`, - CDPipelineLabel: CDPipeline.data.metadata.name, - stageLabel: stage.metadata.name, - applicationsPayloadParam: { - name: 'APPLICATIONS_PAYLOAD', - value: JSON.stringify(appPayload), - }, - stageParam: { - name: 'CDSTAGE', - value: stage.spec.name, - }, - CDPipelineParam: { - name: 'CDPIPELINE', - value: CDPipeline.data.metadata.name, - }, - kubeConfigSecretParam: { - name: 'KUBECONFIG_SECRET_NAME', - value: stage.spec.clusterName, - }, - } - ); + const newDeployPipelineRun = createDeployPipelineRunInstance({ + CDPipeline: CDPipeline.data, + stage, + pipelineRunTemplate: deployPipelineRunTemplate, + appPayload, + }); await createDeployPipelineRun({ deployPipelineRun: newDeployPipelineRun }); }, [ @@ -303,9 +225,7 @@ export const useConfigurationHandlers = ({ createDeployPipelineRun, deployPipelineRunTemplate, enrichedApplicationsWithArgoApplications, - stage.metadata.name, - stage.spec.clusterName, - stage.spec.name, + stage, trigger, values, ]); @@ -320,29 +240,19 @@ export const useConfigurationHandlers = ({ return; } - const newCleanPipelineRun = editResource(newCleanPipelineRunNames, cleanPipelineRunTemplate, { - generateName: `clean-${CDPipeline.data.metadata.name}-${stage.spec.name}-`, - CDPipelineLabel: CDPipeline.data.metadata.name, - stageLabel: stage.metadata.name, - pipelineTypeLabel: 'clean', - stageParam: { - name: 'CDSTAGE', - value: stage.spec.name, - }, - CDPipelineParam: { - name: 'CDPIPELINE', - value: CDPipeline.data.metadata.name, - }, + const newCleanPipelineRun = createCleanPipelineRunInstance({ + CDPipeline: CDPipeline.data, + stage, + pipelineRunTemplate: cleanPipelineRunTemplate, }); await createCleanPipelineRun({ cleanPipelineRun: newCleanPipelineRun }); }, [ - CDPipeline.data.metadata.name, + CDPipeline.data, cleanPipelineRunTemplate, createCleanPipelineRun, showRequestErrorMessage, - stage.metadata.name, - stage.spec.name, + stage, ]); const handleClickClean = React.useCallback(async () => {