Skip to content

Commit 7073dc3

Browse files
authored
Merge pull request #2780 from devtron-labs/feat/link-external-flux
feat: add support for linking external flux apps
2 parents 1b381a1 + 2c74cb7 commit 7073dc3

40 files changed

+593
-362
lines changed

.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,4 @@ FEATURE_MANAGE_TRAFFIC_ENABLE=false
7474
FEATURE_REDFISH_NODE_ENABLE=false
7575
FEATURE_INFRA_PROVISION_INFO_BLOCK_HIDE=false
7676
FEATURE_FLUX_DEPLOYMENTS_ENABLE=false
77+
FEATURE_LINK_EXTERNAL_FLUX_ENABLE=false

config.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,6 @@
5151
| SENTRY_RELEASE_VERSION | | Sentry release Version |
5252
| LOGIN_PAGE_IMAGE | | Login page image url |
5353
| FEATURE_FLUX_DEPLOYMENTS_ENABLE | false | Enables flux cd deployment type for devtron apps and devtron charts |
54+
| FEATURE_LINK_EXTERNAL_FLUX_ENABLE | false | Enables external flux cd migration |
5455

5556
# DASHBOARD CONFIG SECRET

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"private": true,
55
"homepage": "/dashboard",
66
"dependencies": {
7-
"@devtron-labs/devtron-fe-common-lib": "1.16.0",
7+
"@devtron-labs/devtron-fe-common-lib": "1.16.0-beta-1",
88
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
99
"@rjsf/core": "^5.13.3",
1010
"@rjsf/utils": "^5.13.3",

src/components/app/details/appDetails/IssuesCard.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,16 @@ const IssuesCard = ({ cardLoading, setErrorsList, toggleIssuesModal, setDetailed
8282
}, [appDetails])
8383

8484
useEffect(() => {
85-
if (appDetails.deploymentAppType === DeploymentAppTypes.GITOPS && appDetails.deploymentAppDeleteRequest) {
85+
if (appDetails.deploymentAppType === DeploymentAppTypes.ARGO && appDetails.deploymentAppDeleteRequest) {
8686
verifyDeployedClusterConnectionStatus()
8787
}
8888
}, [appDetails.appId, appDetails.environmentId])
8989

9090
const verifyDeployedClusterConnectionStatus = async (): Promise<void> => {
9191
await getClusterConnectionStatus(appDetails.environmentId).then((response: ClusterConnectionResponse) => {
9292
if (response.result) {
93-
response.result?.clusterReachable ? setClusterConnectionError(false) : setClusterConnectionError(true)
94-
setClusterName(response.result.clusterName)
93+
setClusterConnectionError(response.result.clusterReachable ?? false)
94+
setClusterName(response.result.clusterName ?? '')
9595
}
9696
})
9797
}

src/components/app/details/appDetails/SourceInfo.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ export const SourceInfo = ({
9494
const [hibernationPatchResponseLoading, setHibernationPatchResponseLoading] = useState<boolean>(false)
9595

9696
const isdeploymentAppDeleting = appDetails?.deploymentAppDeleteRequest || false
97-
const isArgoCdApp = appDetails?.deploymentAppType === DeploymentAppTypes.GITOPS
9897
const status = appDetails?.resourceTree?.status || ''
9998
const conditions = appDetails?.resourceTree?.conditions
10099
let message = null

src/components/app/details/triggerView/workflow/nodes/triggerCDNode.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export class TriggerCDNode extends Component<TriggerCDNodeProps, TriggerCDNodeSt
4545
gitopsConflictLoading: false,
4646
reloadNoGitOpsRepoConfiguredModal: false,
4747
gitOpsRepoWarningCondition:
48-
this.props.deploymentAppType === DeploymentAppTypes.GITOPS && this.props.isGitOpsRepoNotConfigured,
48+
this.props.deploymentAppType === DeploymentAppTypes.ARGO && this.props.isGitOpsRepoNotConfigured,
4949
}
5050
}
5151

@@ -68,7 +68,7 @@ export class TriggerCDNode extends Component<TriggerCDNodeProps, TriggerCDNodeSt
6868
if (prevProps.isGitOpsRepoNotConfigured !== this.props.isGitOpsRepoNotConfigured) {
6969
this.setState({
7070
gitOpsRepoWarningCondition:
71-
this.props.deploymentAppType === DeploymentAppTypes.GITOPS && this.props.isGitOpsRepoNotConfigured,
71+
this.props.deploymentAppType === DeploymentAppTypes.ARGO && this.props.isGitOpsRepoNotConfigured,
7272
})
7373
}
7474
}

src/components/app/details/triggerView/workflow/nodes/triggerPrePostCDNode.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import { getAppGroupDeploymentHistoryLink } from '../../../../../ApplicationGrou
3333

3434
export class TriggerPrePostCDNode extends Component<TriggerPrePostCDNodeProps, TriggerPrePostCDNodeState> {
3535
gitOpsRepoWarningCondition =
36-
this.props.deploymentAppType === DeploymentAppTypes.GITOPS && this.props.isGitOpsRepoNotConfigured
36+
this.props.deploymentAppType === DeploymentAppTypes.ARGO && this.props.isGitOpsRepoNotConfigured
3737

3838
constructor(props) {
3939
super(props)

src/components/app/list-new/AppListService.ts

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,16 @@ import {
2222
EnvironmentListHelmResult,
2323
Teams,
2424
getUrlWithSearchParams,
25+
APIOptions,
2526
} from '@devtron-labs/devtron-fe-common-lib'
2627
import moment from 'moment'
2728
import { Cluster } from '@Services/service.types'
2829
import { Moment12HourFormat, Routes } from '../../../config'
2930
import {
3031
AppListFilterConfig,
3132
AppListPayloadType,
33+
FluxCDTemplateType,
34+
GenericAppListResponse,
3235
GenericAppType,
3336
GetDevtronHelmAppListParamsType,
3437
HelmAppListResponse,
@@ -49,18 +52,27 @@ export const getDevtronInstalledHelmApps = (
4952
return get(url)
5053
}
5154

52-
export const getArgoInstalledExternalApps = (clusterIdsCsv: string, abortControllerRef?: MutableRefObject<AbortController>): Promise<ResponseType<GenericAppType[]>> =>
53-
get(`${Routes.ARGO_APPS}${clusterIdsCsv ? `?clusterIds=${clusterIdsCsv}` : ''}`, { abortControllerRef })
55+
export const getArgoInstalledExternalApps = (
56+
clusterIdsCsv: string,
57+
abortControllerRef?: MutableRefObject<AbortController>,
58+
): Promise<ResponseType<GenericAppType[]>> => {
59+
const url = getUrlWithSearchParams(Routes.ARGO_APPS, { clusterIds: clusterIdsCsv })
60+
return get(url, { abortControllerRef })
61+
}
5462

5563
export const getDevtronAppListDataToExport = (
5664
filterConfig: AppListFilterConfig,
5765
environmentList: EnvListMinDTO[],
5866
namespaceList: EnvironmentListHelmResult[],
5967
clusterList: Cluster[],
6068
projectList: Teams[],
61-
appCount: number
69+
appCount: number,
6270
) => {
63-
const appListPayload: AppListPayloadType = {...getDevtronAppListPayload(filterConfig, environmentList, namespaceList), offset: 0, size: appCount} // Over riding size and offset as we need all list (no pagination)
71+
const appListPayload: AppListPayloadType = {
72+
...getDevtronAppListPayload(filterConfig, environmentList, namespaceList),
73+
offset: 0,
74+
size: appCount,
75+
} // Over riding size and offset as we need all list (no pagination)
6476
const clusterMap = new Map<string, number>()
6577
clusterList.forEach((cluster) => clusterMap.set(cluster.cluster_name, cluster.id))
6678
return getAppList(appListPayload).then(({ result }) => {
@@ -111,3 +123,19 @@ export const getDevtronAppListDataToExport = (
111123
return []
112124
})
113125
}
126+
127+
export const getFluxInstalledExternalApps = async (
128+
clusterIdsCsv: string,
129+
options?: APIOptions,
130+
templateType?: FluxCDTemplateType,
131+
): Promise<ResponseType<GenericAppType[]>> => {
132+
const url = getUrlWithSearchParams(Routes.FLUX_APPS, { clusterIds: clusterIdsCsv, noStream: true })
133+
const response = await get<GenericAppListResponse>(url, options)
134+
const appList = response.result?.fluxApplication ?? []
135+
return {
136+
...response,
137+
result: templateType
138+
? appList.filter(({ fluxAppDeploymentType }) => fluxAppDeploymentType === templateType)
139+
: appList,
140+
}
141+
}

src/components/cdPipeline/BuildCD.tsx

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ import { EnvironmentWithSelectPickerType } from '@Components/CIPipelineN/types'
6363
import { BuildCDProps } from './types'
6464
import { MigrateToDevtron } from './MigrateToDevtron'
6565
import TriggerTypeRadio from './TriggerTypeRadio'
66-
import { MigrateToDevtronProps } from './MigrateToDevtron/types'
66+
import { DEPLOYMENT_APP_TYPE_LABEL } from './MigrateToDevtron/constants'
6767

6868
const VirtualEnvSelectionInfoText = importComponentFromFELibrary('VirtualEnvSelectionInfoText')
6969
const HelmManifestPush = importComponentFromFELibrary('HelmManifestPush')
@@ -140,14 +140,6 @@ export default function BuildCD({
140140
setFormData(_form)
141141
}
142142

143-
const handleMigrateFromAppTypeChange: MigrateToDevtronProps['handleMigrateFromAppTypeChange'] = (event) => {
144-
const { value } = event.target as HTMLInputElement
145-
setMigrateToDevtronFormState((prevState) => ({
146-
...prevState,
147-
deploymentAppType: value as MigrateToDevtronFormState['deploymentAppType'],
148-
}))
149-
}
150-
151143
const handleNamespaceChange = (event): void => {
152144
const _form = { ...formData }
153145
_form.namespace = event.target.value
@@ -771,7 +763,6 @@ export default function BuildCD({
771763
<MigrateToDevtron
772764
migrateToDevtronFormState={migrateToDevtronFormState}
773765
setMigrateToDevtronFormState={setMigrateToDevtronFormState}
774-
handleMigrateFromAppTypeChange={handleMigrateFromAppTypeChange}
775766
/>
776767
)
777768
}
@@ -785,9 +776,7 @@ export default function BuildCD({
785776
<ICInfo className="dc__no-shrink icon-dim-20 dc__no-shrink" />
786777
<span className="fs-13 fw-4 lh-20 cn-9 dc__word-break">
787778
This deployment pipeline was linked to&nbsp;
788-
{formData.deploymentAppType === DeploymentAppTypes.GITOPS
789-
? 'Argo CD application'
790-
: 'helm release'}
779+
{DEPLOYMENT_APP_TYPE_LABEL[formData.deploymentAppType as DeploymentAppTypes]}
791780
&nbsp;: {formData.deploymentAppName}
792781
</span>
793782
</div>

src/components/cdPipeline/CDPipeline.tsx

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,11 @@ import {
5353
ButtonStyleType,
5454
ButtonVariantType,
5555
ComponentSizeType,
56+
Icon,
5657
handleAnalyticsEvent,
5758
} from '@devtron-labs/devtron-fe-common-lib'
5859
import { useEffect, useMemo, useRef, useState } from 'react'
5960
import { Redirect, Route, Switch, useParams, useRouteMatch } from 'react-router-dom'
60-
import { ReactComponent as ICWarning } from '@Icons/ic-warning.svg'
61-
import { ReactComponent as Close } from '../../assets/icons/ic-close.svg'
6261
import { CDDeploymentTabText, RegistryPayloadType, SourceTypeMap, ViewType } from '../../config'
6362
import { getPluginIdsFromBuildStage, importComponentFromFELibrary, sortObjectArrayAlphabetically } from '../common'
6463
import BuildCD from './BuildCD'
@@ -92,6 +91,7 @@ import {
9291
import {
9392
calculateLastStepDetailsLogic,
9493
checkUniqueness,
94+
getIsExternalAppLinkable,
9595
getMigrateToDevtronRequiredPayload,
9696
handleDeleteCDNodePipeline,
9797
validateTask,
@@ -275,7 +275,7 @@ export default function CDPipeline({
275275

276276
const isExternalArgoPipeline =
277277
formData.releaseMode === ReleaseMode.MIGRATE_EXTERNAL_APPS &&
278-
formData.deploymentAppType === DeploymentAppTypes.GITOPS
278+
formData.deploymentAppType === DeploymentAppTypes.ARGO
279279

280280
const isGitOpsRepoNotConfigured = isExternalArgoPipeline ? false : isGitOpsRepoNotConfiguredProp
281281

@@ -942,7 +942,7 @@ export default function CDPipeline({
942942
setGitOpsRepoConfiguredWarning({ show: true, text: gitOpsRepoNotConfiguredWithOptionsHidden })
943943
}
944944
const isGitOpsRepoNotConfiguredAndOptionsVisible =
945-
formData.deploymentAppType === DeploymentAppTypes.GITOPS &&
945+
formData.deploymentAppType === DeploymentAppTypes.ARGO &&
946946
isGitOpsRepoNotConfigured &&
947947
!window._env_.HIDE_GITOPS_OR_HELM_OPTION
948948

@@ -973,7 +973,7 @@ export default function CDPipeline({
973973

974974
const savePipeline = async () => {
975975
if (!isMigratingFromExternalApp) {
976-
if (formData.deploymentAppType === DeploymentAppTypes.GITOPS && isGitOpsInstalledButNotConfigured) {
976+
if (formData.deploymentAppType === DeploymentAppTypes.ARGO && isGitOpsInstalledButNotConfigured) {
977977
ToastManager.showToast({
978978
variant: ToastVariantType.error,
979979
title: 'GitOps credentials not configured',
@@ -1092,7 +1092,7 @@ export default function CDPipeline({
10921092

10931093
const deleteCD = (force: boolean, cascadeDelete: boolean) => {
10941094
const isPartialDelete =
1095-
formData.deploymentAppType === DeploymentAppTypes.GITOPS && formData.deploymentAppCreated && !force
1095+
formData.deploymentAppType === DeploymentAppTypes.ARGO && formData.deploymentAppCreated && !force
10961096
const payload = {
10971097
action: isPartialDelete ? CD_PATCH_ACTION.DEPLOYMENT_PARTIAL_DELETE : CD_PATCH_ACTION.DELETE,
10981098
appId: parseInt(appId),
@@ -1221,7 +1221,7 @@ export default function CDPipeline({
12211221
>
12221222
Advanced options
12231223
{mandatoryPluginData && (!mandatoryPluginData.isValidPre || !mandatoryPluginData.isValidPost) && (
1224-
<ICWarning className="icon-dim-16 warning-icon-y7-imp dc__no-shrink" />
1224+
<Icon name="ic-warning" color="Y700" />
12251225
)}
12261226
</button>
12271227
)
@@ -1399,10 +1399,7 @@ export default function CDPipeline({
13991399
// Disable button if environment or release name is not selected
14001400
const getButtonDisabledMessage = (): string => {
14011401
if (isMigratingFromExternalApp) {
1402-
const isLinkable =
1403-
migrateToDevtronFormState.deploymentAppType === DeploymentAppTypes.HELM
1404-
? migrateToDevtronFormState.migrateFromHelmFormState.validationResponse.isLinkable
1405-
: migrateToDevtronFormState.migrateFromArgoFormState.validationResponse.isLinkable
1402+
const isLinkable = getIsExternalAppLinkable(migrateToDevtronFormState)
14061403
if (!isLinkable) {
14071404
return 'Please resolve errors before proceeding'
14081405
}
@@ -1428,12 +1425,19 @@ export default function CDPipeline({
14281425
}`}
14291426
>
14301427
<div className="flex flex-align-center flex-justify bg__primary px-20 py-12">
1431-
<h2 className="fs-16 fw-6 lh-1-43 m-0" data-testid="build-pipeline-heading">
1428+
<h2 className="fs-16 fw-6 lh-24 m-0" data-testid="build-pipeline-heading">
14321429
{title}
14331430
</h2>
1434-
<button type="button" className="dc__transparent flex icon-dim-24" onClick={closePipelineModal}>
1435-
<Close className="icon-dim-24" />
1436-
</button>
1431+
<Button
1432+
dataTestId="close-cd-modal"
1433+
icon={<Icon name="ic-close-large" color={null} />}
1434+
size={ComponentSizeType.small}
1435+
onClick={closePipelineModal}
1436+
ariaLabel="close modal"
1437+
showAriaLabelInTippy={false}
1438+
style={ButtonStyleType.negativeGrey}
1439+
variant={ButtonVariantType.borderLess}
1440+
/>
14371441
</div>
14381442

14391443
{!isAdvanced && !isTemplateView && (

0 commit comments

Comments
 (0)