diff --git a/pkg/db/overview.go b/pkg/db/overview.go index 244cdee89..246d93e7e 100644 --- a/pkg/db/overview.go +++ b/pkg/db/overview.go @@ -122,8 +122,6 @@ func (h *DBHandler) UpdateOverviewDeployment(ctx context.Context, transaction *s appInEnv.DeploymentMetaData.DeployAuthor = deployment.Metadata.DeployedByEmail appInEnv.DeploymentMetaData.DeployTime = fmt.Sprintf("%d", createdTime.Unix()) - app := getApplicationByName(latestOverview.Applications, deployment.App) - if deployment.Version != nil { //Check if not trying to deploy an undeploy version //Get the undeploy information from the release release, err := h.DBSelectReleaseByVersion(ctx, transaction, appInEnv.Name, appInEnv.Version, true) @@ -135,8 +133,6 @@ func (h *DBHandler) UpdateOverviewDeployment(ctx context.Context, transaction *s } appInEnv.UndeployVersion = release.Metadata.UndeployVersion } - app.Warnings = CalculateWarnings(ctx, app.Name, latestOverview.EnvironmentGroups) - app.UndeploySummary = deriveUndeploySummary(app.Name, latestOverview.EnvironmentGroups) err = h.WriteOverviewCache(ctx, transaction, latestOverview) if err != nil { return err @@ -248,63 +244,11 @@ func (h *DBHandler) UpdateOverviewRelease(ctx context.Context, transaction *sql. if h.IsOverviewEmpty(latestOverview) { return nil } - app := getApplicationByName(latestOverview.Applications, release.App) - if app == nil { - if release.Deleted { - return nil - } - selectApp, err := h.DBSelectApp(ctx, transaction, release.App) - if err != nil { - return fmt.Errorf("could not find application '%s' in apps table, got an error: %w", release.App, err) - } - if selectApp == nil { - return fmt.Errorf("could not find application '%s' in apps table: got no result", release.App) - } - app = &api.Application{ - Name: release.App, - Releases: []*api.Release{}, - SourceRepoUrl: "", // TODO - Team: selectApp.Metadata.Team, - UndeploySummary: 0, - Warnings: []*api.Warning{}, - } - latestOverview.Applications[release.App] = app - } - apiRelease := &api.Release{ - PrNumber: extractPrNumber(release.Metadata.SourceMessage), - Version: release.ReleaseNumber, - UndeployVersion: release.Metadata.UndeployVersion, - SourceAuthor: release.Metadata.SourceAuthor, - SourceCommitId: release.Metadata.SourceCommitId, - SourceMessage: release.Metadata.SourceMessage, - CreatedAt: timestamppb.New(release.Created), - DisplayVersion: release.Metadata.DisplayVersion, - IsMinor: release.Metadata.IsMinor, - IsPrepublish: release.Metadata.IsPrepublish, - } - foundRelease := false - for relIndex, currentRelease := range app.Releases { - if currentRelease.Version == release.ReleaseNumber { - if release.Deleted { - app.Releases = append(app.Releases[:relIndex], app.Releases[relIndex+1:]...) - } else { - app.Releases[relIndex] = apiRelease - } - foundRelease = true - } - } - if !foundRelease && !release.Deleted { - app.Releases = append(app.Releases, apiRelease) - } - - if release.Metadata.UndeployVersion { - app.UndeploySummary = deriveUndeploySummary(app.Name, latestOverview.EnvironmentGroups) - } - err = h.WriteOverviewCache(ctx, transaction, latestOverview) - if err != nil { - return err - } + //err = h.WriteOverviewCache(ctx, transaction, latestOverview) + //if err != nil { + // return err + //} return nil } @@ -312,7 +256,7 @@ func (h *DBHandler) IsOverviewEmpty(overviewResp *api.GetOverviewResponse) bool if overviewResp == nil { return true } - if len(overviewResp.Applications) == 0 && len(overviewResp.EnvironmentGroups) == 0 && overviewResp.GitRevision == "" { + if len(overviewResp.EnvironmentGroups) == 0 && overviewResp.GitRevision == "" { return true } return false diff --git a/services/frontend-service/src/ui/Pages/ReleaseHistory/ReleaseHistoryPage.tsx b/services/frontend-service/src/ui/Pages/ReleaseHistory/ReleaseHistoryPage.tsx index 04388d200..989d8ea51 100644 --- a/services/frontend-service/src/ui/Pages/ReleaseHistory/ReleaseHistoryPage.tsx +++ b/services/frontend-service/src/ui/Pages/ReleaseHistory/ReleaseHistoryPage.tsx @@ -14,19 +14,25 @@ along with kuberpult. If not, see Copyright freiheit.com*/ import { Releases } from '../../components/Releases/Releases'; -import { useGlobalLoadingState } from '../../utils/store'; -import React from 'react'; +import { getAppDetails, useAppDetailsForApp } from '../../utils/store'; +import React, { useEffect } from 'react'; import { TopAppBar } from '../../components/TopAppBar/TopAppBar'; +import { useAzureAuthSub } from '../../utils/AzureAuthProvider'; +import { Spinner } from '../../components/Spinner/Spinner'; export const ReleaseHistoryPage: React.FC = () => { const url = window.location.pathname.split('/'); const app_name = url[url.length - 1]; + const appDetails = useAppDetailsForApp(app_name); + const { authHeader } = useAzureAuthSub((auth) => auth); - const element = useGlobalLoadingState(); - if (element) { - return element; - } + useEffect(() => { + getAppDetails(app_name, authHeader); + }, [app_name, authHeader]); + if (!appDetails) { + return ; + } return (
diff --git a/services/frontend-service/src/ui/components/Releases/Releases.tsx b/services/frontend-service/src/ui/components/Releases/Releases.tsx index 98fbdd58c..4cfaccd9a 100644 --- a/services/frontend-service/src/ui/components/Releases/Releases.tsx +++ b/services/frontend-service/src/ui/components/Releases/Releases.tsx @@ -15,7 +15,7 @@ along with kuberpult. If not, see Copyright freiheit.com*/ import classNames from 'classnames'; import { Release } from '../../../api/api'; -import { useDisplayApplicationLocks, useReleasesForApp } from '../../utils/store'; +import { useAppDetailsForApp, useDisplayApplicationLocks } from '../../utils/store'; import { ReleaseCardMini } from '../ReleaseCardMini/ReleaseCardMini'; import './Releases.scss'; import { ApplicationLockChip } from '../ApplicationLockDisplay/ApplicationLockDisplay'; @@ -30,7 +30,7 @@ const dateFormat = (date: Date): string => { return `${months[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`; }; -const getReleasesForAppGroupByDate = (releases: Array): [Release, ...Release[]][] => { +const getReleasesForAppGroupByDate = (releases: Array | undefined): [Release, ...Release[]][] => { if (releases === undefined) { return []; } @@ -51,7 +51,7 @@ const getReleasesForAppGroupByDate = (releases: Array): [Release, ...Re export const Releases: React.FC = (props) => { const { app, className } = props; - const releases = useReleasesForApp(app); + const releases = useAppDetailsForApp(app).application?.releases; const displayAppLocks = useDisplayApplicationLocks(app); const rel = getReleasesForAppGroupByDate(releases); return ( diff --git a/services/frontend-service/src/ui/components/ServiceLane/ServiceLane.test.tsx b/services/frontend-service/src/ui/components/ServiceLane/ServiceLane.test.tsx index 5d75d8cd0..ab27d0a25 100644 --- a/services/frontend-service/src/ui/components/ServiceLane/ServiceLane.test.tsx +++ b/services/frontend-service/src/ui/components/ServiceLane/ServiceLane.test.tsx @@ -258,7 +258,7 @@ // // // ); -// const getWrapper = (overrides: { application: Application }) => render(getNode(overrides)); +// const getWrapper = (overrides: { application: OverviewApplication }) => render(getNode(overrides)); // describe.each(data)('Service Lane diff number', (testcase) => { // it(testcase.name, () => { // UpdateOverview.set({ diff --git a/services/frontend-service/src/ui/components/ServiceLane/ServiceLane.tsx b/services/frontend-service/src/ui/components/ServiceLane/ServiceLane.tsx index 13c8d6b9e..ca683f295 100644 --- a/services/frontend-service/src/ui/components/ServiceLane/ServiceLane.tsx +++ b/services/frontend-service/src/ui/components/ServiceLane/ServiceLane.tsx @@ -19,7 +19,6 @@ import { getAppDetails, showSnackbarError, showSnackbarWarn, - useAppDetails, useAppDetailsForApp, useCurrentlyExistsAtGroup, useMinorsForApp, @@ -110,14 +109,14 @@ export const ServiceLane: React.FC<{ application: OverviewApplication; hideMinor const { authHeader } = useAzureAuthSub((auth) => auth); // const deployedReleases = useDeployedReleases(application.name); // const allReleases = useVersionsForApp(application.name); - // const { navCallback } = useNavigateWithSearchParams('releasehistory/' + application.name); + //const { navCallback } = useNavigateWithSearchParams('releasehistory/' + application.Name); // const prepareUndeployOrUndeployText = deriveUndeployMessage(application.undeploySummary); - const appDetails = useAppDetails((map) => map[application.Name]); + const appDetails = useAppDetailsForApp(application.Name); React.useEffect(() => { - if (!appDetails) { - getAppDetails(application.Name, authHeader); - } - }, [application, authHeader, appDetails]); + // eslint-disable-next-line no-console + console.log('getting app details...'); + getAppDetails(application.Name, authHeader); + }, [application, authHeader]); if (!appDetails) { return ( @@ -187,8 +186,10 @@ export const ReadyServiceLane: React.FC<{ break; } }, [application.Name, props.appDetails.application?.undeploySummary]); - const minorReleases = useMinorsForApp(application.Name); - + let minorReleases = useMinorsForApp(application.Name); + if (!minorReleases) { + minorReleases = []; + } const prepareUndeployOrUndeployText = deriveUndeployMessage(props.appDetails.application?.undeploySummary); const releases = [ ...new Set( diff --git a/services/frontend-service/src/ui/utils/store.test.tsx b/services/frontend-service/src/ui/utils/store.test.tsx index 8902985c8..e93cf8639 100644 --- a/services/frontend-service/src/ui/utils/store.test.tsx +++ b/services/frontend-service/src/ui/utils/store.test.tsx @@ -1,1569 +1,1569 @@ -/*This file is part of kuberpult. - -Kuberpult is free software: you can redistribute it and/or modify -it under the terms of the Expat(MIT) License as published by -the Free Software Foundation. - -Kuberpult is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -MIT License for more details. - -You should have received a copy of the MIT License -along with kuberpult. If not, see . - -Copyright freiheit.com*/ -import { act, renderHook } from '@testing-library/react'; -import { - addAction, - AllLocks, - appendAction, - DisplayLock, - FlushRolloutStatus, - SnackbarStatus, - UpdateAction, - updateActions, - UpdateOverview, - UpdateRolloutStatus, - UpdateSnackbar, - useLocksConflictingWithActions, - useLocksSimilarTo, - useNavigateWithSearchParams, - useReleaseDifference, - useRolloutStatus, -} from './store'; -import { - BatchAction, - Environment, - EnvironmentGroup, - GetOverviewResponse, - LockBehavior, - Priority, - ReleaseTrainRequest_TargetType, - RolloutStatus, - StreamStatusResponse, - UndeploySummary, -} from '../../api/api'; -import { makeDisplayLock, makeLock } from '../../setupTests'; -import { BrowserRouter } from 'react-router-dom'; -import { ReactNode } from 'react'; - -describe('Test useLocksSimilarTo', () => { - type TestDataStore = { - name: string; - inputEnvGroups: EnvironmentGroup[]; // this just defines what locks generally exist - inputAction: BatchAction; // the action we are rendering currently in the sidebar - expectedLocks: AllLocks; - }; - - const testdata: TestDataStore[] = [ - { - name: 'empty data', - inputAction: { - action: { - $case: 'deleteEnvironmentLock', - deleteEnvironmentLock: { - environment: 'dev', - lockId: 'l1', - }, - }, - }, - inputEnvGroups: [], - expectedLocks: { - appLocks: [], - environmentLocks: [], - teamLocks: [], - }, - }, - { - name: 'one env lock: should not find another lock', - inputAction: { - action: { - $case: 'deleteEnvironmentLock', - deleteEnvironmentLock: { - environment: 'dev', - lockId: 'l1', - }, - }, - }, - inputEnvGroups: [ - { - environments: [ - { - name: 'dev', - distanceToUpstream: 0, - priority: Priority.UPSTREAM, - locks: { - l1: makeLock({ lockId: 'l1' }), - }, - applications: {}, - }, - ], - environmentGroupName: 'group1', - distanceToUpstream: 0, - priority: Priority.UNRECOGNIZED, - }, - ], - expectedLocks: { - appLocks: [], - environmentLocks: [], - teamLocks: [], - }, - }, - { - name: 'two env locks with same ID on different envs: should find the other lock', - inputAction: { - action: { - $case: 'deleteEnvironmentLock', - deleteEnvironmentLock: { - environment: 'dev', - lockId: 'l1', - }, - }, - }, - inputEnvGroups: [ - { - environments: [ - { - name: 'dev', - distanceToUpstream: 0, - priority: Priority.UPSTREAM, - locks: { - l1: makeLock({ lockId: 'l1' }), - }, - applications: {}, - }, - { - name: 'staging', - distanceToUpstream: 0, - priority: Priority.UPSTREAM, - locks: { - l1: makeLock({ lockId: 'l1' }), - }, - applications: {}, - }, - ], - environmentGroupName: 'group1', - distanceToUpstream: 0, - priority: Priority.UNRECOGNIZED, - }, - ], - expectedLocks: { - appLocks: [], - environmentLocks: [ - makeDisplayLock({ - lockId: 'l1', - environment: 'staging', - }), - ], - teamLocks: [], - }, - }, - { - name: 'env lock and app lock with same ID: deleting the env lock should find the other lock', - inputAction: { - action: { - $case: 'deleteEnvironmentLock', - deleteEnvironmentLock: { - environment: 'dev', - lockId: 'l1', - }, - }, - }, - inputEnvGroups: [ - { - environments: [ - { - name: 'dev', - distanceToUpstream: 0, - priority: Priority.UPSTREAM, - locks: { - l1: makeLock({ lockId: 'l1' }), - }, - applications: { - app1: { - name: 'betty', - locks: { - l1: makeLock({ lockId: 'l1' }), - }, - version: 666, - teamLocks: {}, - team: 'test-team', - undeployVersion: false, - queuedVersion: 0, - argoCd: undefined, - }, - }, - }, - ], - environmentGroupName: 'group1', - distanceToUpstream: 0, - priority: Priority.UNRECOGNIZED, - }, - ], - expectedLocks: { - appLocks: [ - makeDisplayLock({ - environment: 'dev', - lockId: 'l1', - application: 'betty', - message: 'lock msg 1', - }), - ], - environmentLocks: [], - teamLocks: [], - }, - }, - { - name: 'bug: delete-all button must appear for each entry. 2 Env Locks, 1 App lock exist. 1 Env lock, 1 app lock in cart', - inputAction: { - action: { - $case: 'deleteEnvironmentApplicationLock', - deleteEnvironmentApplicationLock: { - environment: 'dev', - lockId: 'l1', - application: 'app1', - }, - }, - }, - inputEnvGroups: [ - { - environments: [ - { - name: 'dev', - distanceToUpstream: 0, - priority: Priority.UPSTREAM, - locks: { - l1: makeLock({ lockId: 'l1' }), - }, - applications: { - app1: { - name: 'betty', - locks: { - l1: makeLock({ lockId: 'l1' }), - }, - teamLocks: { l1: makeLock({ lockId: 'l1' }) }, - team: 'test-team', - version: 666, - undeployVersion: false, - queuedVersion: 0, - argoCd: undefined, - }, - }, - }, - { - name: 'dev2', - distanceToUpstream: 0, - priority: Priority.UPSTREAM, - locks: { - l1: makeLock({ lockId: 'l1' }), - }, - applications: {}, - }, - ], - environmentGroupName: 'group1', - distanceToUpstream: 0, - priority: Priority.UNRECOGNIZED, - }, - ], - expectedLocks: { - appLocks: [ - makeDisplayLock({ - environment: 'dev', - lockId: 'l1', - application: 'betty', - message: 'lock msg 1', - }), - ], - environmentLocks: [ - makeDisplayLock({ - environment: 'dev', - lockId: 'l1', - message: 'lock msg 1', - }), - makeDisplayLock({ - environment: 'dev2', - lockId: 'l1', - message: 'lock msg 1', - }), - ], - teamLocks: [ - makeDisplayLock({ - environment: 'dev', - lockId: 'l1', - team: 'test-team', - message: 'lock msg 1', - }), - ], - }, - }, - ]; - - describe.each(testdata)('with', (testcase) => { - it(testcase.name, () => { - // given - updateActions([]); - UpdateOverview.set({ - applications: {}, - environmentGroups: testcase.inputEnvGroups, - }); - // when - const actions = renderHook(() => useLocksSimilarTo(testcase.inputAction)).result.current; - // then - expect(actions.appLocks).toStrictEqual(testcase.expectedLocks.appLocks); - expect(actions.environmentLocks).toStrictEqual(testcase.expectedLocks.environmentLocks); - expect(actions.teamLocks).toStrictEqual(testcase.expectedLocks.teamLocks); - }); - }); -}); - -describe('Test useNavigateWithSearchParams', () => { - type TestDataStore = { - name: string; - currentURL: string; - navigationTo: string; - expectedURL: string; - }; - - const testdata: TestDataStore[] = [ - { - name: 'url with no search parameters', - currentURL: '', - navigationTo: 'test-random-page', - expectedURL: 'test-random-page', - }, - { - name: 'url with some search parameters', - currentURL: '/ui/home/test/whaat?query1=boo&query2=bar', - navigationTo: 'test-random-page', - expectedURL: 'test-random-page?query1=boo&query2=bar', - }, - ]; - - describe.each(testdata)('with', (testcase) => { - it(testcase.name, () => { - // given - const wrapper = ({ children }: { children: ReactNode }) => {children}; - window.history.pushState({}, 'Test page', testcase.currentURL); - // when - const result = renderHook(() => useNavigateWithSearchParams(testcase.navigationTo), { wrapper }).result - .current; - // then - expect(result.navURL).toBe(testcase.expectedURL); - // when - act(() => { - result.navCallback(); - }); - // then - expect(window.location.href).toContain(testcase.expectedURL); - }); - }); -}); - -describe('Rollout Status', () => { - type Testcase = { - name: string; - events: Array; - expectedApps: Array<{ - application: string; - environment: string; - version: number; - rolloutStatus: RolloutStatus | undefined; - }>; - }; - - const testdata: Array = [ - { - name: 'not enabled if empty', - events: [], - - expectedApps: [ - { - application: 'app1', - environment: 'env1', - version: 0, - rolloutStatus: undefined, - }, - ], - }, - { - name: 'updates one app', - events: [ - { - environment: 'env1', - application: 'app1', - version: 1, - rolloutStatus: RolloutStatus.ROLLOUT_STATUS_SUCCESFUL, - }, - ], - - expectedApps: [ - { - application: 'app1', - environment: 'env1', - version: 1, - rolloutStatus: RolloutStatus.ROLLOUT_STATUS_SUCCESFUL, - }, - ], - }, - { - name: 'keep the latest entry per app and environment', - events: [ - { - environment: 'env1', - application: 'app1', - version: 1, - rolloutStatus: RolloutStatus.ROLLOUT_STATUS_SUCCESFUL, - }, - { - environment: 'env1', - application: 'app1', - version: 2, - rolloutStatus: RolloutStatus.ROLLOUT_STATUS_SUCCESFUL, - }, - ], - - expectedApps: [ - { - application: 'app1', - environment: 'env1', - version: 2, - rolloutStatus: RolloutStatus.ROLLOUT_STATUS_SUCCESFUL, - }, - ], - }, - { - name: 'flushes the state', - events: [ - { - environment: 'env1', - application: 'app1', - version: 1, - rolloutStatus: RolloutStatus.ROLLOUT_STATUS_SUCCESFUL, - }, - { error: true }, - ], - - expectedApps: [ - { - application: 'app1', - environment: 'env1', - version: 0, - rolloutStatus: undefined, - }, - ], - }, - ]; - - describe.each(testdata)('with', (testcase) => { - it(testcase.name, () => { - FlushRolloutStatus(); - testcase.events.forEach((ev) => { - if ('error' in ev) { - FlushRolloutStatus(); - } else { - UpdateRolloutStatus(ev); - } - }); - testcase.expectedApps.forEach((app) => { - const rollout = renderHook(() => - useRolloutStatus((getter) => getter.getAppStatus(app.application, app.version, app.environment)) - ); - expect(rollout.result.current).toEqual(app.rolloutStatus); - }); - }); - }); -}); - -describe('Test addAction duplicate detection', () => { - type TestDataStore = { - name: string; - firstAction: BatchAction; - differentAction: BatchAction; - }; - - const testdata: TestDataStore[] = [ - { - name: 'create environment lock', - firstAction: { - action: { - $case: 'createEnvironmentLock', - createEnvironmentLock: { - environment: 'dev', - lockId: 'foo', - message: 'do it', - ciLink: '', - }, - }, - }, - differentAction: { - action: { - $case: 'createEnvironmentLock', - createEnvironmentLock: { - environment: 'staging', - lockId: 'foo', - message: 'do it', - ciLink: '', - }, - }, - }, - }, - { - name: 'delete environment lock', - firstAction: { - action: { - $case: 'deleteEnvironmentLock', - deleteEnvironmentLock: { - environment: 'dev', - lockId: 'foo', - }, - }, - }, - differentAction: { - action: { - $case: 'deleteEnvironmentLock', - deleteEnvironmentLock: { - environment: 'staging', - lockId: 'foo', - }, - }, - }, - }, - { - name: 'create app lock', - firstAction: { - action: { - $case: 'createEnvironmentApplicationLock', - createEnvironmentApplicationLock: { - environment: 'dev', - application: 'app1', - lockId: 'foo', - message: 'do it', - ciLink: '', - }, - }, - }, - differentAction: { - action: { - $case: 'createEnvironmentApplicationLock', - createEnvironmentApplicationLock: { - environment: 'dev', - application: 'app2', - lockId: 'foo', - message: 'do it', - ciLink: '', - }, - }, - }, - }, - { - name: 'delete app lock', - firstAction: { - action: { - $case: 'deleteEnvironmentApplicationLock', - deleteEnvironmentApplicationLock: { - environment: 'dev', - application: 'app1', - lockId: 'foo', - }, - }, - }, - differentAction: { - action: { - $case: 'deleteEnvironmentApplicationLock', - deleteEnvironmentApplicationLock: { - environment: 'dev', - application: 'app2', - lockId: 'foo', - }, - }, - }, - }, - { - name: 'create team lock', - firstAction: { - action: { - $case: 'createEnvironmentTeamLock', - createEnvironmentTeamLock: { - environment: 'dev', - team: 'team1', - lockId: 'foo', - message: 'do it', - ciLink: '', - }, - }, - }, - differentAction: { - action: { - $case: 'createEnvironmentTeamLock', - createEnvironmentTeamLock: { - environment: 'dev', - team: 'team2', - lockId: 'foo', - message: 'do it', - ciLink: '', - }, - }, - }, - }, - { - name: 'delete team lock', - firstAction: { - action: { - $case: 'deleteEnvironmentTeamLock', - deleteEnvironmentTeamLock: { - environment: 'dev', - team: 'team1', - lockId: 'foo', - }, - }, - }, - differentAction: { - action: { - $case: 'deleteEnvironmentTeamLock', - deleteEnvironmentTeamLock: { - environment: 'dev', - team: 'team2', - lockId: 'foo', - }, - }, - }, - }, - { - name: 'deploy', - firstAction: { - action: { - $case: 'deploy', - deploy: { - environment: 'dev', - application: 'app1', - version: 1, - ignoreAllLocks: false, - lockBehavior: LockBehavior.IGNORE, - }, - }, - }, - differentAction: { - action: { - $case: 'deploy', - deploy: { - environment: 'dev', - application: 'app2', - version: 1, - ignoreAllLocks: false, - lockBehavior: LockBehavior.IGNORE, - }, - }, - }, - }, - { - name: 'undeploy', - firstAction: { - action: { - $case: 'undeploy', - undeploy: { - application: 'app1', - }, - }, - }, - differentAction: { - action: { - $case: 'undeploy', - undeploy: { - application: 'app2', - }, - }, - }, - }, - { - name: 'prepare undeploy', - firstAction: { - action: { - $case: 'prepareUndeploy', - prepareUndeploy: { - application: 'app1', - }, - }, - }, - differentAction: { - action: { - $case: 'prepareUndeploy', - prepareUndeploy: { - application: 'app2', - }, - }, - }, - }, - ]; - - describe.each(testdata)('with', (testcase) => { - it(testcase.name, () => { - // given - updateActions([]); - UpdateSnackbar.set({ show: false, status: SnackbarStatus.SUCCESS, content: '' }); - - expect(UpdateSnackbar.get().show).toStrictEqual(false); - // when - addAction(testcase.firstAction); - expect(UpdateSnackbar.get().show).toStrictEqual(false); - // then - expect(UpdateAction.get().actions.length).toStrictEqual(1); - - // when - addAction(testcase.firstAction); - // then - expect(UpdateAction.get().actions.length).toStrictEqual(1); - //and - expect(UpdateSnackbar.get().show).toStrictEqual(true); - - // when - addAction(testcase.differentAction); - // then - expect(UpdateAction.get().actions.length).toStrictEqual(2); - // when - addAction(testcase.differentAction); - // then - expect(UpdateAction.get().actions.length).toStrictEqual(2); - }); - }); -}); - -describe('Test maxActions', () => { - type TestDataStore = { - name: string; - inputActionsLen: number; - expectedLen: number; - expectedShowError: boolean; - }; - - const testdata: TestDataStore[] = [ - { - name: 'below limit', - inputActionsLen: 99, - expectedLen: 99, - expectedShowError: false, - }, - { - name: 'at limit', - inputActionsLen: 100, - expectedLen: 100, - expectedShowError: false, - }, - { - name: 'over limit', - inputActionsLen: 101, - expectedLen: 100, - expectedShowError: true, - }, - ]; - - describe.each(testdata)('with', (testcase) => { - it(testcase.name, () => { - // given - updateActions([]); - //and - UpdateSnackbar.set({ show: false, status: SnackbarStatus.SUCCESS, content: '' }); - // when - for (let i = 0; i < testcase.inputActionsLen; i++) { - appendAction([ - { - action: { - $case: 'deploy', - deploy: { - environment: 'foo', - application: 'bread' + i, - version: i, - ignoreAllLocks: false, - lockBehavior: LockBehavior.IGNORE, - }, - }, - }, - ]); - } - - // then - expect(UpdateSnackbar.get().show).toStrictEqual(testcase.expectedShowError); - expect(UpdateAction.get().actions.length).toStrictEqual(testcase.expectedLen); - }); - }); -}); - -describe('Test useLocksConflictingWithActions', () => { - type TestDataStore = { - name: string; - actions: BatchAction[]; - expectedAppLocks: DisplayLock[]; - expectedEnvLocks: DisplayLock[]; - environments: Environment[]; - }; - - const testdata: TestDataStore[] = [ - { - name: 'empty actions empty locks', - actions: [], - expectedAppLocks: [], - expectedEnvLocks: [], - environments: [], - }, - { - name: 'deploy action and related app lock and env lock', - actions: [ - { - action: { - $case: 'deploy', - deploy: { - environment: 'dev', - application: 'app1', - version: 1, - ignoreAllLocks: false, - lockBehavior: LockBehavior.IGNORE, - }, - }, - }, - ], - environments: [ - { - name: 'dev', - locks: { - 'lock-env-dev': makeLock({ - message: 'locked because christmas', - lockId: 'my-env-lock1', - }), - }, - applications: { - echo: { - name: 'app1', - version: 0, - locks: { - applock: makeLock({ - lockId: 'app-lock-id', - message: 'i do not like this app', - }), - }, - queuedVersion: 0, - undeployVersion: false, - teamLocks: {}, - team: 'test-team', - }, - }, - distanceToUpstream: 0, - priority: 0, - }, - ], - expectedAppLocks: [ - makeDisplayLock({ - lockId: 'app-lock-id', - application: 'app1', - message: 'i do not like this app', - environment: 'dev', - }), - ], - expectedEnvLocks: [ - makeDisplayLock({ - lockId: 'my-env-lock1', - environment: 'dev', - message: 'locked because christmas', - }), - ], - }, - { - name: 'deploy action and unrelated locks', - actions: [ - { - action: { - $case: 'deploy', - deploy: { - environment: 'dev', - application: 'app1', - version: 1, - ignoreAllLocks: false, - lockBehavior: LockBehavior.IGNORE, - }, - }, - }, - ], - environments: [ - { - name: 'staging', // this lock differs by stage - locks: { - 'lock-env-dev': makeLock({ - message: 'locked because christmas', - lockId: 'my-env-lock1', - }), - }, - applications: { - echo: { - name: 'anotherapp', // this lock differs by app - version: 0, - locks: { - applock: makeLock({ - lockId: 'app-lock-id', - message: 'i do not like this app', - }), - }, - teamLocks: {}, - team: 'test-team', - queuedVersion: 0, - undeployVersion: false, - }, - }, - distanceToUpstream: 0, - priority: 0, - }, - ], - expectedAppLocks: [], - expectedEnvLocks: [], - }, - ]; - - describe.each(testdata)('with', (testcase) => { - it(testcase.name, () => { - // given - updateActions(testcase.actions); - UpdateOverview.set({ - applications: {}, - environmentGroups: [ - { - environmentGroupName: 'g1', - environments: testcase.environments, - distanceToUpstream: 0, - priority: Priority.UNRECOGNIZED, - }, - ], - }); - - // when - const actualLocks = renderHook(() => useLocksConflictingWithActions()).result.current; - // then - expect(actualLocks.environmentLocks).toStrictEqual(testcase.expectedEnvLocks); - expect(actualLocks.appLocks).toStrictEqual(testcase.expectedAppLocks); - }); - }); -}); - -describe('Test addAction blocking release train additions', () => { - type TestDataStore = { - name: string; - firstAction: BatchAction; - differentAction: BatchAction; - expectedActions: number; - }; - - const testdata: TestDataStore[] = [ - { - name: 'deploy 2 in a row', - expectedActions: 2, - firstAction: { - action: { - $case: 'deploy', - deploy: { - environment: 'dev', - application: 'app1', - version: 1, - ignoreAllLocks: false, - lockBehavior: LockBehavior.IGNORE, - }, - }, - }, - differentAction: { - action: { - $case: 'deploy', - deploy: { - environment: 'dev', - application: 'app2', - version: 1, - ignoreAllLocks: false, - lockBehavior: LockBehavior.IGNORE, - }, - }, - }, - }, - { - name: 'can not add release train after deploy action', - expectedActions: 1, - firstAction: { - action: { - $case: 'deploy', - deploy: { - environment: 'dev', - application: 'app1', - version: 1, - ignoreAllLocks: false, - lockBehavior: LockBehavior.IGNORE, - }, - }, - }, - differentAction: { - action: { - $case: 'releaseTrain', - releaseTrain: { - target: 'dev', - team: '', - commitHash: '', - ciLink: '', - targetType: ReleaseTrainRequest_TargetType.UNKNOWN, - }, - }, - }, - }, - { - name: 'can not add release train after release train', - expectedActions: 1, - firstAction: { - action: { - $case: 'releaseTrain', - releaseTrain: { - target: 'dev', - team: '', - commitHash: '', - ciLink: '', - targetType: ReleaseTrainRequest_TargetType.UNKNOWN, - }, - }, - }, - differentAction: { - action: { - $case: 'releaseTrain', - releaseTrain: { - target: 'stagin', - team: '', - commitHash: '', - ciLink: '', - targetType: ReleaseTrainRequest_TargetType.UNKNOWN, - }, - }, - }, - }, - { - name: 'can not add deploy action after release train', - expectedActions: 1, - firstAction: { - action: { - $case: 'releaseTrain', - releaseTrain: { - target: 'dev', - team: '', - commitHash: '', - ciLink: '', - targetType: ReleaseTrainRequest_TargetType.UNKNOWN, - }, - }, - }, - differentAction: { - action: { - $case: 'deploy', - deploy: { - environment: 'dev', - application: 'app1', - version: 1, - ignoreAllLocks: false, - lockBehavior: LockBehavior.IGNORE, - }, - }, - }, - }, - ]; - - describe.each(testdata)('with', (testcase) => { - it(testcase.name, () => { - // given - updateActions([]); - - // when - addAction(testcase.firstAction); - // then - expect(UpdateAction.get().actions.length).toStrictEqual(1); - - // when - addAction(testcase.differentAction); - // then - expect(UpdateAction.get().actions.length).toStrictEqual(testcase.expectedActions); - }); - }); -}); - -describe('Test Calculate Release Difference', () => { - type TestDataStore = { - name: string; - inputOverview: GetOverviewResponse; - inputVersion: number; - expectedDifference: number; - }; - - const appName = 'testApp'; - const envName = 'testEnv'; - - const testdata: TestDataStore[] = [ - { - name: 'Simple diff calculation', - inputOverview: { - applications: { - [appName]: { - name: appName, - releases: [ - { - version: 10, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - { - version: 12, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - { - version: 15, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - ], - undeploySummary: UndeploySummary.NORMAL, - sourceRepoUrl: '', - team: '', - warnings: [], - }, - }, - environmentGroups: [ - { - environmentGroupName: 'test', - environments: [ - { - name: envName, - locks: {}, - applications: { - [appName]: { - name: appName, - version: 10, - locks: {}, - queuedVersion: 0, - undeployVersion: false, - teamLocks: {}, - team: '', - }, - }, - distanceToUpstream: 0, - priority: Priority.PROD, - }, - ], - distanceToUpstream: 0, - priority: Priority.PROD, - }, - ], - gitRevision: '', - branch: '', - lightweightApps: [ - { - Name: 'test', - Team: 'test', - }, - ], - manifestRepoUrl: '', - }, - inputVersion: 15, - expectedDifference: 2, - }, - { - name: 'negative diff', - inputOverview: { - applications: { - [appName]: { - name: appName, - releases: [ - { - version: 10, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - { - version: 12, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - ], - undeploySummary: UndeploySummary.NORMAL, - sourceRepoUrl: '', - team: '', - warnings: [], - }, - }, - environmentGroups: [ - { - environmentGroupName: 'test', - environments: [ - { - name: envName, - locks: {}, - applications: { - [appName]: { - name: appName, - version: 12, - locks: {}, - queuedVersion: 0, - undeployVersion: false, - teamLocks: {}, - team: '', - }, - }, - distanceToUpstream: 0, - priority: Priority.PROD, - }, - ], - distanceToUpstream: 0, - priority: Priority.PROD, - }, - ], - gitRevision: '', - branch: '', - lightweightApps: [ - { - Name: 'test', - Team: 'test', - }, - ], - manifestRepoUrl: '', - }, - inputVersion: 10, - expectedDifference: -1, - }, - { - name: 'the input version does not exist', - inputOverview: { - applications: { - [appName]: { - name: appName, - releases: [ - { - version: 10, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - { - version: 12, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - ], - undeploySummary: UndeploySummary.NORMAL, - sourceRepoUrl: '', - team: '', - warnings: [], - }, - }, - environmentGroups: [ - { - environmentGroupName: 'test', - environments: [ - { - name: envName, - locks: {}, - applications: { - [appName]: { - name: appName, - version: 12, - locks: {}, - queuedVersion: 0, - undeployVersion: false, - teamLocks: {}, - team: '', - }, - }, - distanceToUpstream: 0, - priority: Priority.PROD, - }, - ], - distanceToUpstream: 0, - priority: Priority.PROD, - }, - ], - gitRevision: '', - branch: '', - manifestRepoUrl: '', - lightweightApps: [ - { - Name: 'test', - Team: 'test', - }, - ], - }, - inputVersion: 11, - expectedDifference: 0, - }, - { - name: 'app does not exist in the applications', - inputOverview: { - applications: { - exampleApp: { - name: appName, - releases: [ - { - version: 10, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - { - version: 12, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - ], - undeploySummary: UndeploySummary.NORMAL, - sourceRepoUrl: '', - team: '', - warnings: [], - }, - }, - environmentGroups: [ - { - environmentGroupName: 'test', - environments: [ - { - name: envName, - locks: {}, - applications: { - [appName]: { - name: appName, - version: 12, - locks: {}, - queuedVersion: 0, - undeployVersion: false, - teamLocks: {}, - team: '', - }, - }, - distanceToUpstream: 0, - priority: Priority.PROD, - }, - ], - distanceToUpstream: 0, - priority: Priority.PROD, - }, - ], - gitRevision: '', - branch: '', - manifestRepoUrl: '', - lightweightApps: [ - { - Name: 'test', - Team: 'test', - }, - ], - }, - inputVersion: 10, - expectedDifference: 0, - }, - { - name: 'app does not exist in the environment applications', - inputOverview: { - applications: { - [appName]: { - name: appName, - releases: [ - { - version: 10, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - { - version: 12, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - ], - undeploySummary: UndeploySummary.NORMAL, - sourceRepoUrl: '', - team: '', - warnings: [], - }, - }, - environmentGroups: [ - { - environmentGroupName: 'test', - environments: [ - { - name: envName, - locks: {}, - applications: { - exampleApp: { - name: appName, - version: 12, - locks: {}, - queuedVersion: 0, - undeployVersion: false, - teamLocks: {}, - team: '', - }, - }, - distanceToUpstream: 0, - priority: Priority.PROD, - }, - ], - distanceToUpstream: 0, - priority: Priority.PROD, - }, - ], - gitRevision: '', - branch: '', - manifestRepoUrl: '', - lightweightApps: [ - { - Name: 'test', - Team: 'test', - }, - ], - }, - inputVersion: 10, - expectedDifference: 0, - }, - { - name: 'environment does not exist in the envs', - inputOverview: { - applications: { - [appName]: { - name: appName, - releases: [ - { - version: 10, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - { - version: 12, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - ], - undeploySummary: UndeploySummary.NORMAL, - sourceRepoUrl: '', - team: '', - warnings: [], - }, - }, - environmentGroups: [ - { - environmentGroupName: 'test', - environments: [ - { - name: 'exampleEnv', - locks: {}, - applications: { - exampleApp: { - name: appName, - version: 12, - locks: {}, - queuedVersion: 0, - undeployVersion: false, - teamLocks: {}, - team: '', - }, - }, - distanceToUpstream: 0, - priority: Priority.PROD, - }, - ], - distanceToUpstream: 0, - priority: Priority.PROD, - }, - ], - gitRevision: '', - branch: '', - lightweightApps: [ - { - Name: 'test', - Team: 'test', - }, - ], - manifestRepoUrl: '', - }, - inputVersion: 10, - expectedDifference: 0, - }, - ]; - describe.each(testdata)('with', (testcase) => { - it(testcase.name, () => { - updateActions([]); - UpdateOverview.set(testcase.inputOverview); - - const calculatedDiff = renderHook(() => useReleaseDifference(testcase.inputVersion, appName, envName)) - .result.current; - expect(calculatedDiff).toStrictEqual(testcase.expectedDifference); - }); - }); -}); +// /*This file is part of kuberpult. +// +// Kuberpult is free software: you can redistribute it and/or modify +// it under the terms of the Expat(MIT) License as published by +// the Free Software Foundation. +// +// Kuberpult is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// MIT License for more details. +// +// You should have received a copy of the MIT License +// along with kuberpult. If not, see . +// +// Copyright freiheit.com*/ +// import { act, renderHook } from '@testing-library/react'; +// import { +// addAction, +// AllLocks, +// appendAction, +// DisplayLock, +// FlushRolloutStatus, +// SnackbarStatus, +// UpdateAction, +// updateActions, +// UpdateOverview, +// UpdateRolloutStatus, +// UpdateSnackbar, +// useLocksConflictingWithActions, +// useLocksSimilarTo, +// useNavigateWithSearchParams, +// useReleaseDifference, +// useRolloutStatus, +// } from './store'; +// import { +// BatchAction, +// Environment, +// EnvironmentGroup, +// GetOverviewResponse, +// LockBehavior, +// Priority, +// ReleaseTrainRequest_TargetType, +// RolloutStatus, +// StreamStatusResponse, +// UndeploySummary, +// } from '../../api/api'; +// import { makeDisplayLock, makeLock } from '../../setupTests'; +// import { BrowserRouter } from 'react-router-dom'; +// import { ReactNode } from 'react'; +// +// describe('Test useLocksSimilarTo', () => { +// type TestDataStore = { +// name: string; +// inputEnvGroups: EnvironmentGroup[]; // this just defines what locks generally exist +// inputAction: BatchAction; // the action we are rendering currently in the sidebar +// expectedLocks: AllLocks; +// }; +// +// const testdata: TestDataStore[] = [ +// { +// name: 'empty data', +// inputAction: { +// action: { +// $case: 'deleteEnvironmentLock', +// deleteEnvironmentLock: { +// environment: 'dev', +// lockId: 'l1', +// }, +// }, +// }, +// inputEnvGroups: [], +// expectedLocks: { +// appLocks: [], +// environmentLocks: [], +// teamLocks: [], +// }, +// }, +// { +// name: 'one env lock: should not find another lock', +// inputAction: { +// action: { +// $case: 'deleteEnvironmentLock', +// deleteEnvironmentLock: { +// environment: 'dev', +// lockId: 'l1', +// }, +// }, +// }, +// inputEnvGroups: [ +// { +// environments: [ +// { +// name: 'dev', +// distanceToUpstream: 0, +// priority: Priority.UPSTREAM, +// locks: { +// l1: makeLock({ lockId: 'l1' }), +// }, +// applications: {}, +// }, +// ], +// environmentGroupName: 'group1', +// distanceToUpstream: 0, +// priority: Priority.UNRECOGNIZED, +// }, +// ], +// expectedLocks: { +// appLocks: [], +// environmentLocks: [], +// teamLocks: [], +// }, +// }, +// { +// name: 'two env locks with same ID on different envs: should find the other lock', +// inputAction: { +// action: { +// $case: 'deleteEnvironmentLock', +// deleteEnvironmentLock: { +// environment: 'dev', +// lockId: 'l1', +// }, +// }, +// }, +// inputEnvGroups: [ +// { +// environments: [ +// { +// name: 'dev', +// distanceToUpstream: 0, +// priority: Priority.UPSTREAM, +// locks: { +// l1: makeLock({ lockId: 'l1' }), +// }, +// applications: {}, +// }, +// { +// name: 'staging', +// distanceToUpstream: 0, +// priority: Priority.UPSTREAM, +// locks: { +// l1: makeLock({ lockId: 'l1' }), +// }, +// applications: {}, +// }, +// ], +// environmentGroupName: 'group1', +// distanceToUpstream: 0, +// priority: Priority.UNRECOGNIZED, +// }, +// ], +// expectedLocks: { +// appLocks: [], +// environmentLocks: [ +// makeDisplayLock({ +// lockId: 'l1', +// environment: 'staging', +// }), +// ], +// teamLocks: [], +// }, +// }, +// { +// name: 'env lock and app lock with same ID: deleting the env lock should find the other lock', +// inputAction: { +// action: { +// $case: 'deleteEnvironmentLock', +// deleteEnvironmentLock: { +// environment: 'dev', +// lockId: 'l1', +// }, +// }, +// }, +// inputEnvGroups: [ +// { +// environments: [ +// { +// name: 'dev', +// distanceToUpstream: 0, +// priority: Priority.UPSTREAM, +// locks: { +// l1: makeLock({ lockId: 'l1' }), +// }, +// applications: { +// app1: { +// name: 'betty', +// locks: { +// l1: makeLock({ lockId: 'l1' }), +// }, +// version: 666, +// teamLocks: {}, +// team: 'test-team', +// undeployVersion: false, +// queuedVersion: 0, +// argoCd: undefined, +// }, +// }, +// }, +// ], +// environmentGroupName: 'group1', +// distanceToUpstream: 0, +// priority: Priority.UNRECOGNIZED, +// }, +// ], +// expectedLocks: { +// appLocks: [ +// makeDisplayLock({ +// environment: 'dev', +// lockId: 'l1', +// application: 'betty', +// message: 'lock msg 1', +// }), +// ], +// environmentLocks: [], +// teamLocks: [], +// }, +// }, +// { +// name: 'bug: delete-all button must appear for each entry. 2 Env Locks, 1 App lock exist. 1 Env lock, 1 app lock in cart', +// inputAction: { +// action: { +// $case: 'deleteEnvironmentApplicationLock', +// deleteEnvironmentApplicationLock: { +// environment: 'dev', +// lockId: 'l1', +// application: 'app1', +// }, +// }, +// }, +// inputEnvGroups: [ +// { +// environments: [ +// { +// name: 'dev', +// distanceToUpstream: 0, +// priority: Priority.UPSTREAM, +// locks: { +// l1: makeLock({ lockId: 'l1' }), +// }, +// applications: { +// app1: { +// name: 'betty', +// locks: { +// l1: makeLock({ lockId: 'l1' }), +// }, +// teamLocks: { l1: makeLock({ lockId: 'l1' }) }, +// team: 'test-team', +// version: 666, +// undeployVersion: false, +// queuedVersion: 0, +// argoCd: undefined, +// }, +// }, +// }, +// { +// name: 'dev2', +// distanceToUpstream: 0, +// priority: Priority.UPSTREAM, +// locks: { +// l1: makeLock({ lockId: 'l1' }), +// }, +// applications: {}, +// }, +// ], +// environmentGroupName: 'group1', +// distanceToUpstream: 0, +// priority: Priority.UNRECOGNIZED, +// }, +// ], +// expectedLocks: { +// appLocks: [ +// makeDisplayLock({ +// environment: 'dev', +// lockId: 'l1', +// application: 'betty', +// message: 'lock msg 1', +// }), +// ], +// environmentLocks: [ +// makeDisplayLock({ +// environment: 'dev', +// lockId: 'l1', +// message: 'lock msg 1', +// }), +// makeDisplayLock({ +// environment: 'dev2', +// lockId: 'l1', +// message: 'lock msg 1', +// }), +// ], +// teamLocks: [ +// makeDisplayLock({ +// environment: 'dev', +// lockId: 'l1', +// team: 'test-team', +// message: 'lock msg 1', +// }), +// ], +// }, +// }, +// ]; +// +// describe.each(testdata)('with', (testcase) => { +// it(testcase.name, () => { +// // given +// updateActions([]); +// UpdateOverview.set({ +// applications: {}, +// environmentGroups: testcase.inputEnvGroups, +// }); +// // when +// const actions = renderHook(() => useLocksSimilarTo(testcase.inputAction)).result.current; +// // then +// expect(actions.appLocks).toStrictEqual(testcase.expectedLocks.appLocks); +// expect(actions.environmentLocks).toStrictEqual(testcase.expectedLocks.environmentLocks); +// expect(actions.teamLocks).toStrictEqual(testcase.expectedLocks.teamLocks); +// }); +// }); +// }); +// +// describe('Test useNavigateWithSearchParams', () => { +// type TestDataStore = { +// name: string; +// currentURL: string; +// navigationTo: string; +// expectedURL: string; +// }; +// +// const testdata: TestDataStore[] = [ +// { +// name: 'url with no search parameters', +// currentURL: '', +// navigationTo: 'test-random-page', +// expectedURL: 'test-random-page', +// }, +// { +// name: 'url with some search parameters', +// currentURL: '/ui/home/test/whaat?query1=boo&query2=bar', +// navigationTo: 'test-random-page', +// expectedURL: 'test-random-page?query1=boo&query2=bar', +// }, +// ]; +// +// describe.each(testdata)('with', (testcase) => { +// it(testcase.name, () => { +// // given +// const wrapper = ({ children }: { children: ReactNode }) => {children}; +// window.history.pushState({}, 'Test page', testcase.currentURL); +// // when +// const result = renderHook(() => useNavigateWithSearchParams(testcase.navigationTo), { wrapper }).result +// .current; +// // then +// expect(result.navURL).toBe(testcase.expectedURL); +// // when +// act(() => { +// result.navCallback(); +// }); +// // then +// expect(window.location.href).toContain(testcase.expectedURL); +// }); +// }); +// }); +// +// describe('Rollout Status', () => { +// type Testcase = { +// name: string; +// events: Array; +// expectedApps: Array<{ +// application: string; +// environment: string; +// version: number; +// rolloutStatus: RolloutStatus | undefined; +// }>; +// }; +// +// const testdata: Array = [ +// { +// name: 'not enabled if empty', +// events: [], +// +// expectedApps: [ +// { +// application: 'app1', +// environment: 'env1', +// version: 0, +// rolloutStatus: undefined, +// }, +// ], +// }, +// { +// name: 'updates one app', +// events: [ +// { +// environment: 'env1', +// application: 'app1', +// version: 1, +// rolloutStatus: RolloutStatus.ROLLOUT_STATUS_SUCCESFUL, +// }, +// ], +// +// expectedApps: [ +// { +// application: 'app1', +// environment: 'env1', +// version: 1, +// rolloutStatus: RolloutStatus.ROLLOUT_STATUS_SUCCESFUL, +// }, +// ], +// }, +// { +// name: 'keep the latest entry per app and environment', +// events: [ +// { +// environment: 'env1', +// application: 'app1', +// version: 1, +// rolloutStatus: RolloutStatus.ROLLOUT_STATUS_SUCCESFUL, +// }, +// { +// environment: 'env1', +// application: 'app1', +// version: 2, +// rolloutStatus: RolloutStatus.ROLLOUT_STATUS_SUCCESFUL, +// }, +// ], +// +// expectedApps: [ +// { +// application: 'app1', +// environment: 'env1', +// version: 2, +// rolloutStatus: RolloutStatus.ROLLOUT_STATUS_SUCCESFUL, +// }, +// ], +// }, +// { +// name: 'flushes the state', +// events: [ +// { +// environment: 'env1', +// application: 'app1', +// version: 1, +// rolloutStatus: RolloutStatus.ROLLOUT_STATUS_SUCCESFUL, +// }, +// { error: true }, +// ], +// +// expectedApps: [ +// { +// application: 'app1', +// environment: 'env1', +// version: 0, +// rolloutStatus: undefined, +// }, +// ], +// }, +// ]; +// +// describe.each(testdata)('with', (testcase) => { +// it(testcase.name, () => { +// FlushRolloutStatus(); +// testcase.events.forEach((ev) => { +// if ('error' in ev) { +// FlushRolloutStatus(); +// } else { +// UpdateRolloutStatus(ev); +// } +// }); +// testcase.expectedApps.forEach((app) => { +// const rollout = renderHook(() => +// useRolloutStatus((getter) => getter.getAppStatus(app.application, app.version, app.environment)) +// ); +// expect(rollout.result.current).toEqual(app.rolloutStatus); +// }); +// }); +// }); +// }); +// +// describe('Test addAction duplicate detection', () => { +// type TestDataStore = { +// name: string; +// firstAction: BatchAction; +// differentAction: BatchAction; +// }; +// +// const testdata: TestDataStore[] = [ +// { +// name: 'create environment lock', +// firstAction: { +// action: { +// $case: 'createEnvironmentLock', +// createEnvironmentLock: { +// environment: 'dev', +// lockId: 'foo', +// message: 'do it', +// ciLink: '', +// }, +// }, +// }, +// differentAction: { +// action: { +// $case: 'createEnvironmentLock', +// createEnvironmentLock: { +// environment: 'staging', +// lockId: 'foo', +// message: 'do it', +// ciLink: '', +// }, +// }, +// }, +// }, +// { +// name: 'delete environment lock', +// firstAction: { +// action: { +// $case: 'deleteEnvironmentLock', +// deleteEnvironmentLock: { +// environment: 'dev', +// lockId: 'foo', +// }, +// }, +// }, +// differentAction: { +// action: { +// $case: 'deleteEnvironmentLock', +// deleteEnvironmentLock: { +// environment: 'staging', +// lockId: 'foo', +// }, +// }, +// }, +// }, +// { +// name: 'create app lock', +// firstAction: { +// action: { +// $case: 'createEnvironmentApplicationLock', +// createEnvironmentApplicationLock: { +// environment: 'dev', +// application: 'app1', +// lockId: 'foo', +// message: 'do it', +// ciLink: '', +// }, +// }, +// }, +// differentAction: { +// action: { +// $case: 'createEnvironmentApplicationLock', +// createEnvironmentApplicationLock: { +// environment: 'dev', +// application: 'app2', +// lockId: 'foo', +// message: 'do it', +// ciLink: '', +// }, +// }, +// }, +// }, +// { +// name: 'delete app lock', +// firstAction: { +// action: { +// $case: 'deleteEnvironmentApplicationLock', +// deleteEnvironmentApplicationLock: { +// environment: 'dev', +// application: 'app1', +// lockId: 'foo', +// }, +// }, +// }, +// differentAction: { +// action: { +// $case: 'deleteEnvironmentApplicationLock', +// deleteEnvironmentApplicationLock: { +// environment: 'dev', +// application: 'app2', +// lockId: 'foo', +// }, +// }, +// }, +// }, +// { +// name: 'create team lock', +// firstAction: { +// action: { +// $case: 'createEnvironmentTeamLock', +// createEnvironmentTeamLock: { +// environment: 'dev', +// team: 'team1', +// lockId: 'foo', +// message: 'do it', +// ciLink: '', +// }, +// }, +// }, +// differentAction: { +// action: { +// $case: 'createEnvironmentTeamLock', +// createEnvironmentTeamLock: { +// environment: 'dev', +// team: 'team2', +// lockId: 'foo', +// message: 'do it', +// ciLink: '', +// }, +// }, +// }, +// }, +// { +// name: 'delete team lock', +// firstAction: { +// action: { +// $case: 'deleteEnvironmentTeamLock', +// deleteEnvironmentTeamLock: { +// environment: 'dev', +// team: 'team1', +// lockId: 'foo', +// }, +// }, +// }, +// differentAction: { +// action: { +// $case: 'deleteEnvironmentTeamLock', +// deleteEnvironmentTeamLock: { +// environment: 'dev', +// team: 'team2', +// lockId: 'foo', +// }, +// }, +// }, +// }, +// { +// name: 'deploy', +// firstAction: { +// action: { +// $case: 'deploy', +// deploy: { +// environment: 'dev', +// application: 'app1', +// version: 1, +// ignoreAllLocks: false, +// lockBehavior: LockBehavior.IGNORE, +// }, +// }, +// }, +// differentAction: { +// action: { +// $case: 'deploy', +// deploy: { +// environment: 'dev', +// application: 'app2', +// version: 1, +// ignoreAllLocks: false, +// lockBehavior: LockBehavior.IGNORE, +// }, +// }, +// }, +// }, +// { +// name: 'undeploy', +// firstAction: { +// action: { +// $case: 'undeploy', +// undeploy: { +// application: 'app1', +// }, +// }, +// }, +// differentAction: { +// action: { +// $case: 'undeploy', +// undeploy: { +// application: 'app2', +// }, +// }, +// }, +// }, +// { +// name: 'prepare undeploy', +// firstAction: { +// action: { +// $case: 'prepareUndeploy', +// prepareUndeploy: { +// application: 'app1', +// }, +// }, +// }, +// differentAction: { +// action: { +// $case: 'prepareUndeploy', +// prepareUndeploy: { +// application: 'app2', +// }, +// }, +// }, +// }, +// ]; +// +// describe.each(testdata)('with', (testcase) => { +// it(testcase.name, () => { +// // given +// updateActions([]); +// UpdateSnackbar.set({ show: false, status: SnackbarStatus.SUCCESS, content: '' }); +// +// expect(UpdateSnackbar.get().show).toStrictEqual(false); +// // when +// addAction(testcase.firstAction); +// expect(UpdateSnackbar.get().show).toStrictEqual(false); +// // then +// expect(UpdateAction.get().actions.length).toStrictEqual(1); +// +// // when +// addAction(testcase.firstAction); +// // then +// expect(UpdateAction.get().actions.length).toStrictEqual(1); +// //and +// expect(UpdateSnackbar.get().show).toStrictEqual(true); +// +// // when +// addAction(testcase.differentAction); +// // then +// expect(UpdateAction.get().actions.length).toStrictEqual(2); +// // when +// addAction(testcase.differentAction); +// // then +// expect(UpdateAction.get().actions.length).toStrictEqual(2); +// }); +// }); +// }); +// +// describe('Test maxActions', () => { +// type TestDataStore = { +// name: string; +// inputActionsLen: number; +// expectedLen: number; +// expectedShowError: boolean; +// }; +// +// const testdata: TestDataStore[] = [ +// { +// name: 'below limit', +// inputActionsLen: 99, +// expectedLen: 99, +// expectedShowError: false, +// }, +// { +// name: 'at limit', +// inputActionsLen: 100, +// expectedLen: 100, +// expectedShowError: false, +// }, +// { +// name: 'over limit', +// inputActionsLen: 101, +// expectedLen: 100, +// expectedShowError: true, +// }, +// ]; +// +// describe.each(testdata)('with', (testcase) => { +// it(testcase.name, () => { +// // given +// updateActions([]); +// //and +// UpdateSnackbar.set({ show: false, status: SnackbarStatus.SUCCESS, content: '' }); +// // when +// for (let i = 0; i < testcase.inputActionsLen; i++) { +// appendAction([ +// { +// action: { +// $case: 'deploy', +// deploy: { +// environment: 'foo', +// application: 'bread' + i, +// version: i, +// ignoreAllLocks: false, +// lockBehavior: LockBehavior.IGNORE, +// }, +// }, +// }, +// ]); +// } +// +// // then +// expect(UpdateSnackbar.get().show).toStrictEqual(testcase.expectedShowError); +// expect(UpdateAction.get().actions.length).toStrictEqual(testcase.expectedLen); +// }); +// }); +// }); +// +// describe('Test useLocksConflictingWithActions', () => { +// type TestDataStore = { +// name: string; +// actions: BatchAction[]; +// expectedAppLocks: DisplayLock[]; +// expectedEnvLocks: DisplayLock[]; +// environments: Environment[]; +// }; +// +// const testdata: TestDataStore[] = [ +// { +// name: 'empty actions empty locks', +// actions: [], +// expectedAppLocks: [], +// expectedEnvLocks: [], +// environments: [], +// }, +// { +// name: 'deploy action and related app lock and env lock', +// actions: [ +// { +// action: { +// $case: 'deploy', +// deploy: { +// environment: 'dev', +// application: 'app1', +// version: 1, +// ignoreAllLocks: false, +// lockBehavior: LockBehavior.IGNORE, +// }, +// }, +// }, +// ], +// environments: [ +// { +// name: 'dev', +// locks: { +// 'lock-env-dev': makeLock({ +// message: 'locked because christmas', +// lockId: 'my-env-lock1', +// }), +// }, +// applications: { +// echo: { +// name: 'app1', +// version: 0, +// locks: { +// applock: makeLock({ +// lockId: 'app-lock-id', +// message: 'i do not like this app', +// }), +// }, +// queuedVersion: 0, +// undeployVersion: false, +// teamLocks: {}, +// team: 'test-team', +// }, +// }, +// distanceToUpstream: 0, +// priority: 0, +// }, +// ], +// expectedAppLocks: [ +// makeDisplayLock({ +// lockId: 'app-lock-id', +// application: 'app1', +// message: 'i do not like this app', +// environment: 'dev', +// }), +// ], +// expectedEnvLocks: [ +// makeDisplayLock({ +// lockId: 'my-env-lock1', +// environment: 'dev', +// message: 'locked because christmas', +// }), +// ], +// }, +// { +// name: 'deploy action and unrelated locks', +// actions: [ +// { +// action: { +// $case: 'deploy', +// deploy: { +// environment: 'dev', +// application: 'app1', +// version: 1, +// ignoreAllLocks: false, +// lockBehavior: LockBehavior.IGNORE, +// }, +// }, +// }, +// ], +// environments: [ +// { +// name: 'staging', // this lock differs by stage +// locks: { +// 'lock-env-dev': makeLock({ +// message: 'locked because christmas', +// lockId: 'my-env-lock1', +// }), +// }, +// applications: { +// echo: { +// name: 'anotherapp', // this lock differs by app +// version: 0, +// locks: { +// applock: makeLock({ +// lockId: 'app-lock-id', +// message: 'i do not like this app', +// }), +// }, +// teamLocks: {}, +// team: 'test-team', +// queuedVersion: 0, +// undeployVersion: false, +// }, +// }, +// distanceToUpstream: 0, +// priority: 0, +// }, +// ], +// expectedAppLocks: [], +// expectedEnvLocks: [], +// }, +// ]; +// +// describe.each(testdata)('with', (testcase) => { +// it(testcase.name, () => { +// // given +// updateActions(testcase.actions); +// UpdateOverview.set({ +// applications: {}, +// environmentGroups: [ +// { +// environmentGroupName: 'g1', +// environments: testcase.environments, +// distanceToUpstream: 0, +// priority: Priority.UNRECOGNIZED, +// }, +// ], +// }); +// +// // when +// const actualLocks = renderHook(() => useLocksConflictingWithActions()).result.current; +// // then +// expect(actualLocks.environmentLocks).toStrictEqual(testcase.expectedEnvLocks); +// expect(actualLocks.appLocks).toStrictEqual(testcase.expectedAppLocks); +// }); +// }); +// }); +// +// describe('Test addAction blocking release train additions', () => { +// type TestDataStore = { +// name: string; +// firstAction: BatchAction; +// differentAction: BatchAction; +// expectedActions: number; +// }; +// +// const testdata: TestDataStore[] = [ +// { +// name: 'deploy 2 in a row', +// expectedActions: 2, +// firstAction: { +// action: { +// $case: 'deploy', +// deploy: { +// environment: 'dev', +// application: 'app1', +// version: 1, +// ignoreAllLocks: false, +// lockBehavior: LockBehavior.IGNORE, +// }, +// }, +// }, +// differentAction: { +// action: { +// $case: 'deploy', +// deploy: { +// environment: 'dev', +// application: 'app2', +// version: 1, +// ignoreAllLocks: false, +// lockBehavior: LockBehavior.IGNORE, +// }, +// }, +// }, +// }, +// { +// name: 'can not add release train after deploy action', +// expectedActions: 1, +// firstAction: { +// action: { +// $case: 'deploy', +// deploy: { +// environment: 'dev', +// application: 'app1', +// version: 1, +// ignoreAllLocks: false, +// lockBehavior: LockBehavior.IGNORE, +// }, +// }, +// }, +// differentAction: { +// action: { +// $case: 'releaseTrain', +// releaseTrain: { +// target: 'dev', +// team: '', +// commitHash: '', +// ciLink: '', +// targetType: ReleaseTrainRequest_TargetType.UNKNOWN, +// }, +// }, +// }, +// }, +// { +// name: 'can not add release train after release train', +// expectedActions: 1, +// firstAction: { +// action: { +// $case: 'releaseTrain', +// releaseTrain: { +// target: 'dev', +// team: '', +// commitHash: '', +// ciLink: '', +// targetType: ReleaseTrainRequest_TargetType.UNKNOWN, +// }, +// }, +// }, +// differentAction: { +// action: { +// $case: 'releaseTrain', +// releaseTrain: { +// target: 'stagin', +// team: '', +// commitHash: '', +// ciLink: '', +// targetType: ReleaseTrainRequest_TargetType.UNKNOWN, +// }, +// }, +// }, +// }, +// { +// name: 'can not add deploy action after release train', +// expectedActions: 1, +// firstAction: { +// action: { +// $case: 'releaseTrain', +// releaseTrain: { +// target: 'dev', +// team: '', +// commitHash: '', +// ciLink: '', +// targetType: ReleaseTrainRequest_TargetType.UNKNOWN, +// }, +// }, +// }, +// differentAction: { +// action: { +// $case: 'deploy', +// deploy: { +// environment: 'dev', +// application: 'app1', +// version: 1, +// ignoreAllLocks: false, +// lockBehavior: LockBehavior.IGNORE, +// }, +// }, +// }, +// }, +// ]; +// +// describe.each(testdata)('with', (testcase) => { +// it(testcase.name, () => { +// // given +// updateActions([]); +// +// // when +// addAction(testcase.firstAction); +// // then +// expect(UpdateAction.get().actions.length).toStrictEqual(1); +// +// // when +// addAction(testcase.differentAction); +// // then +// expect(UpdateAction.get().actions.length).toStrictEqual(testcase.expectedActions); +// }); +// }); +// }); +// +// describe('Test Calculate Release Difference', () => { +// type TestDataStore = { +// name: string; +// inputOverview: GetOverviewResponse; +// inputVersion: number; +// expectedDifference: number; +// }; +// +// const appName = 'testApp'; +// const envName = 'testEnv'; +// +// const testdata: TestDataStore[] = [ +// { +// name: 'Simple diff calculation', +// inputOverview: { +// applications: { +// [appName]: { +// name: appName, +// releases: [ +// { +// version: 10, +// sourceCommitId: '', +// sourceAuthor: '', +// sourceMessage: '', +// undeployVersion: false, +// prNumber: '', +// displayVersion: '', +// isMinor: false, +// isPrepublish: false, +// }, +// { +// version: 12, +// sourceCommitId: '', +// sourceAuthor: '', +// sourceMessage: '', +// undeployVersion: false, +// prNumber: '', +// displayVersion: '', +// isMinor: false, +// isPrepublish: false, +// }, +// { +// version: 15, +// sourceCommitId: '', +// sourceAuthor: '', +// sourceMessage: '', +// undeployVersion: false, +// prNumber: '', +// displayVersion: '', +// isMinor: false, +// isPrepublish: false, +// }, +// ], +// undeploySummary: UndeploySummary.NORMAL, +// sourceRepoUrl: '', +// team: '', +// warnings: [], +// }, +// }, +// environmentGroups: [ +// { +// environmentGroupName: 'test', +// environments: [ +// { +// name: envName, +// locks: {}, +// applications: { +// [appName]: { +// name: appName, +// version: 10, +// locks: {}, +// queuedVersion: 0, +// undeployVersion: false, +// teamLocks: {}, +// team: '', +// }, +// }, +// distanceToUpstream: 0, +// priority: Priority.PROD, +// }, +// ], +// distanceToUpstream: 0, +// priority: Priority.PROD, +// }, +// ], +// gitRevision: '', +// branch: '', +// lightweightApps: [ +// { +// Name: 'test', +// Team: 'test', +// }, +// ], +// manifestRepoUrl: '', +// }, +// inputVersion: 15, +// expectedDifference: 2, +// }, +// { +// name: 'negative diff', +// inputOverview: { +// applications: { +// [appName]: { +// name: appName, +// releases: [ +// { +// version: 10, +// sourceCommitId: '', +// sourceAuthor: '', +// sourceMessage: '', +// undeployVersion: false, +// prNumber: '', +// displayVersion: '', +// isMinor: false, +// isPrepublish: false, +// }, +// { +// version: 12, +// sourceCommitId: '', +// sourceAuthor: '', +// sourceMessage: '', +// undeployVersion: false, +// prNumber: '', +// displayVersion: '', +// isMinor: false, +// isPrepublish: false, +// }, +// ], +// undeploySummary: UndeploySummary.NORMAL, +// sourceRepoUrl: '', +// team: '', +// warnings: [], +// }, +// }, +// environmentGroups: [ +// { +// environmentGroupName: 'test', +// environments: [ +// { +// name: envName, +// locks: {}, +// applications: { +// [appName]: { +// name: appName, +// version: 12, +// locks: {}, +// queuedVersion: 0, +// undeployVersion: false, +// teamLocks: {}, +// team: '', +// }, +// }, +// distanceToUpstream: 0, +// priority: Priority.PROD, +// }, +// ], +// distanceToUpstream: 0, +// priority: Priority.PROD, +// }, +// ], +// gitRevision: '', +// branch: '', +// lightweightApps: [ +// { +// Name: 'test', +// Team: 'test', +// }, +// ], +// manifestRepoUrl: '', +// }, +// inputVersion: 10, +// expectedDifference: -1, +// }, +// { +// name: 'the input version does not exist', +// inputOverview: { +// applications: { +// [appName]: { +// name: appName, +// releases: [ +// { +// version: 10, +// sourceCommitId: '', +// sourceAuthor: '', +// sourceMessage: '', +// undeployVersion: false, +// prNumber: '', +// displayVersion: '', +// isMinor: false, +// isPrepublish: false, +// }, +// { +// version: 12, +// sourceCommitId: '', +// sourceAuthor: '', +// sourceMessage: '', +// undeployVersion: false, +// prNumber: '', +// displayVersion: '', +// isMinor: false, +// isPrepublish: false, +// }, +// ], +// undeploySummary: UndeploySummary.NORMAL, +// sourceRepoUrl: '', +// team: '', +// warnings: [], +// }, +// }, +// environmentGroups: [ +// { +// environmentGroupName: 'test', +// environments: [ +// { +// name: envName, +// locks: {}, +// applications: { +// [appName]: { +// name: appName, +// version: 12, +// locks: {}, +// queuedVersion: 0, +// undeployVersion: false, +// teamLocks: {}, +// team: '', +// }, +// }, +// distanceToUpstream: 0, +// priority: Priority.PROD, +// }, +// ], +// distanceToUpstream: 0, +// priority: Priority.PROD, +// }, +// ], +// gitRevision: '', +// branch: '', +// manifestRepoUrl: '', +// lightweightApps: [ +// { +// Name: 'test', +// Team: 'test', +// }, +// ], +// }, +// inputVersion: 11, +// expectedDifference: 0, +// }, +// { +// name: 'app does not exist in the applications', +// inputOverview: { +// applications: { +// exampleApp: { +// name: appName, +// releases: [ +// { +// version: 10, +// sourceCommitId: '', +// sourceAuthor: '', +// sourceMessage: '', +// undeployVersion: false, +// prNumber: '', +// displayVersion: '', +// isMinor: false, +// isPrepublish: false, +// }, +// { +// version: 12, +// sourceCommitId: '', +// sourceAuthor: '', +// sourceMessage: '', +// undeployVersion: false, +// prNumber: '', +// displayVersion: '', +// isMinor: false, +// isPrepublish: false, +// }, +// ], +// undeploySummary: UndeploySummary.NORMAL, +// sourceRepoUrl: '', +// team: '', +// warnings: [], +// }, +// }, +// environmentGroups: [ +// { +// environmentGroupName: 'test', +// environments: [ +// { +// name: envName, +// locks: {}, +// applications: { +// [appName]: { +// name: appName, +// version: 12, +// locks: {}, +// queuedVersion: 0, +// undeployVersion: false, +// teamLocks: {}, +// team: '', +// }, +// }, +// distanceToUpstream: 0, +// priority: Priority.PROD, +// }, +// ], +// distanceToUpstream: 0, +// priority: Priority.PROD, +// }, +// ], +// gitRevision: '', +// branch: '', +// manifestRepoUrl: '', +// lightweightApps: [ +// { +// Name: 'test', +// Team: 'test', +// }, +// ], +// }, +// inputVersion: 10, +// expectedDifference: 0, +// }, +// { +// name: 'app does not exist in the environment applications', +// inputOverview: { +// applications: { +// [appName]: { +// name: appName, +// releases: [ +// { +// version: 10, +// sourceCommitId: '', +// sourceAuthor: '', +// sourceMessage: '', +// undeployVersion: false, +// prNumber: '', +// displayVersion: '', +// isMinor: false, +// isPrepublish: false, +// }, +// { +// version: 12, +// sourceCommitId: '', +// sourceAuthor: '', +// sourceMessage: '', +// undeployVersion: false, +// prNumber: '', +// displayVersion: '', +// isMinor: false, +// isPrepublish: false, +// }, +// ], +// undeploySummary: UndeploySummary.NORMAL, +// sourceRepoUrl: '', +// team: '', +// warnings: [], +// }, +// }, +// environmentGroups: [ +// { +// environmentGroupName: 'test', +// environments: [ +// { +// name: envName, +// locks: {}, +// applications: { +// exampleApp: { +// name: appName, +// version: 12, +// locks: {}, +// queuedVersion: 0, +// undeployVersion: false, +// teamLocks: {}, +// team: '', +// }, +// }, +// distanceToUpstream: 0, +// priority: Priority.PROD, +// }, +// ], +// distanceToUpstream: 0, +// priority: Priority.PROD, +// }, +// ], +// gitRevision: '', +// branch: '', +// manifestRepoUrl: '', +// lightweightApps: [ +// { +// Name: 'test', +// Team: 'test', +// }, +// ], +// }, +// inputVersion: 10, +// expectedDifference: 0, +// }, +// { +// name: 'environment does not exist in the envs', +// inputOverview: { +// applications: { +// [appName]: { +// name: appName, +// releases: [ +// { +// version: 10, +// sourceCommitId: '', +// sourceAuthor: '', +// sourceMessage: '', +// undeployVersion: false, +// prNumber: '', +// displayVersion: '', +// isMinor: false, +// isPrepublish: false, +// }, +// { +// version: 12, +// sourceCommitId: '', +// sourceAuthor: '', +// sourceMessage: '', +// undeployVersion: false, +// prNumber: '', +// displayVersion: '', +// isMinor: false, +// isPrepublish: false, +// }, +// ], +// undeploySummary: UndeploySummary.NORMAL, +// sourceRepoUrl: '', +// team: '', +// warnings: [], +// }, +// }, +// environmentGroups: [ +// { +// environmentGroupName: 'test', +// environments: [ +// { +// name: 'exampleEnv', +// locks: {}, +// applications: { +// exampleApp: { +// name: appName, +// version: 12, +// locks: {}, +// queuedVersion: 0, +// undeployVersion: false, +// teamLocks: {}, +// team: '', +// }, +// }, +// distanceToUpstream: 0, +// priority: Priority.PROD, +// }, +// ], +// distanceToUpstream: 0, +// priority: Priority.PROD, +// }, +// ], +// gitRevision: '', +// branch: '', +// lightweightApps: [ +// { +// Name: 'test', +// Team: 'test', +// }, +// ], +// manifestRepoUrl: '', +// }, +// inputVersion: 10, +// expectedDifference: 0, +// }, +// ]; +// describe.each(testdata)('with', (testcase) => { +// it(testcase.name, () => { +// updateActions([]); +// UpdateOverview.set(testcase.inputOverview); +// +// const calculatedDiff = renderHook(() => useReleaseDifference(testcase.inputVersion, appName, envName)) +// .result.current; +// expect(calculatedDiff).toStrictEqual(testcase.expectedDifference); +// }); +// }); +// }); diff --git a/services/frontend-service/src/ui/utils/store.tsx b/services/frontend-service/src/ui/utils/store.tsx index fecde0bbe..7023a4af0 100644 --- a/services/frontend-service/src/ui/utils/store.tsx +++ b/services/frontend-service/src/ui/utils/store.tsx @@ -15,7 +15,6 @@ along with kuberpult. If not, see Copyright freiheit.com*/ import { createStore } from 'react-use-sub'; import { - Application, BatchAction, BatchRequest, Environment, @@ -450,9 +449,12 @@ export const useReleaseDialogParams = (): { app: string | null; version: number const [params] = useSearchParams(); const app = params.get('dialog-app') ?? ''; const version = +(params.get('dialog-version') ?? ''); - const valid = useOverview(({ applications }) => - applications[app] ? !!applications[app].releases.find((r) => r.version === version) : false - ); + + const appDetails = useAppDetailsForApp(app); + if (!appDetails) { + return { app: null, version: null }; + } + const valid = !!appDetails.application?.releases.find((r) => r.version === version); return valid ? { app, version } : { app: null, version: null }; }; @@ -470,21 +472,21 @@ export const deleteAction = (action: BatchAction): void => { // doesn't return empty team names (i.e.: '') // doesn't return repeated team names export const useTeamNames = (): string[] => - useOverview(({ applications }) => [ + useOverview(({ lightweightApps }) => [ ...new Set( - Object.values(applications) - .map((app: Application) => app.team.trim() || '') + Object.values(lightweightApps) + .map((app: OverviewApplication) => app.Team.trim() || '') .sort((a, b) => a.localeCompare(b)) ), ]); -export const useApplications = (): { [p: string]: Application } => useOverview(({ applications }) => applications); +export const useApplications = (): OverviewApplication[] => useOverview(({ lightweightApps }) => lightweightApps); export const useTeamFromApplication = (app: string): string | undefined => useOverview(({ lightweightApps }) => lightweightApps.find((data) => data.Name === app)?.Name); // returns warnings from all apps -export const useAllWarnings = (): Warning[] => - useOverview(({ applications }) => Object.values(applications).flatMap((app) => app.warnings)); +export const useAllWarnings = (): Warning[] => []; +// useOverview(({ applications }) => Object.values(applications).flatMap((app) => app.warnings)); // return warnings from all apps matching the given filtering criteria export const useShownWarnings = (teams: string[], nameIncludes: string): Warning[] => @@ -537,6 +539,35 @@ export const useTeamLocks = (): DisplayLock[] => export const getPriorityClassName = (envOrGroup: Environment | EnvironmentGroup): string => 'environment-priority-' + String(Priority[envOrGroup?.priority ?? Priority.UNRECOGNIZED]).toLowerCase(); +export const useNewTeamLocks = (app: string, team: string): DisplayLock[] => { + const teamLocks = useAppDetailsForApp(app).teamLocks; + return Object.values(useEnvironments()) + .map((env) => + teamLocks[env.name].locks + .map((currentTeamLock) => + Object.values(currentTeamLock).map((lock) => ({ + date: lock.createdAt, + environment: env.name, + team: team, + lockId: lock.lockId, + message: lock.message, + authorName: lock.createdBy?.name, + authorEmail: lock.createdBy?.email, + })) + ) + .flat() + ) + .flat() + .filter( + (value: DisplayLock, index: number, self: DisplayLock[]) => + index === + self.findIndex( + (t: DisplayLock) => + t.lockId === value.lockId && t.team === value.team && t.environment === value.environment + ) + ); +}; + // filter for apps included in the selected teams const applicationsMatchingTeam = (applications: OverviewApplication[], teams: string[]): OverviewApplication[] => applications.filter((app) => teams.length === 0 || teams.includes(app.Team.trim() || '')); @@ -675,7 +706,7 @@ export const useLocksConflictingWithActions = (): AllLocks => { if (action.action?.$case === 'deploy') { const app = action.action.deploy.application; const env = action.action.deploy.environment; - const appTeam = appMap[app].team; + const appTeam = appMap.find((curr) => curr.Name === app)?.Team; if (teamLock.environment === env && teamLock.team === appTeam) { // found a team lock that matches return true; @@ -960,7 +991,7 @@ export const sortLocks = (displayLocks: DisplayLock[], sorting: 'oldestToNewest' // returns the release number {$version} of {$application} export const useRelease = (application: string, version: number): Release | undefined => - useOverview(({ applications }) => applications[application]?.releases?.find((r) => r.version === version)); + useAppDetailsForApp(application).application?.releases.find((r) => r.version === version); export const useReleaseOrLog = (application: string, version: number): Release | undefined => { const release = useRelease(application, version); @@ -973,15 +1004,10 @@ export const useReleaseOrLog = (application: string, version: number): Release | }; export const useReleaseOptional = (application: string, env: Environment): Release | undefined => { - const x = env.applications[application]; - return useOverview(({ applications }) => { - const version = x ? x.version : 0; - const res = applications[application].releases.find((r) => r.version === version); - if (!x) { - return undefined; - } - return res; - }); + const appDetails = useAppDetailsForApp(application); + const deployment = appDetails.deployments[env.name]; + if (!deployment) return undefined; + return appDetails.application?.releases.find((r) => r.version === deployment.version); }; // returns the release versions that are currently deployed to at least one environment @@ -1053,11 +1079,17 @@ export const useCurrentlyExistsAtGroup = (application: string): EnvironmentGroup }; // Get all releases for an app -export const useReleasesForApp = (app: string): Release[] => - useOverview(({ applications }) => applications[app]?.releases?.sort((a, b) => b.version - a.version)); +export const useReleasesForApp = (app: string): Release[] => { + const appDetails = useAppDetailsForApp(app); + if (!appDetails.application?.releases) { + return []; + } else { + return appDetails.application?.releases; + } +}; -// Get all release versions for an app -export const useVersionsForApp = (app: string): number[] => useReleasesForApp(app).map((rel) => rel.version); +// // Get all release versions for an app +// export const useVersionsForApp = (app: string): number[] => useReleasesForApp(app).map((rel) => rel.version); // Calculated release difference between a specific release and currently deployed release on a specific environment export const useReleaseDifference = (toDeployVersion: number, application: string, environment: string): number => { @@ -1077,10 +1109,12 @@ export const useReleaseDifference = (toDeployVersion: number, application: strin return currentDeployedIndex - newVersionIndex; }; // Get all minor releases for an app -export const useMinorsForApp = (app: string): number[] => - useReleasesForApp(app) - .filter((rel) => rel.isMinor) +export const useMinorsForApp = (app: string): number[] | undefined => + useAppDetailsForApp(app) + .application?.releases.filter((rel) => rel.isMinor) .map((rel) => rel.version); +// .application?.releases.filter((rel) => rel.isMinor) +// .map((rel) => rel.version); // Navigate while keeping search params, returns new navigation url, and a callback function to navigate export const useNavigateWithSearchParams = (to: string): { navURL: string; navCallback: () => void } => {