]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-13195 PR overview not showing all failing conditions
authorWouter Admiraal <wouter.admiraal@sonarsource.com>
Mon, 6 Apr 2020 15:02:48 +0000 (17:02 +0200)
committersonartech <sonartech@sonarsource.com>
Thu, 16 Apr 2020 20:03:49 +0000 (20:03 +0000)
server/sonar-web/src/main/js/apps/overview/__tests__/utils-test.ts
server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx
server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-test.tsx
server/sonar-web/src/main/js/types/quality-gates.ts

index 927b36415e2c3ec8baa332b3cc41d06e9707e7fd..7e06a7b7bdf3ff92c7713a0458d3233414342349 100644 (file)
@@ -62,7 +62,7 @@ function mockMeasure() {
         }),
         mockQualityGateStatusCondition({
           metric: MetricKey.new_duplicated_lines_density,
-          level: 'WARNING',
+          level: 'OK',
           warning: '5'
         })
       ]
index 18862261bce776d7ed839cf33a3d566fd462ba58..4be5783d3af348fbffba5eab3e532c928a0394aa 100644 (file)
@@ -18,6 +18,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as classNames from 'classnames';
+import { differenceBy, uniq } from 'lodash';
 import * as React from 'react';
 import { connect } from 'react-redux';
 import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip';
@@ -48,7 +49,7 @@ interface StateProps {
 }
 
 interface DispatchProps {
-  fetchBranchStatus: (branchLike: BranchLike, projectKey: string) => Promise<void>;
+  fetchBranchStatus: (branchLike: BranchLike, projectKey: string) => void;
 }
 
 interface OwnProps {
@@ -73,29 +74,65 @@ export class PullRequestOverview extends React.PureComponent<Props, State> {
 
   componentDidMount() {
     this.mounted = true;
-    this.fetchBranchData();
+    if (this.props.conditions === undefined) {
+      this.fetchBranchStatusData();
+    } else {
+      this.fetchBranchData();
+    }
+  }
+
+  componentDidUpdate(prevProps: Props) {
+    if (this.conditionsHaveChanged(prevProps)) {
+      this.fetchBranchData();
+    }
   }
 
   componentWillUnmount() {
     this.mounted = false;
   }
 
-  fetchBranchData = () => {
+  conditionsHaveChanged = (prevProps: Props) => {
+    const prevConditions = prevProps.conditions ?? [];
+    const newConditions = this.props.conditions ?? [];
+    const diff = differenceBy(
+      prevConditions.filter(c => c.level === 'ERROR'),
+      newConditions.filter(c => c.level === 'ERROR'),
+      c => c.metric
+    );
+
+    return (
+      (prevProps.conditions === undefined && this.props.conditions !== undefined) || diff.length > 0
+    );
+  };
+
+  fetchBranchStatusData = () => {
     const {
       branchLike,
       component: { key }
     } = this.props;
+    this.props.fetchBranchStatus(branchLike, key);
+  };
+
+  fetchBranchData = () => {
+    const {
+      branchLike,
+      component: { key },
+      conditions
+    } = this.props;
 
     this.setState({ loading: true });
 
-    Promise.all([
-      getMeasuresAndMeta(key, PR_METRICS, {
-        additionalFields: 'metrics',
-        ...getBranchLikeQuery(branchLike)
-      }),
-      this.props.fetchBranchStatus(branchLike, key)
-    ]).then(
-      ([{ component, metrics }]) => {
+    const metricKeys =
+      conditions !== undefined
+        ? // Also load metrics that apply to failing QG conditions.
+          uniq([...PR_METRICS, ...conditions.filter(c => c.level !== 'OK').map(c => c.metric)])
+        : PR_METRICS;
+
+    getMeasuresAndMeta(key, metricKeys, {
+      additionalFields: 'metrics',
+      ...getBranchLikeQuery(branchLike)
+    }).then(
+      ({ component, metrics }) => {
         if (this.mounted && component.measures) {
           this.setState({
             loading: false,
index 1c2c1cb34d53f4b36edb9189a9ee6a1b7ba6211c..ae06e66200a6c06e31b481eba82107bf18e98bae 100644 (file)
@@ -24,6 +24,7 @@ import { getMeasuresAndMeta } from '../../../../api/measures';
 import { mockPullRequest } from '../../../../helpers/mocks/branch-like';
 import { mockQualityGateStatusCondition } from '../../../../helpers/mocks/quality-gates';
 import { mockComponent } from '../../../../helpers/testMocks';
+import { PR_METRICS } from '../../utils';
 import { PullRequestOverview } from '../PullRequestOverview';
 
 jest.mock('../../../../api/measures', () => {
@@ -103,13 +104,22 @@ it('should render correctly for a failed QG', async () => {
   expect(wrapper).toMatchSnapshot();
 });
 
-it('should correctly handle a WS failure', async () => {
-  (getMeasuresAndMeta as jest.Mock).mockRejectedValueOnce({});
-  const fetchBranchStatus = jest.fn().mockRejectedValue({});
-  const wrapper = shallowRender({ fetchBranchStatus });
+it('should correctly fetch all required metrics for a passing QG', async () => {
+  const wrapper = shallowRender({ conditions: [] });
+  await waitAndUpdate(wrapper);
+  expect(getMeasuresAndMeta).toBeCalledWith('my-project', PR_METRICS, expect.any(Object));
+});
 
+it('should correctly fetch all required metrics for a failing QG', async () => {
+  const wrapper = shallowRender({
+    conditions: [mockQualityGateStatusCondition({ level: 'ERROR', metric: 'foo' })]
+  });
   await waitAndUpdate(wrapper);
-  expect(wrapper.type()).toBeNull();
+  expect(getMeasuresAndMeta).toBeCalledWith(
+    'my-project',
+    [...PR_METRICS, 'foo'],
+    expect.any(Object)
+  );
 });
 
 function shallowRender(props: Partial<PullRequestOverview['props']> = {}) {
index e3dbe2130c3c234c5cb5310295003d201d1b8911..84b14f1bf45579b993bd3fbfd2c223e58227b42a 100644 (file)
@@ -44,7 +44,7 @@ export interface QualityGateApplicationStatusCondition {
   metric: string;
   periodIndex?: number;
   onLeak?: boolean;
-  status: string;
+  status: T.Status;
   value: string;
   warningThreshold?: string;
 }
@@ -67,7 +67,7 @@ export interface QualityGateStatus {
 export interface QualityGateStatusCondition {
   actual?: string;
   error?: string;
-  level: string;
+  level: T.Status;
   metric: string;
   op: string;
   period?: number;