Skip to content

Commit

Permalink
Merge pull request #39 from devtron-labs/chore/generic-cd-service
Browse files Browse the repository at this point in the history
chore: generic cd service
  • Loading branch information
AbhishekA1509 authored Nov 15, 2023
2 parents b01e19d + a597716 commit b07c1b1
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 81 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@devtron-labs/devtron-fe-common-lib",
"version": "0.0.39",
"version": "0.0.40",
"description": "Supporting common component library",
"main": "dist/index.js",
"scripts": {
Expand Down
299 changes: 223 additions & 76 deletions src/Common/Common.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,19 @@ import moment from 'moment';
import {get, post} from './Api';
import { ROUTES } from './Constants'
import { sortCallback } from './Helper';
import { TeamList ,ResponseType, DeploymentNodeType, CDModalTab, FilterStates } from './Types';
import {
TeamList,
ResponseType,
DeploymentNodeType,
CDModalTab,
FilterStates,
CDMaterialServiceEnum,
CDMaterialServiceQueryParams,
CDMaterialResponseType,
CDMaterialsMetaInfo,
CDMaterialsApprovalInfo,
CDMaterialFilterQuery,
} from './Types'

export const getTeamListMin = (): Promise<TeamList> => {
// ignore active field
Expand Down Expand Up @@ -30,7 +42,7 @@ interface UserRole extends ResponseType {
}
}

let stageMap = {
const stageMap = {
PRECD: 'PRE',
CD: 'DEPLOY',
POSTCD: 'POST',
Expand All @@ -51,83 +63,218 @@ export function setImageTags(request, pipelineId: number, artifactId: number){
return post(`${ROUTES.IMAGE_TAGGING}/${pipelineId}/${artifactId}`,request )
}

// FIXME: This is only returning materials to cater the case of search in approval but it should be a common function service coming from dashboard.
export const getCDMaterials = (
cdMaterialId,
stageType: DeploymentNodeType,
abortSignal: AbortSignal,
isApprovalNode?: boolean,
imageTag?: string): Promise<any> => {
const URL = (!imageTag) ? `app/cd-pipeline/${cdMaterialId}/material?stage=${stageMap[stageType]}` : `app/cd-pipeline/${cdMaterialId}/material?stage=${stageMap[stageType]}&search=${imageTag}`

return get(URL, {
signal: abortSignal,
}).then((response) => {
let artifacts = response.result.ci_artifacts ?? []
if (!response.result) {
return {
materials: [],
const processURL = (url: string, params: object) => {
const validParams = Object.keys(params).filter((key) => {
return params[key] != null
})

if (!validParams.length) {
return url
}

const queryString = validParams
.map((key) => {
if (Array.isArray(params[key])) {
return `${key}=${params[key].join(',')}`
}
return `${key}=${params[key]}`
})
.join('&')

return `${url}?${queryString}`
}

const cdMaterialListModal = (artifacts: any[], offset: number, artifactId?: number, artifactStatus?: string) => {
if (!artifacts || !artifacts.length) return []

const markFirstSelected = offset === 0
const startIndex = offset
let isImageMarked = false

const materials = artifacts.map((material, index) => {
let artifactStatusValue = ''
const filterState = material.filterState ?? FilterStates.ALLOWED

if (artifactId && artifactStatus && material.id === artifactId) {
artifactStatusValue = artifactStatus
}
else {
const materials = artifacts.map((material, index) => {
let artifactStatusValue = ''
const filterState = material.filterState ?? FilterStates.ALLOWED

return {
index,
id: material.id,
deployedTime: material.deployed_time
? moment(material.deployed_time).format('ddd, DD MMM YYYY, hh:mm A')
: 'Not Deployed',
deployedBy: material.deployedBy,
wfrId: material.wfrId,
image: extractImage(material.image),
showChanges: false,
vulnerabilities: [],
buildTime: material.build_time || '',
tab: CDModalTab.Changes,
showSourceInfo: false,
deployed: material.deployed || false,
latest: material.latest || false,
vulnerabilitiesLoading: true,
scanned: material.scanned,
scanEnabled: material.scanEnabled,
isSelected: !material.vulnerable && filterState === FilterStates.ALLOWED && index === 0,
vulnerable: material.vulnerable,
runningOnParentCd: material.runningOnParentCd,
artifactStatus: artifactStatusValue,
userApprovalMetadata: material.userApprovalMetadata,
triggeredBy: material.triggeredBy,
isVirtualEnvironment: material.isVirtualEnvironment,
imageComment: material.imageComment,
imageReleaseTags: material.imageReleaseTags,
materialInfo: material.material_info
? material.material_info.map((mat) => {
return {
modifiedTime: mat.modifiedTime ? moment(mat.modifiedTime).format("ddd, DD MMM YYYY, hh:mm A") : '',
commitLink: createGitCommitUrl(mat.url, mat.revision),
author: mat.author || '',
message: mat.message || '',
revision: mat.revision || '',
tag: mat.tag || '',
webhookData: mat.webhookData || '',
url: mat.url || '',
branch:
(material.ciConfigureSourceType === SourceTypeMap.WEBHOOK
? material.ciConfigureSourceValue
: mat.branch) || '',
type: material.ciConfigureSourceType || '',
}
})
: [],
filterState,
}
})
return {
materials: materials
}

const selectImage =
!isImageMarked && markFirstSelected && filterState === FilterStates.ALLOWED ? !material.vulnerable : false
if (selectImage) {
isImageMarked = true
}

return {
index: startIndex + index,
id: material.id,
deployedTime: material.deployed_time
? moment(material.deployed_time).format('ddd, DD MMM YYYY, hh:mm A')
: 'Not Deployed',
deployedBy: material.deployedBy,
wfrId: material.wfrId,
tab: CDModalTab.Changes,
image: extractImage(material.image),
showChanges: false,
vulnerabilities: [],
buildTime: material.build_time || '',
isSelected: selectImage,
showSourceInfo: false,
deployed: material.deployed || false,
latest: material.latest || false,
vulnerabilitiesLoading: true,
scanned: material.scanned,
scanEnabled: material.scanEnabled,
vulnerable: material.vulnerable,
runningOnParentCd: material.runningOnParentCd,
artifactStatus: artifactStatusValue,
userApprovalMetadata: material.userApprovalMetadata,
triggeredBy: material.triggeredBy,
isVirtualEnvironment: material.isVirtualEnvironment,
imageComment: material.imageComment,
imageReleaseTags: material.imageReleaseTags,
// It is going to be null but required in type so can't remove
lastExecution: material.lastExecution,
materialInfo: material.material_info
? material.material_info.map((mat) => {
return {
modifiedTime: mat.modifiedTime
? moment(mat.modifiedTime).format('ddd, DD MMM YYYY, hh:mm A')
: '',
commitLink: createGitCommitUrl(mat.url, mat.revision),
author: mat.author || '',
message: mat.message || '',
revision: mat.revision || '',
tag: mat.tag || '',
webhookData: mat.webhookData || '',
url: mat.url || '',
branch:
(material.ciConfigureSourceType === SourceTypeMap.WEBHOOK
? material.ciConfigureSourceValue
: mat.branch) || '',
type: material.ciConfigureSourceType || '',
}
})
: [],
filterState,
appliedFiltersTimestamp: material.appliedFiltersTimestamp ?? '',
appliedFilters: material.appliedFilters ?? [],
appliedFiltersState: material.appliedFiltersState ?? FilterStates.ALLOWED,
createdTime: material.createdTime ?? '',
dataSource: material.data_source ?? '',
}
})
return materials
}

const processCDMaterialsApprovalInfo = (enableApproval: boolean, cdMaterialsResult): CDMaterialsApprovalInfo => {
if (!enableApproval) {
return {
approvalUsers: [],
userApprovalConfig: null,
requestedUserId: 0,
}
}

return {
approvalUsers: cdMaterialsResult.approvalUsers,
userApprovalConfig: cdMaterialsResult.userApprovalConfig,
requestedUserId: cdMaterialsResult.requestedUserId,
}
}

const processCDMaterialsMetaInfo = (cdMaterialsResult): CDMaterialsMetaInfo => {
if (!cdMaterialsResult) {
return {
tagsEditable: false,
appReleaseTagNames: [],
hideImageTaggingHardDelete: false,
resourceFilters: [],
totalCount: 0,
canApproverDeploy: cdMaterialsResult.canApproverDeploy ?? false,
}
}

return {
appReleaseTagNames: cdMaterialsResult.appReleaseTagNames,
tagsEditable: cdMaterialsResult.tagsEditable,
hideImageTaggingHardDelete: cdMaterialsResult.hideImageTaggingHardDelete,
resourceFilters: cdMaterialsResult.resourceFilters ?? [],
totalCount: cdMaterialsResult.totalCount ?? 0,
canApproverDeploy: cdMaterialsResult.canApproverDeploy ?? false,
}
}

const processCDMaterialServiceResponse = (
cdMaterialsResult,
stage: DeploymentNodeType,
offset: number,
filter: CDMaterialFilterQuery,
): CDMaterialResponseType => {
if (!cdMaterialsResult) {
return {
materials: [],
...processCDMaterialsMetaInfo(cdMaterialsResult),
...processCDMaterialsApprovalInfo(false, cdMaterialsResult),
}
}

const materials = cdMaterialListModal(
cdMaterialsResult.ci_artifacts,
offset ?? 0,
cdMaterialsResult.latest_wf_artifact_id,
cdMaterialsResult.latest_wf_artifact_status,
)
const approvalInfo = processCDMaterialsApprovalInfo(
stage === DeploymentNodeType.CD || stage === DeploymentNodeType.APPROVAL,
cdMaterialsResult,
)
const metaInfo = processCDMaterialsMetaInfo(cdMaterialsResult)

// TODO: On update of service would remove from here
const filteredMaterials =
filter && filter === CDMaterialFilterQuery.RESOURCE
? materials.filter((material) => {
return material.filterState === FilterStates.ALLOWED
})
: materials

return {
materials: filteredMaterials,
...approvalInfo,
...metaInfo,
}
}

const getSanitizedQueryParams = (queryParams: CDMaterialServiceQueryParams): CDMaterialServiceQueryParams => {
const { filter, ...rest } = queryParams
return rest
}

export const genericCDMaterialsService = (
serviceType: CDMaterialServiceEnum,
cdMaterialID: number,
stage: DeploymentNodeType,
signal: AbortSignal,
queryParams: CDMaterialServiceQueryParams = {},
): Promise<CDMaterialResponseType> => {
// TODO: On update of service would remove from here
const manipulatedParams = getSanitizedQueryParams(queryParams)

let URL
switch (serviceType) {
case CDMaterialServiceEnum.ROLLBACK:
URL = processURL(`${ROUTES.CD_MATERIAL_GET}/${cdMaterialID}/material/rollback`, manipulatedParams)
break

// Meant for handling getCDMaterialList
default:
URL = processURL(`${ROUTES.CD_MATERIAL_GET}/${cdMaterialID}/material`, { ...manipulatedParams, stage: stageMap[stage] })
break
}

return get(URL, { signal }).then((response) => {
return processCDMaterialServiceResponse(response.result, stage, queryParams.offset, queryParams.filter)
})
}

Expand Down
1 change: 1 addition & 0 deletions src/Common/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const ROUTES = {
PROJECT_LIST_MIN: 'team/autocomplete',
USER_CHECK_ROLE: 'user/check/roles',
IMAGE_TAGGING:'app/image-tagging',
CD_MATERIAL_GET: 'app/cd-pipeline'
}

export enum KEY_VALUE {
Expand Down
13 changes: 11 additions & 2 deletions src/Common/ImageTags.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ import { showError, stopPropagation } from './Helper'
import { TippyCustomized } from './TippyCustomized'
import { setImageTags } from './Common.service'
import Tippy from '@tippyjs/react'
import { Progressing } from './Progressing'

export const ImageTagsContainer = ({
// Setting it to zero in case of external pipeline
ciPipelineId,
artifactId,
imageComment,
Expand Down Expand Up @@ -47,6 +49,7 @@ export const ImageTagsContainer = ({
const [hardDeleteTags, setHardDeleteTags] = useState<ReleaseTag[]>([])
const [descriptionValidationMessage, setDescriptionValidationMessage] = useState<string>('')
const [textInput, setTextInput] = useState<string>('')
const [loading, setLoading] = useState<boolean>(false)


useEffect(() => {
Expand Down Expand Up @@ -213,7 +216,8 @@ export const ImageTagsContainer = ({
}

// set loading state true
setImageTags(payload, ciPipelineId, artifactId)
setLoading(true)
setImageTags(payload, ciPipelineId ?? 0, artifactId)
.then((res) => {
const tags = res.result?.imageReleaseTags?.map((tag) => ({
id: tag.id,
Expand Down Expand Up @@ -249,6 +253,9 @@ export const ImageTagsContainer = ({
showError(err)
}
})
.finally(()=>{
setLoading(false)
})
}

const renderInfoCard = (): JSX.Element => {
Expand Down Expand Up @@ -425,6 +432,7 @@ export const ImageTagsContainer = ({
stopPropagation(e)
handleCancel()
}}
disabled={loading}
>
Cancel
</button>
Expand All @@ -436,8 +444,9 @@ export const ImageTagsContainer = ({
stopPropagation(e)
onClickSave()
}}
disabled={loading}
>
Save
{loading ? <Progressing /> : 'Save'}
</button>
</div>
</div>
Expand Down
Loading

0 comments on commit b07c1b1

Please sign in to comment.