From 21e1a34acc8fbeb7163e6bb1582105eb92bf55f6 Mon Sep 17 00:00:00 2001 From: Rachelle Rathbone Date: Thu, 23 Nov 2023 09:23:14 +1100 Subject: [PATCH 1/8] wip --- app/jenkins-for-jira-ui/src/api/getAllJenkinsServers.ts | 2 +- app/src/storage/get-all-jenkins-servers.ts | 1 + app/src/webtrigger/handle-jenkins-request.ts | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/jenkins-for-jira-ui/src/api/getAllJenkinsServers.ts b/app/jenkins-for-jira-ui/src/api/getAllJenkinsServers.ts index 23c03a75..681046d4 100644 --- a/app/jenkins-for-jira-ui/src/api/getAllJenkinsServers.ts +++ b/app/jenkins-for-jira-ui/src/api/getAllJenkinsServers.ts @@ -55,7 +55,7 @@ const sendJenkinsServersAnalytics = async (jenkinsServers: JenkinsServer[]): Pro const getAllJenkinsServers = async (): Promise => { try { const jenkinsServers = await invoke('getAllJenkinsServers') as JenkinsServer[]; - + console.log('my servers: ', jenkinsServers); if (jenkinsServers.length) { sendJenkinsServersAnalytics(jenkinsServers); await analyticsClient.sendAnalytics( diff --git a/app/src/storage/get-all-jenkins-servers.ts b/app/src/storage/get-all-jenkins-servers.ts index fc2c4a88..0eb53f3b 100644 --- a/app/src/storage/get-all-jenkins-servers.ts +++ b/app/src/storage/get-all-jenkins-servers.ts @@ -13,6 +13,7 @@ async function getAllJenkinsServers(): Promise { let results: Result[] = []; let response = await fetchInitialResult(); + logger.info('response: ', response); results = response.results; while (response.nextCursor) { diff --git a/app/src/webtrigger/handle-jenkins-request.ts b/app/src/webtrigger/handle-jenkins-request.ts index 80b9ad9f..17fd1b5c 100644 --- a/app/src/webtrigger/handle-jenkins-request.ts +++ b/app/src/webtrigger/handle-jenkins-request.ts @@ -51,6 +51,8 @@ export default async function handleJenkinsRequest( let response; + logger.info('jenkinsRequest: ', jenkinsRequest); + switch (jenkinsRequest.requestType) { case RequestType.EVENT: { response = await handleEvent(jenkinsRequest as JenkinsEvent, jenkinsServerUuid, cloudId, logger); From 252bb40ae2f1bef147b0b715bfc285a0a64247df Mon Sep 17 00:00:00 2001 From: Rachelle Rathbone Date: Thu, 23 Nov 2023 14:56:36 +1100 Subject: [PATCH 2/8] wip - consuming data and adding tests --- .../src/api/getAllJenkinsServers.ts | 2 +- .../ConnectionPanel.styles.tsx | 2 +- .../ConnectionPanel/ConnectionPanel.tests.tsx | 107 ++++++++++++++++++ .../ConnectionPanel/ConnectionPanel.tsx | 55 ++++++--- .../ConnectionPanel/ConnectionPanelMain.tsx | 5 +- .../ConnectionPanel/ConnectionPanelTop.tsx | 7 +- .../ConnectionPanel/NotConnectedState.tsx | 3 +- .../components/ConnectionPanel/SetUpGuide.tsx | 13 ++- 8 files changed, 165 insertions(+), 29 deletions(-) diff --git a/app/jenkins-for-jira-ui/src/api/getAllJenkinsServers.ts b/app/jenkins-for-jira-ui/src/api/getAllJenkinsServers.ts index 681046d4..23c03a75 100644 --- a/app/jenkins-for-jira-ui/src/api/getAllJenkinsServers.ts +++ b/app/jenkins-for-jira-ui/src/api/getAllJenkinsServers.ts @@ -55,7 +55,7 @@ const sendJenkinsServersAnalytics = async (jenkinsServers: JenkinsServer[]): Pro const getAllJenkinsServers = async (): Promise => { try { const jenkinsServers = await invoke('getAllJenkinsServers') as JenkinsServer[]; - console.log('my servers: ', jenkinsServers); + if (jenkinsServers.length) { sendJenkinsServersAnalytics(jenkinsServers); await analyticsClient.sendAnalytics( diff --git a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanel.styles.tsx b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanel.styles.tsx index 6e334e22..cfaa3f01 100644 --- a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanel.styles.tsx +++ b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanel.styles.tsx @@ -6,7 +6,7 @@ export const connectionPanelContainer = css` box-shadow: 0px 2px 4px 0px #091E4240; display: flex; flex-direction: column; - padding: ${token('space.300')}; + padding: ${token('space.300')} ${token('space.300')} ${token('space.0')}; margin: ${token('space.400')} auto ${token('space.400')} ${token('space.025')}; `; diff --git a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanel.tests.tsx b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanel.tests.tsx index 712cee03..da70c4e7 100644 --- a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanel.tests.tsx +++ b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanel.tests.tsx @@ -2,6 +2,113 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { ConnectionPanelTop } from './ConnectionPanelTop'; import { ConnectedState } from '../StatusLabel/StatusLabel'; +import { addConnectedState } from './ConnectionPanel'; +import { EventType, JenkinsServer } from '../../../../src/common/types'; + +const servers: JenkinsServer[] = [ + { + name: 'server one', + uuid: '56046af9-d0eb-4efb-8896-6c9d0da884fe', + pluginConfig: { + ipAddress: '10.10.10.10', + lastUpdatedOn: new Date() + }, + pipelines: [ + { + name: '#74315', + lastEventType: EventType.DEPLOYMENT, + lastEventStatus: 'successful', + lastEventDate: new Date() + }, + { + name: '#1234', + lastEventType: EventType.BUILD, + lastEventStatus: 'failed', + lastEventDate: new Date() + } + ] + }, + { + name: 'server two', + uuid: '56046af9-d0eb-4efb-8896-jsdfn8234234', + pluginConfig: { + ipAddress: '10.10.10.11', + lastUpdatedOn: new Date() + }, + pipelines: [] + }, + { + name: 'server three', + uuid: '56046af9-d0eb-4efb-8896-ehdf34bhsdf', + pluginConfig: { + ipAddress: '10.10.10.10', + lastUpdatedOn: new Date() + }, + pipelines: [] + }, + { + name: 'server four', + uuid: '56046af9-d0eb-4efb-8896-sjnd893rsd', + pluginConfig: { + ipAddress: '10.10.10.12', + lastUpdatedOn: new Date() + }, + pipelines: [ + { + name: '#3456', + lastEventType: EventType.BUILD, + lastEventStatus: 'successful', + lastEventDate: new Date() + } + ] + }, + { + name: 'server five', + uuid: '56046af9-d0eb-4efb-8896-ed182ende', + pluginConfig: undefined, + pipelines: [ + { + name: '#6789', + lastEventType: EventType.DEPLOYMENT, + lastEventStatus: 'pending', + lastEventDate: new Date() + } + ] + } +]; + +describe('addConnectedState', () => { + it('should handle a single server', () => { + const singleServer: JenkinsServer[] = [servers[0]]; + const result = addConnectedState(singleServer); + + expect(result[0].connectedState).toEqual(ConnectedState.CONNECTED); + }); + + it('should correctly set state for two servers with different IPs', () => { + const twoServers: JenkinsServer[] = [servers[0], servers[1]]; + const result = addConnectedState(twoServers); + + expect(result[0].connectedState).toEqual(ConnectedState.CONNECTED); + expect(result[1].connectedState).toEqual(ConnectedState.PENDING); + }); + + it('should correctly set state for multiple servers with duplicate IPs', () => { + const multipleServers: JenkinsServer[] = [servers[0], servers[2], servers[3]]; + const result = addConnectedState(multipleServers); + + expect(result[0].connectedState).toEqual(ConnectedState.CONNECTED); + expect(result[1].connectedState).toEqual(ConnectedState.DUPLICATE); + expect(result[2].connectedState).toEqual(ConnectedState.CONNECTED); + }); + + it('should handle servers with no pluginConfig', () => { + const noPluginConfig: JenkinsServer[] = [servers[4]]; + const result = addConnectedState(noPluginConfig); + + expect(result[0].connectedState).toEqual(ConnectedState.PENDING); + }); +}); describe('ConnectionPanelTop', () => { test('renders with the correct content and styles for CONNECTED state', () => { diff --git a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanel.tsx b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanel.tsx index 3d340f8f..5330e980 100644 --- a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanel.tsx +++ b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanel.tsx @@ -7,12 +7,28 @@ import { connectionPanelContainer } from './ConnectionPanel.styles'; import { JenkinsServer } from '../../../../src/common/types'; import { getAllJenkinsServers } from '../../api/getAllJenkinsServers'; -// TODO - add DUPLICATE state once I'm pulling in new data from backend export const addConnectedState = (servers: JenkinsServer[]): JenkinsServer[] => { - return servers.map((server: JenkinsServer) => ({ - ...server, - connectedState: server.pipelines.length === 0 ? ConnectedState.PENDING : ConnectedState.CONNECTED - })); + const ipAddressSet = new Set(); + + return servers + .slice() // Create a shallow copy to avoid mutating the original array + .sort((a, b) => b.pipelines.length - a.pipelines.length) + .map((server: JenkinsServer) => { + const ipAddress = server.pluginConfig?.ipAddress; + let connectedState = ConnectedState.PENDING; + + if (ipAddress && ipAddressSet.has(ipAddress)) { + connectedState = ConnectedState.DUPLICATE; + } else if (server.pipelines.length > 0 && ipAddress) { + connectedState = ConnectedState.CONNECTED; + ipAddressSet.add(ipAddress); + } + + return { + ...server, + connectedState + }; + }); }; const ConnectionPanel = (): JSX.Element => { @@ -31,19 +47,22 @@ const ConnectionPanel = (): JSX.Element => { return ( <> {jenkinsServers.map( - (server: JenkinsServer, index: number): JSX.Element => ( -
- - -
- ) + (server: JenkinsServer, index: number): JSX.Element => { + const ipAddress = server.pluginConfig?.ipAddress; + return ( +
+ + +
+ ); + } )} ); diff --git a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanelMain.tsx b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanelMain.tsx index ab0fb43c..c9790007 100644 --- a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanelMain.tsx +++ b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanelMain.tsx @@ -12,9 +12,8 @@ import { JenkinsServer } from '../../../../src/common/types'; import { ConnectedJenkinsServers } from './ConnectedJenkinsServers'; import { SetUpGuide } from './SetUpGuide'; -// TODO - remove ? for children and connectedState once set up guide is merged type PanelProps = { - children?: ReactNode, + children: ReactNode, connectedState?: ConnectedState, 'data-testid'?: string }; @@ -73,7 +72,7 @@ const ConnectionPanelMain = ({ connectedState, jenkinsServer }: ConnectionPanelM - + diff --git a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanelTop.tsx b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanelTop.tsx index 8e58597a..8f490eb9 100644 --- a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanelTop.tsx +++ b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanelTop.tsx @@ -14,7 +14,7 @@ import { ConnectedState, StatusLabel } from '../StatusLabel/StatusLabel'; type ConnectionPanelTopProps = { connectedState: ConnectedState, - ipAddress: string, + ipAddress?: string, name: string }; @@ -35,7 +35,10 @@ const ConnectionPanelTop = ({ connectedState, ipAddress, name }: ConnectionPanel
-

IP address: {ipAddress}

+ { + ipAddress && +

IP address: {ipAddress}

+ }
Connection settings - : + : } ); diff --git a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/SetUpGuide.tsx b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/SetUpGuide.tsx index 78a3a6c2..f40d8ad8 100644 --- a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/SetUpGuide.tsx +++ b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/SetUpGuide.tsx @@ -13,6 +13,7 @@ import { setUpGuideParagraph, setUpGuideContainer } from './ConnectionPanel.styles'; +import { JenkinsPluginConfig } from '../../../../src/common/types'; type SetUpGuideLinkProps = { onClick: (event: React.MouseEvent) => void, @@ -99,7 +100,11 @@ const SetUpGuideInstructions = ({ ); }; -const SetUpGuide = (): JSX.Element => { +type SetUpGuideProps = { + pluginConfig?: JenkinsPluginConfig +}; + +const SetUpGuide = ({ pluginConfig }: SetUpGuideProps): JSX.Element => { const [isDrawerOpen, setIsDrawerOpen] = useState(false); const [areGlobalSettingsOn, setAreGlobalSettingsOn] = useState(false); const [hasBuildFilters, setHasBuildFilters] = useState(false); @@ -107,8 +112,10 @@ const SetUpGuide = (): JSX.Element => { useEffect(() => { // TODO - update global settings based on new data received from Jenkins plugin setAreGlobalSettingsOn(false); - setHasBuildFilters(false); - }, []); + if (pluginConfig?.autoBuildEnabled && pluginConfig.autoBuildRegex) { + setHasBuildFilters(true); + } + }, [pluginConfig?.autoBuildEnabled, pluginConfig?.autoBuildRegex]); const openDrawer = () => { setIsDrawerOpen(true); From 56012840e538995af72506c8be3c091a657ebf7d Mon Sep 17 00:00:00 2001 From: Rachelle Rathbone Date: Thu, 23 Nov 2023 15:04:00 +1100 Subject: [PATCH 3/8] add additional test to confirm the correct state was applied to duplicate servers when none of them have pipelines --- .../ConnectionPanel/ConnectionPanel.tests.tsx | 27 +++++++++++++++++++ app/src/storage/get-all-jenkins-servers.ts | 1 - app/src/webtrigger/handle-jenkins-request.ts | 2 -- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanel.tests.tsx b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanel.tests.tsx index da70c4e7..1626cc4a 100644 --- a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanel.tests.tsx +++ b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/ConnectionPanel.tests.tsx @@ -74,6 +74,24 @@ const servers: JenkinsServer[] = [ lastEventDate: new Date() } ] + }, + { + name: 'server six', + uuid: '56046af9-d0eb-4efb-8896-hsdbf723rh2r', + pluginConfig: { + ipAddress: '10.10.10.10', + lastUpdatedOn: new Date() + }, + pipelines: [] + }, + { + name: 'server seven', + uuid: '56046af9-d0eb-4efb-8896-iwer23rjesu', + pluginConfig: { + ipAddress: '10.10.10.10', + lastUpdatedOn: new Date() + }, + pipelines: [] } ]; @@ -108,6 +126,15 @@ describe('addConnectedState', () => { expect(result[0].connectedState).toEqual(ConnectedState.PENDING); }); + + it('should correctly set state for multiple servers with duplicate IPs and no pipelines', () => { + const duplicateServers: JenkinsServer[] = [servers[2], servers[5], servers[6]]; + const result = addConnectedState(duplicateServers); + + expect(result[0].connectedState).toEqual(ConnectedState.PENDING); + expect(result[1].connectedState).toEqual(ConnectedState.DUPLICATE); + expect(result[2].connectedState).toEqual(ConnectedState.DUPLICATE); + }); }); describe('ConnectionPanelTop', () => { diff --git a/app/src/storage/get-all-jenkins-servers.ts b/app/src/storage/get-all-jenkins-servers.ts index 0eb53f3b..fc2c4a88 100644 --- a/app/src/storage/get-all-jenkins-servers.ts +++ b/app/src/storage/get-all-jenkins-servers.ts @@ -13,7 +13,6 @@ async function getAllJenkinsServers(): Promise { let results: Result[] = []; let response = await fetchInitialResult(); - logger.info('response: ', response); results = response.results; while (response.nextCursor) { diff --git a/app/src/webtrigger/handle-jenkins-request.ts b/app/src/webtrigger/handle-jenkins-request.ts index 17fd1b5c..80b9ad9f 100644 --- a/app/src/webtrigger/handle-jenkins-request.ts +++ b/app/src/webtrigger/handle-jenkins-request.ts @@ -51,8 +51,6 @@ export default async function handleJenkinsRequest( let response; - logger.info('jenkinsRequest: ', jenkinsRequest); - switch (jenkinsRequest.requestType) { case RequestType.EVENT: { response = await handleEvent(jenkinsRequest as JenkinsEvent, jenkinsServerUuid, cloudId, logger); From 777ebacc212220f5e4423c8e236ed76e8c14defe Mon Sep 17 00:00:00 2001 From: Rachelle Rathbone Date: Thu, 23 Nov 2023 17:51:00 +1100 Subject: [PATCH 4/8] add setup guide tests --- .../ConnectionPanel/SetUpGuide.test.tsx | 74 ++++++++++++ .../components/ConnectionPanel/SetUpGuide.tsx | 105 ++++++++++-------- 2 files changed, 130 insertions(+), 49 deletions(-) create mode 100644 app/jenkins-for-jira-ui/src/components/ConnectionPanel/SetUpGuide.test.tsx diff --git a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/SetUpGuide.test.tsx b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/SetUpGuide.test.tsx new file mode 100644 index 00000000..9ee72722 --- /dev/null +++ b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/SetUpGuide.test.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { PipelineEventType, SetUpGuideInstructions, SetUpGuideLink } from './SetUpGuide'; + +describe('SetUpGuideInstructions Component', () => { + const onClickMock = jest.fn(); + + test('renders SetUpGuideInstructions with BUILD eventType, globalSettings, and regex', () => { + const { getByText } = render( + + ); + + expect(getByText('jiraSendBuildInfo')).toBeInTheDocument(); + expect(getByText('OR')).toBeInTheDocument(); + expect(getByText('^build$')).toBeInTheDocument(); + }); + + test('renders SetUpGuideInstructions with BUILD eventType, globalSettings, and no regex', () => { + const { getByText } = render( + + ); + + expect(getByText('No setup required')).toBeInTheDocument(); + }); + + test('renders SetUpGuideInstructions with DEPLOYMENT eventType, globalSettings, and regex', () => { + const { getByText } = render( + + ); + + expect(getByText('jiraSendDeploymentInfo')).toBeInTheDocument(); + expect(getByText('OR')).toBeInTheDocument(); + expect(getByText('^deploy to (?.*)$')).toBeInTheDocument(); + }); + + test('renders SetUpGuideInstructions with DEPLOYMENT eventType, globalSettings set to false', () => { + const { getByText, queryByText } = render( + + ); + + expect(getByText('jiraSendDeploymentInfo')).toBeInTheDocument(); + expect(queryByText('OR')).toBeNull(); + }); +}); + +describe('SetUpGuideLink Component', () => { + const onClickMock = jest.fn(); + + test('renders SetUpGuideLink with label', () => { + const { getByText } = render( + + ); + + expect(getByText('build')).toBeInTheDocument(); + }); +}); diff --git a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/SetUpGuide.tsx b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/SetUpGuide.tsx index f40d8ad8..998c839d 100644 --- a/app/jenkins-for-jira-ui/src/components/ConnectionPanel/SetUpGuide.tsx +++ b/app/jenkins-for-jira-ui/src/components/ConnectionPanel/SetUpGuide.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import { cx } from '@emotion/css'; import Drawer from '@atlaskit/drawer'; import PeopleGroup from '@atlaskit/icon/glyph/people-group'; @@ -20,7 +20,7 @@ type SetUpGuideLinkProps = { label: string, }; -const SetUpGuideLink = ({ onClick, label }: SetUpGuideLinkProps): JSX.Element => { +export const SetUpGuideLink = ({ onClick, label }: SetUpGuideLinkProps): JSX.Element => { return (