]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10571 Show background task notifications only on related branch/pr
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Fri, 13 Apr 2018 08:51:47 +0000 (10:51 +0200)
committerSonarTech <sonartech@sonarsource.com>
Mon, 16 Apr 2018 18:20:47 +0000 (20:20 +0200)
server/sonar-web/src/main/js/api/ce.ts
server/sonar-web/src/main/js/app/components/ComponentContainer.tsx
server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx
server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx

index 3046f797467f5b133531e397a11944239b57c899..21eaff0990df1cbb37734f3487fb8b26eb2eb17b 100644 (file)
@@ -21,12 +21,16 @@ import { getJSON, post, RequestData } from '../helpers/request';
 import throwGlobalError from '../app/utils/throwGlobalError';
 
 export interface PendingTask {
+  branch?: string;
+  branchType?: string;
   componentKey: string;
   componentName: string;
   componentQualifier: string;
   id: string;
   logs: boolean;
   organization: string;
+  pullRequest?: string;
+  pullRequestTitle?: string;
   status: string;
   submittedAt: Date;
   submitterLogin?: string;
index 530bb5f63d4278a91dd85dfd291eb02ed2ce1487..27165885dc5a3dc2e423948057f9c20e221fd1cb 100644 (file)
@@ -25,12 +25,18 @@ import ComponentNav from './nav/component/ComponentNav';
 import { Component, BranchLike } from '../types';
 import handleRequiredAuthorization from '../utils/handleRequiredAuthorization';
 import { getBranches, getPullRequests } from '../../api/branches';
-import { Task, getTasksForComponent } from '../../api/ce';
+import { Task, getTasksForComponent, PendingTask } from '../../api/ce';
 import { getComponentData } from '../../api/components';
 import { getComponentNavigation } from '../../api/nav';
 import { fetchOrganizations } from '../../store/rootActions';
 import { STATUSES } from '../../apps/background-tasks/constants';
-import { isPullRequest, isBranch } from '../../helpers/branches';
+import {
+  isPullRequest,
+  isBranch,
+  isMainBranch,
+  isLongLivingBranch,
+  isShortLivingBranch
+} from '../../helpers/branches';
 
 interface Props {
   children: any;
@@ -42,11 +48,10 @@ interface Props {
 
 interface State {
   branchLikes: BranchLike[];
-  loading: boolean;
   component?: Component;
   currentTask?: Task;
-  isInProgress?: boolean;
-  isPending?: boolean;
+  loading: boolean;
+  pendingTasks?: PendingTask[];
 }
 
 export class ComponentContainer extends React.PureComponent<Props, State> {
@@ -132,17 +137,38 @@ export class ComponentContainer extends React.PureComponent<Props, State> {
     getTasksForComponent(component.key).then(
       ({ current, queue }) => {
         if (this.mounted) {
-          this.setState({
-            currentTask: current,
-            isInProgress: queue.some(task => task.status === STATUSES.IN_PROGRESS),
-            isPending: queue.some(task => task.status === STATUSES.PENDING)
-          });
+          this.setState({ currentTask: current, pendingTasks: queue });
         }
       },
       () => {}
     );
   };
 
+  getCurrentTask = (branchLike?: BranchLike) => {
+    const { currentTask } = this.state;
+    return currentTask && this.isSameBranch(currentTask, branchLike) ? currentTask : undefined;
+  };
+
+  getPendingTasks = (branchLike?: BranchLike) => {
+    const { pendingTasks = [] } = this.state;
+    return pendingTasks.filter(task => this.isSameBranch(task, branchLike));
+  };
+
+  isSameBranch = (
+    task: Pick<PendingTask, 'branch' | 'branchType' | 'pullRequest'>,
+    branchLike?: BranchLike
+  ) => {
+    if (branchLike && !isMainBranch(branchLike)) {
+      if (isPullRequest(branchLike)) {
+        return branchLike.key === task.pullRequest;
+      }
+      if (isShortLivingBranch(branchLike) || isLongLivingBranch(branchLike)) {
+        return branchLike.type === task.branchType && branchLike.name === task.branch;
+      }
+    }
+    return !task.branch && !task.pullRequest;
+  };
+
   handleComponentChange = (changes: {}) => {
     if (this.mounted) {
       this.setState(state => ({ component: { ...state.component, ...changes } }));
@@ -174,6 +200,11 @@ export class ComponentContainer extends React.PureComponent<Props, State> {
       ? branchLikes.find(b => isPullRequest(b) && b.key === query.pullRequest)
       : branchLikes.find(b => isBranch(b) && (query.branch ? b.name === query.branch : b.isMain));
 
+    const currentTask = this.getCurrentTask(branchLike);
+    const pendingTasks = this.getPendingTasks(branchLike);
+    const isInProgress = pendingTasks.some(task => task.status === STATUSES.IN_PROGRESS);
+    const isPending = pendingTasks.some(task => task.status === STATUSES.PENDING);
+
     return (
       <div>
         {component &&
@@ -182,9 +213,9 @@ export class ComponentContainer extends React.PureComponent<Props, State> {
               branchLikes={branchLikes}
               component={component}
               currentBranchLike={branchLike}
-              currentTask={this.state.currentTask}
-              isInProgress={this.state.isInProgress}
-              isPending={this.state.isPending}
+              currentTask={currentTask}
+              isInProgress={isInProgress}
+              isPending={isPending}
               location={this.props.location}
             />
           )}
@@ -197,8 +228,8 @@ export class ComponentContainer extends React.PureComponent<Props, State> {
             branchLike,
             branchLikes,
             component,
-            isInProgress: this.state.isInProgress,
-            isPending: this.state.isPending,
+            isInProgress,
+            isPending,
             onBranchesChange: this.handleBranchesChange,
             onComponentChange: this.handleComponentChange
           })
index b0917c9d1c72eccd829bd0285003fc57e9936d62..1611daa5d00ac8553a31a887dc9d3ff44ace1d6b 100644 (file)
@@ -21,9 +21,16 @@ import * as React from 'react';
 import { shallow, mount } from 'enzyme';
 import { ComponentContainer } from '../ComponentContainer';
 import { getBranches, getPullRequests } from '../../../api/branches';
-import { getTasksForComponent } from '../../../api/ce';
+import { getTasksForComponent, Task } from '../../../api/ce';
 import { getComponentData } from '../../../api/components';
 import { getComponentNavigation } from '../../../api/nav';
+import {
+  ShortLivingBranch,
+  MainBranch,
+  LongLivingBranch,
+  PullRequest,
+  BranchType
+} from '../../types';
 
 jest.mock('../../../api/branches', () => ({
   getBranches: jest.fn(() => Promise.resolve([])),
@@ -170,3 +177,61 @@ it('fetches status', async () => {
   await new Promise(setImmediate);
   expect(getTasksForComponent).toBeCalledWith('portfolioKey');
 });
+
+it('filters correctly the pending tasks for a main branch', () => {
+  const wrapper = shallow(
+    <ComponentContainer fetchOrganizations={jest.fn()} location={{ query: { id: 'foo' } }}>
+      <Inner />
+    </ComponentContainer>
+  );
+
+  const component = wrapper.instance() as ComponentContainer;
+  const mainBranch: MainBranch = { isMain: true, name: 'master' };
+  const shortBranch: ShortLivingBranch = {
+    isMain: false,
+    mergeBranch: 'master',
+    name: 'feature',
+    type: BranchType.SHORT
+  };
+  const longBranch: LongLivingBranch = { isMain: false, name: 'branch-7.2', type: BranchType.LONG };
+  const pullRequest: PullRequest = {
+    base: 'feature',
+    branch: 'feature',
+    key: 'pr-89',
+    title: 'PR Feature'
+  };
+
+  expect(component.isSameBranch({}, undefined)).toBeTruthy();
+  expect(component.isSameBranch({}, mainBranch)).toBeTruthy();
+  expect(component.isSameBranch({}, shortBranch)).toBeFalsy();
+  expect(
+    component.isSameBranch({ branch: 'feature', branchType: 'SHORT' }, shortBranch)
+  ).toBeTruthy();
+  expect(
+    component.isSameBranch({ branch: 'feature', branchType: 'SHORT' }, longBranch)
+  ).toBeFalsy();
+  expect(
+    component.isSameBranch({ branch: 'feature', branchType: 'SHORT' }, longBranch)
+  ).toBeFalsy();
+  expect(
+    component.isSameBranch({ branch: 'branch-7.1', branchType: 'LONG' }, longBranch)
+  ).toBeFalsy();
+  expect(
+    component.isSameBranch({ branch: 'branch-7.2', branchType: 'LONG' }, pullRequest)
+  ).toBeFalsy();
+  expect(component.isSameBranch({ pullRequest: 'pr-89' }, pullRequest)).toBeTruthy();
+
+  const currentTask = { pullRequest: 'pr-89' } as Task;
+  const pendingTasks = [
+    currentTask,
+    { branch: 'feature', branchType: 'SHORT' } as Task,
+    {} as Task
+  ];
+  expect(component.getCurrentTask(undefined)).toBe(undefined);
+  component.setState({ currentTask });
+  expect(component.getCurrentTask(mainBranch)).toBe(undefined);
+  expect(component.getCurrentTask(pullRequest)).toMatchObject(currentTask);
+  component.setState({ pendingTasks });
+  expect(component.getPendingTasks(mainBranch)).toMatchObject([{}]);
+  expect(component.getPendingTasks(pullRequest)).toMatchObject([currentTask]);
+});
index 366b240f3576b51b977eceaf3f66a65b8be00b65..f5ca55b6f8348f77e58b3477b8eb4a18b11dd237 100644 (file)
@@ -67,12 +67,12 @@ export default class ComponentNav extends React.PureComponent<Props> {
   };
 
   render() {
-    const { currentTask, isInProgress, isPending } = this.props;
+    const { component, currentBranchLike, currentTask, isInProgress, isPending } = this.props;
     let notifComponent;
     if (isInProgress || isPending || (currentTask && currentTask.status === STATUSES.FAILED)) {
       notifComponent = (
         <ComponentNavBgTaskNotif
-          component={this.props.component}
+          component={component}
           currentTask={currentTask}
           isInProgress={isInProgress}
           isPending={isPending}
@@ -87,19 +87,16 @@ export default class ComponentNav extends React.PureComponent<Props> {
         <div className="navbar-context-justified">
           <ComponentNavHeader
             branchLikes={this.props.branchLikes}
-            component={this.props.component}
-            currentBranchLike={this.props.currentBranchLike}
+            component={component}
+            currentBranchLike={currentBranchLike}
             // to close dropdown on any location change
             location={this.props.location}
           />
-          <ComponentNavMeta
-            branchLike={this.props.currentBranchLike}
-            component={this.props.component}
-          />
+          <ComponentNavMeta branchLike={currentBranchLike} component={component} />
         </div>
         <ComponentNavMenu
-          branchLike={this.props.currentBranchLike}
-          component={this.props.component}
+          branchLike={currentBranchLike}
+          component={component}
           // to re-render selected menu item
           location={this.props.location}
         />