Skip to content

feat: add support for skipping hibernated apps in bulk deploy #2613

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Apr 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"homepage": "/dashboard",
"dependencies": {
"@devtron-labs/devtron-fe-common-lib": "1.11.0",
"@devtron-labs/devtron-fe-common-lib": "1.11.0-pre-1",
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
"@rjsf/core": "^5.13.3",
"@rjsf/utils": "^5.13.3",
Expand Down
19 changes: 15 additions & 4 deletions src/components/ApplicationGroup/AppGroup.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export interface BulkCDTriggerType extends BulkRuntimeParamsType {
appList: BulkCDDetailType[]
closePopup: (e) => void
updateBulkInputMaterial: (materialList: Record<string, any>) => void
onClickTriggerBulkCD: (appsToRetry?: Record<string, boolean>) => void
onClickTriggerBulkCD: (skipIfHibernated: boolean, appsToRetry?: Record<string, boolean>) => void
changeTab?: (
materrialId: string | number,
artifactId: number,
Expand Down Expand Up @@ -185,10 +185,21 @@ export interface TriggerResponseModalBodyProps {
envName?: string
}

export interface TriggerResponseModalFooterProps extends Pick<TriggerResponseModalBodyProps, 'isLoading' | 'responseList'> {
onClickRetryBuild: (appsToRetry: Record<string, boolean>) => void
type RetryFailedType =
| {
onClickRetryDeploy: BulkCDTriggerType['onClickTriggerBulkCD']
skipHibernatedApps: boolean
onClickRetryBuild?: never
}
| {
onClickRetryDeploy?: never
skipHibernatedApps?: never
onClickRetryBuild: (appsToRetry: Record<string, boolean>) => void
}

export type TriggerResponseModalFooterProps = Pick<TriggerResponseModalBodyProps, 'isLoading' | 'responseList'> & {
closePopup: (e) => void
}
} & RetryFailedType

export interface TriggerModalRowType {
rowData: ResponseRowType
Expand Down
6 changes: 5 additions & 1 deletion src/components/ApplicationGroup/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,24 +69,28 @@ export const BULK_VIRTUAL_RESPONSE_STATUS = {
[BulkResponseStatus.PASS]: 'Succeeded',
[BulkResponseStatus.FAIL]: 'Failed',
[BulkResponseStatus.UNAUTHORIZE]: 'Not authorised',
[BulkResponseStatus.SKIP]: 'Skipped',
}

export const BULK_CI_RESPONSE_STATUS_TEXT = {
[BulkResponseStatus.PASS]: 'Build triggered',
[BulkResponseStatus.FAIL]: 'Build not triggered',
[BulkResponseStatus.UNAUTHORIZE]: 'Not authorized',
[BulkResponseStatus.SKIP]: 'Skipped',
}

export const BULK_CD_RESPONSE_STATUS_TEXT = {
[BulkResponseStatus.PASS]: 'Deployment triggered',
[BulkResponseStatus.FAIL]: 'Deployment not triggered',
[BulkResponseStatus.UNAUTHORIZE]: 'Not authorized',
[BulkResponseStatus.SKIP]: 'Skipped',
}

export const responseListOrder = {
[BulkResponseStatus.FAIL]: 0,
[BulkResponseStatus.UNAUTHORIZE]: 1,
[BulkResponseStatus.PASS]: 2,
[BulkResponseStatus.SKIP]: 2,
[BulkResponseStatus.PASS]: 3,
}

export const BULK_HIBERNATE_ERROR_MESSAGE = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
CDMaterialResponseType,
DeploymentNodeType,
Drawer,
Progressing,
ReleaseTag,
ImageComment,
showError,
Expand Down Expand Up @@ -48,9 +47,12 @@ import {
Button,
ComponentSizeType,
AnimatedDeployButton,
ButtonVariantType,
Icon,
ButtonStyleType,
useMainContext,
} from '@devtron-labs/devtron-fe-common-lib'
import { useHistory, useLocation } from 'react-router-dom'
import { ReactComponent as Close } from '@Icons/ic-cross.svg'
import { ReactComponent as DeployIcon } from '@Icons/ic-nav-rocket.svg'
import { ReactComponent as PlayIcon } from '@Icons/ic-play-outline.svg'
import { ReactComponent as Error } from '@Icons/ic-warning.svg'
Expand Down Expand Up @@ -89,6 +91,7 @@ const validateRuntimeParameters = importComponentFromFELibrary(
() => ({ isValid: true, cellError: {} }),
'function',
)
const SkipHibernatedCheckbox = importComponentFromFELibrary('SkipHibernatedCheckbox', null, 'function')

// TODO: Fix release tags selection
export default function BulkCDTrigger({
Expand All @@ -109,6 +112,7 @@ export default function BulkCDTrigger({
runtimeParamsErrorState,
setRuntimeParamsErrorState,
}: BulkCDTriggerType) {
const { canFetchHelmAppStatus } = useMainContext()
const [selectedApp, setSelectedApp] = useState<BulkCDDetailType>(
appList.find((app) => !app.warningMessage) || appList[0],
)
Expand All @@ -125,6 +129,7 @@ export default function BulkCDTrigger({
const [isPartialActionAllowed, setIsPartialActionAllowed] = useState(false)
const [showResistanceBox, setShowResistanceBox] = useState(false)
const [currentSidebarTab, setCurrentSidebarTab] = useState<CDMaterialSidebarType>(CDMaterialSidebarType.IMAGE)
const [skipHibernatedApps, setSkipHibernatedApps] = useState<boolean>(false)

const location = useLocation()
const history = useHistory()
Expand Down Expand Up @@ -351,15 +356,18 @@ export default function BulkCDTrigger({
const renderHeaderSection = (): JSX.Element => {
return (
<div className="flex flex-align-center flex-justify dc__border-bottom bg__primary pt-16 pr-20 pb-16 pl-20">
<h2 className="fs-16 fw-6 lh-1-43 m-0">Deploy to {appList[0].envName}</h2>
<button
type="button"
className="dc__transparent flex icon-dim-24"
<h2 className="fs-16 fw-6 lh-1-5 m-0 dc__truncate">Deploy to {appList[0].envName}</h2>
<Button
dataTestId="bulk-cd-modal-close"
disabled={isLoading}
onClick={closeBulkCDModal}
>
<Close className="icon-dim-24" />
</button>
size={ComponentSizeType.xs}
icon={<Icon name="ic-close-small" size={null} color={null} />}
ariaLabel="close bulk cd trigger modal"
showAriaLabelInTippy={false}
style={ButtonStyleType.negativeGrey}
variant={ButtonVariantType.borderLess}
/>
</div>
)
}
Expand Down Expand Up @@ -835,7 +843,7 @@ export default function BulkCDTrigger({
} else {
isBulkDeploymentTriggered.current = true
stopPropagation(e)
onClickTriggerBulkCD()
onClickTriggerBulkCD(skipHibernatedApps)
setShowResistanceBox(false)
}
}
Expand All @@ -848,8 +856,21 @@ export default function BulkCDTrigger({

const renderFooterSection = (): JSX.Element => {
const isDeployButtonDisabled: boolean = isDeployDisabled()
const showSkipHibernatedCheckbox = !!SkipHibernatedCheckbox && canFetchHelmAppStatus
return (
<div className="dc__border-top flex right bg__primary px-20 py-16">
<div
className={`dc__border-top flex ${showSkipHibernatedCheckbox ? 'dc__content-space' : 'right'} bg__primary px-20 py-16`}
>
{showSkipHibernatedCheckbox && (
<SkipHibernatedCheckbox
isDeploymentLoading={isLoading}
envId={appList[0].envId}
envName={appList[0].envName}
appIds={appList.map((app) => app.appId)}
skipHibernated={skipHibernatedApps}
setSkipHibernated={setSkipHibernatedApps}
/>
)}
<div className="dc__position-rel tippy-over">
{!isDeployButtonDisabled && stage === DeploymentNodeType.CD && !isLoading ? (
<AnimatedDeployButton onButtonClick={onClickStartDeploy} isVirtualEnvironment={false} />
Expand All @@ -874,7 +895,7 @@ export default function BulkCDTrigger({
return (
<Drawer position="right" width="75%" minWidth="1024px" maxWidth="1200px">
<div className="bg__primary bulk-ci-trigger-container">
<div className='flexbox-col flex-grow-1 dc__overflow-hidden'>
<div className="flexbox-col flex-grow-1 dc__overflow-hidden">
{renderHeaderSection()}
{responseListLength ? (
<TriggerResponseModalBody
Expand All @@ -892,7 +913,8 @@ export default function BulkCDTrigger({
closePopup={closeBulkCDModal}
responseList={responseList}
isLoading={isLoading}
onClickRetryBuild={onClickTriggerBulkCD}
onClickRetryDeploy={onClickTriggerBulkCD}
skipHibernatedApps={skipHibernatedApps}
/>
) : (
renderFooterSection()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import {
ButtonStyleType,
ButtonVariantType,
ComponentSizeType,
API_STATUS_CODES,
} from '@devtron-labs/devtron-fe-common-lib'
import Tippy from '@tippyjs/react'
import { BUILD_STATUS, DEFAULT_GIT_BRANCH_VALUE, NO_COMMIT_SELECTED, URLS, ViewType } from '../../../../config'
Expand Down Expand Up @@ -1429,7 +1430,7 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
return true
}

const onClickTriggerBulkCD = (appsToRetry?: Record<string, boolean>) => {
const onClickTriggerBulkCD = (skipIfHibernated: boolean, appsToRetry?: Record<string, boolean>) => {
if (isCDLoading || !validateBulkRuntimeParams()) {
return
}
Expand Down Expand Up @@ -1482,6 +1483,7 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
...(getRuntimeParamsPayload
? { runtimeParamsPayload: getRuntimeParamsPayload(runtimeParams[currentAppId] ?? []) }
: {}),
skipIfHibernated,
}),
)
} else {
Expand Down Expand Up @@ -1544,19 +1546,19 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
})
} else {
const errorReason = response.reason
if (errorReason.code === 409) {
if (errorReason.code === API_STATUS_CODES.EXPECTATION_FAILED) {
const statusType = filterStatusType(
type,
BULK_CI_RESPONSE_STATUS_TEXT[BulkResponseStatus.FAIL],
BULK_VIRTUAL_RESPONSE_STATUS[BulkResponseStatus.FAIL],
BULK_CD_RESPONSE_STATUS_TEXT[BulkResponseStatus.FAIL],
BULK_CI_RESPONSE_STATUS_TEXT[BulkResponseStatus.SKIP],
BULK_VIRTUAL_RESPONSE_STATUS[BulkResponseStatus.SKIP],
BULK_CD_RESPONSE_STATUS_TEXT[BulkResponseStatus.SKIP],
)
_responseList.push({
appId: triggeredAppList[index].appId,
appName: triggeredAppList[index].appName,
statusText: statusType,
status: BulkResponseStatus.FAIL,
message: errorReason.errors[0].internalMessage,
status: BulkResponseStatus.SKIP,
message: errorReason.errors[0].userMessage,
})
} else if (errorReason.code === 403 || errorReason.code === 422) {
// Adding 422 to handle the unauthorized state due to deployment window
Expand Down Expand Up @@ -1941,7 +1943,7 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
}
if (!filteredWorkflows.length) {
return (
<div className='flex-grow-1'>
<div className="flex-grow-1">
<AppNotConfigured />
</div>
)
Expand Down Expand Up @@ -2099,7 +2101,7 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
)
}

const renderBulkSourchChange = (): JSX.Element | null => {
const renderBulkSourceChange = (): JSX.Element | null => {
if (!showBulkSourceChangeModal) {
return null
}
Expand Down Expand Up @@ -2452,12 +2454,12 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
{renderBulkCDMaterial()}
{renderBulkCIMaterial()}
{renderApprovalMaterial()}
{renderBulkSourchChange()}
{renderBulkSourceChange()}
</TriggerViewContext.Provider>
<div />
</div>
{!!selectedAppList.length && (
<div className="flexbox dc__gap-8 dc__content-space dc__border-top w-100 bg__primary pt-12 pr-20 pb-12 pl-20">
<div className="flexbox dc__gap-8 dc__content-space dc__border-top w-100 bg__primary px-20 py-12">
{renderSelectedApps()}
{renderBulkTriggerActionButtons()}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export const TriggerResponseModalFooter = ({
closePopup,
isLoading,
responseList,
skipHibernatedApps,
onClickRetryBuild,
onClickRetryDeploy,
}: TriggerResponseModalFooterProps) => {
const isShowRetryButton = responseList?.some((response) => response.status === BulkResponseStatus.FAIL)

Expand All @@ -45,7 +47,12 @@ export const TriggerResponseModalFooter = ({
appsToRetry[response.appId] = true
}
})
onClickRetryBuild(appsToRetry)

if (onClickRetryBuild) {
onClickRetryBuild(appsToRetry)
} else {
onClickRetryDeploy(skipHibernatedApps, appsToRetry)
}
}

return (
Expand Down
1 change: 1 addition & 0 deletions src/components/app/details/triggerView/cdMaterial.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,7 @@ const CDMaterial = ({
...(getRuntimeParamsPayload
? { runtimeParamsPayload: getRuntimeParamsPayload(runtimeParamsList ?? []) }
: {}),
skipIfHibernated: false,
})
.then((response: any) => {
if (response.result) {
Expand Down
Loading