diff options
author | Wouter Admiraal <wouter.admiraal@sonarsource.com> | 2019-03-06 15:49:52 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2019-03-29 09:44:57 +0100 |
commit | 2c28c4471b04811c5deb30688ad57561b2e91ae5 (patch) | |
tree | fdbfaddc4c20dfc0f703a61dfc3eb25bdf10f9bd /server/sonar-web/src/main/js | |
parent | 687ced1be70bf111c4c5617ca8d224af3f511441 (diff) | |
download | sonarqube-2c28c4471b04811c5deb30688ad57561b2e91ae5.tar.gz sonarqube-2c28c4471b04811c5deb30688ad57561b2e91ae5.zip |
SONAR-10994 Add new branch store
Diffstat (limited to 'server/sonar-web/src/main/js')
7 files changed, 255 insertions, 4 deletions
diff --git a/server/sonar-web/src/main/js/app/types.d.ts b/server/sonar-web/src/main/js/app/types.d.ts index 16d74f126c0..340ebfa96c6 100644 --- a/server/sonar-web/src/main/js/app/types.d.ts +++ b/server/sonar-web/src/main/js/app/types.d.ts @@ -108,7 +108,7 @@ declare namespace T { analysisDate?: string; isMain: boolean; name: string; - status?: { qualityGateStatus: string }; + status?: { qualityGateStatus: Status }; } export type BranchLike = Branch | PullRequest; @@ -624,7 +624,7 @@ declare namespace T { branch: string; key: string; isOrphan?: true; - status?: { qualityGateStatus: string }; + status?: { qualityGateStatus: Status }; title: string; url?: string; } @@ -646,7 +646,7 @@ declare namespace T { } export interface QualityGateProjectStatusCondition { - status: 'ERROR' | 'OK'; + status: Status; metricKey: string; comparator: string; periodIndex: number; @@ -658,7 +658,7 @@ declare namespace T { projectStatus: { conditions?: QualityGateProjectStatusCondition[]; ignoredConditions: boolean; - status: string; + status: Status; }; } @@ -736,6 +736,8 @@ declare namespace T { export type RuleType = 'BUG' | 'VULNERABILITY' | 'CODE_SMELL' | 'SECURITY_HOTSPOT' | 'UNKNOWN'; + export type Status = 'ERROR' | 'OK'; + export type Setting = SettingValue & { definition: SettingDefinition }; export type SettingType = diff --git a/server/sonar-web/src/main/js/store/__tests__/branches-test.ts b/server/sonar-web/src/main/js/store/__tests__/branches-test.ts new file mode 100644 index 00000000000..554ac0f6a7e --- /dev/null +++ b/server/sonar-web/src/main/js/store/__tests__/branches-test.ts @@ -0,0 +1,80 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program 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 GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import reducer, { + registerBranchStatusAction, + getBranchStatusByBranchLike, + State +} from '../branches'; +import { + mockPullRequest, + mockLongLivingBranch, + mockShortLivingBranch +} from '../../helpers/testMocks'; +import { getBranchLikeKey } from '../../helpers/branches'; + +type TestArgs = [T.BranchLike, string, T.Status]; + +const COMPONENT = 'foo'; +const BRANCH_STATUS_1: TestArgs = [mockPullRequest(), COMPONENT, 'ERROR']; +const BRANCH_STATUS_2: TestArgs = [mockLongLivingBranch(), 'bar', 'OK']; +const BRANCH_STATUS_3: TestArgs = [mockShortLivingBranch(), COMPONENT, 'OK']; + +it('should allow to register new branche statuses', () => { + const initialState: State = convertToState(); + + const newState = reducer(initialState, registerBranchStatusAction(...BRANCH_STATUS_1)); + expect(newState).toEqual(convertToState([BRANCH_STATUS_1])); + + const newerState = reducer(newState, registerBranchStatusAction(...BRANCH_STATUS_2)); + expect(newerState).toEqual(convertToState([BRANCH_STATUS_1, BRANCH_STATUS_2])); + expect(newState).toEqual(convertToState([BRANCH_STATUS_1])); +}); + +it('should allow to update branche statuses', () => { + const initialState: State = convertToState([BRANCH_STATUS_1, BRANCH_STATUS_2, BRANCH_STATUS_3]); + const branchLike: T.BranchLike = { ...BRANCH_STATUS_1[0], status: { qualityGateStatus: 'OK' } }; + const branchStatus: TestArgs = [branchLike, COMPONENT, 'OK']; + + const newState = reducer(initialState, registerBranchStatusAction(...branchStatus)); + expect(newState).toEqual(convertToState([branchStatus, BRANCH_STATUS_2, BRANCH_STATUS_3])); + expect(initialState).toEqual(convertToState([BRANCH_STATUS_1, BRANCH_STATUS_2, BRANCH_STATUS_3])); +}); + +it('should get the branche statuses from state', () => { + const initialState: State = convertToState([BRANCH_STATUS_1, BRANCH_STATUS_2]); + + const [branchLike, component] = BRANCH_STATUS_1; + expect(getBranchStatusByBranchLike(initialState, component, branchLike)).toEqual('ERROR'); + expect(getBranchStatusByBranchLike(initialState, component, BRANCH_STATUS_2[0])).toBeUndefined(); +}); + +function convertToState(items: TestArgs[] = []) { + const state: State = { byComponent: {} }; + + items.forEach(item => { + const [branchLike, component, status] = item; + state.byComponent[component] = { + ...(state.byComponent[component] || {}), + [getBranchLikeKey(branchLike)]: { status } + }; + }); + + return state; +} diff --git a/server/sonar-web/src/main/js/store/__tests__/rootActions-test.tsx b/server/sonar-web/src/main/js/store/__tests__/rootActions-test.tsx new file mode 100644 index 00000000000..18adff3d44e --- /dev/null +++ b/server/sonar-web/src/main/js/store/__tests__/rootActions-test.tsx @@ -0,0 +1,38 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program 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 GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import { registerBranchStatus } from '../rootActions'; +import { mockLongLivingBranch } from '../../helpers/testMocks'; +import { registerBranchStatusAction } from '../branches'; + +jest.mock('../branches', () => ({ + ...require.requireActual('../branches'), + registerBranchStatusAction: jest.fn() +})); + +it('correctly dispatches actions for branches', () => { + const dispatch = jest.fn(); + const branchLike = mockLongLivingBranch(); + const component = 'foo'; + const status = 'OK'; + + registerBranchStatus(branchLike, component, status)(dispatch); + expect(registerBranchStatusAction).toBeCalledWith(branchLike, component, status); + expect(dispatch).toBeCalled(); +}); diff --git a/server/sonar-web/src/main/js/store/__tests__/rootReducers-test.tsx b/server/sonar-web/src/main/js/store/__tests__/rootReducers-test.tsx new file mode 100644 index 00000000000..e31f34625b8 --- /dev/null +++ b/server/sonar-web/src/main/js/store/__tests__/rootReducers-test.tsx @@ -0,0 +1,37 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program 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 GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import { getBranchStatusByBranchLike, Store } from '../rootReducer'; +import * as fromBranches from '../branches'; +import { mockPullRequest } from '../../helpers/testMocks'; + +jest.mock('../branches', () => { + return { + ...require.requireActual('../branches'), + getBranchStatusByBranchLike: jest.fn() + }; +}); + +it('correctly reduce state for branches', () => { + const branches = {}; + const component = 'foo'; + const branchLike = mockPullRequest(); + getBranchStatusByBranchLike({ branches } as Store, component, branchLike); + expect(fromBranches.getBranchStatusByBranchLike).toBeCalledWith(branches, component, branchLike); +}); diff --git a/server/sonar-web/src/main/js/store/branches.ts b/server/sonar-web/src/main/js/store/branches.ts new file mode 100644 index 00000000000..51593449f0d --- /dev/null +++ b/server/sonar-web/src/main/js/store/branches.ts @@ -0,0 +1,72 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program 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 GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import { ActionType } from './utils/actions'; +import { getBranchLikeKey } from '../helpers/branches'; + +export interface State { + byComponent: T.Dict<T.Dict<{ status?: T.Status }>>; +} + +const enum Actions { + RegisterBranchStatus = 'REGISTER_BRANCH_STATUS' +} + +type Action = ActionType<typeof registerBranchStatusAction, Actions.RegisterBranchStatus>; + +export function registerBranchStatusAction( + branchLike: T.BranchLike, + component: string, + status: T.Status +) { + return { type: Actions.RegisterBranchStatus, branchLike, component, status }; +} + +export default function(state: State = { byComponent: {} }, action: Action): State { + if (action.type === Actions.RegisterBranchStatus) { + const { component, branchLike, status } = action; + const branchLikeKey = getBranchLikeKey(branchLike); + return { + byComponent: { + ...state.byComponent, + [component]: { + ...(state.byComponent[component] || {}), + [branchLikeKey]: { + status + } + } + } + }; + } + + return state; +} + +export function getBranchStatusByBranchLike( + state: State, + component: string, + branchLike: T.BranchLike +) { + const branchLikeKey = getBranchLikeKey(branchLike); + return ( + state.byComponent[component] && + state.byComponent[component][branchLikeKey] && + state.byComponent[component][branchLikeKey].status + ); +} diff --git a/server/sonar-web/src/main/js/store/rootActions.ts b/server/sonar-web/src/main/js/store/rootActions.ts index 6bab84e7335..e9d68e0c5c2 100644 --- a/server/sonar-web/src/main/js/store/rootActions.ts +++ b/server/sonar-web/src/main/js/store/rootActions.ts @@ -20,6 +20,7 @@ import { Dispatch } from 'redux'; import { InjectedRouter } from 'react-router'; import { requireAuthorization as requireAuthorizationAction } from './appState'; +import { registerBranchStatusAction } from './branches'; import { addGlobalErrorMessage } from './globalMessages'; import { receiveLanguages } from './languages'; import { receiveMetrics } from './metrics'; @@ -92,3 +93,13 @@ export function requireAuthorization(router: Pick<InjectedRouter, 'replace'>) { router.replace({ pathname: '/sessions/new', query: { return_to: returnTo } }); return requireAuthorizationAction(); } + +export function registerBranchStatus( + branchLike: T.BranchLike, + component: string, + status: T.Status +) { + return (dispatch: Dispatch) => { + dispatch(registerBranchStatusAction(branchLike, component, status)); + }; +} diff --git a/server/sonar-web/src/main/js/store/rootReducer.ts b/server/sonar-web/src/main/js/store/rootReducer.ts index e4286c79a99..c1b94e09bba 100644 --- a/server/sonar-web/src/main/js/store/rootReducer.ts +++ b/server/sonar-web/src/main/js/store/rootReducer.ts @@ -19,6 +19,7 @@ */ import { combineReducers } from 'redux'; import appState from './appState'; +import branches, * as fromBranches from './branches'; import globalMessages, * as fromGlobalMessages from './globalMessages'; import languages, * as fromLanguages from './languages'; import metrics, * as fromMetrics from './metrics'; @@ -28,6 +29,7 @@ import settingsApp, * as fromSettingsApp from '../apps/settings/store/rootReduce export type Store = { appState: T.AppState; + branches: fromBranches.State; globalMessages: fromGlobalMessages.State; languages: T.Languages; metrics: fromMetrics.State; @@ -40,6 +42,7 @@ export type Store = { export default combineReducers<Store>({ appState, + branches, globalMessages, languages, metrics, @@ -125,3 +128,11 @@ export function isSettingsAppLoading(state: Store, key: string) { export function getSettingsAppValidationMessage(state: Store, key: string) { return fromSettingsApp.getValidationMessage(state.settingsApp, key); } + +export function getBranchStatusByBranchLike( + state: Store, + component: string, + branchLike: T.BranchLike +) { + return fromBranches.getBranchStatusByBranchLike(state.branches, component, branchLike); +} |