Browse Source

SONAR-12626 Show a warning if the migrated SLB is in an incorrect state

tags/8.1.0.31237
Wouter Admiraal 4 years ago
parent
commit
3b2f458bfd

+ 2
- 0
server/sonar-web/src/main/js/apps/overview/components/App.tsx View File

@@ -97,6 +97,8 @@ export class App extends React.PureComponent<Props> {
<OverviewApp
branchLike={branchLike}
component={component}
isInProgress={this.props.isInProgress}
isPending={this.props.isPending}
onComponentChange={this.props.onComponentChange}
/>
)}

+ 38
- 5
server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx View File

@@ -20,8 +20,10 @@
import { uniq } from 'lodash';
import * as React from 'react';
import { connect } from 'react-redux';
import { Alert } from 'sonar-ui-common/components/ui/Alert';
import { parseDate } from 'sonar-ui-common/helpers/dates';
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
import { isDiffMetric } from 'sonar-ui-common/helpers/measures';
import { getMeasuresAndMeta } from '../../../api/measures';
import { getAllTimeMachineData } from '../../../api/time-machine';
import A11ySkipTarget from '../../../app/components/a11y/A11ySkipTarget';
@@ -37,6 +39,7 @@ import { getLeakPeriod } from '../../../helpers/periods';
import { fetchMetrics } from '../../../store/rootActions';
import { getMetrics, Store } from '../../../store/rootReducer';
import { BranchLike } from '../../../types/branch-like';
import { ComponentQualifier } from '../../../types/component';
import {
DEFAULT_GRAPH,
getDisplayedHistoryMetrics,
@@ -56,6 +59,8 @@ import { HISTORY_METRICS_LIST, METRICS } from '../utils';
interface Props {
branchLike?: BranchLike;
component: T.Component;
isInProgress?: boolean;
isPending?: boolean;
fetchMetrics: () => void;
onComponentChange: (changes: {}) => void;
metrics: T.Dict<T.Metric>;
@@ -101,9 +106,10 @@ export class OverviewApp extends React.PureComponent<Props, State> {
};

isEmpty = () => {
const { measures } = this.state;
return (
this.state.measures === undefined ||
this.state.measures.find(measure => measure.metric.key === 'ncloc') === undefined
measures === undefined ||
measures.find(measure => ['lines', 'new_lines'].includes(measure.metric.key)) === undefined
);
};

@@ -164,7 +170,7 @@ export class OverviewApp extends React.PureComponent<Props, State> {

renderEmpty = () => {
const { branchLike, component } = this.props;
const isApp = component.qualifier === 'APP';
const isApp = component.qualifier === ComponentQualifier.Application;

/* eslint-disable no-lonely-if */
// - Is App
@@ -217,11 +223,34 @@ export class OverviewApp extends React.PureComponent<Props, State> {
/* eslint-enable no-lonely-if */
return (
<div className="overview-main page-main">
{this.renderNewAnalysisRequired()}
<h3>{title}</h3>
</div>
);
};

renderNewAnalysisRequired = () => {
const { component, isInProgress, isPending } = this.props;
const { measures, periods } = this.state;
const leakPeriod = getLeakPeriod(periods);

if (
!isInProgress &&
!isPending &&
component.qualifier !== ComponentQualifier.Application &&
measures.some(m => isDiffMetric(m.metric.key)) &&
leakPeriod === undefined
) {
return (
<Alert className="big-spacer-bottom" display="inline" variant="warning">
{translate('overview.project.branch_needs_new_analysis')}
</Alert>
);
} else {
return null;
}
};

renderLoading = () => {
return (
<div className="text-center">
@@ -234,7 +263,9 @@ export class OverviewApp extends React.PureComponent<Props, State> {
const { branchLike, component } = this.props;
const { periods, measures, history, historyStartDate } = this.state;
const leakPeriod =
component.qualifier === 'APP' ? this.getApplicationLeakPeriod() : getLeakPeriod(periods);
component.qualifier === ComponentQualifier.Application
? this.getApplicationLeakPeriod()
: getLeakPeriod(periods);
const domainProps = {
branchLike,
component,
@@ -250,7 +281,9 @@ export class OverviewApp extends React.PureComponent<Props, State> {

return (
<div className="overview-main page-main">
{component.qualifier === 'APP' ? (
{this.renderNewAnalysisRequired()}

{component.qualifier === ComponentQualifier.Application ? (
<ApplicationQualityGate
branch={isBranch(branchLike) && !isMainBranch(branchLike) ? branchLike : undefined}
component={component}

+ 22
- 3
server/sonar-web/src/main/js/apps/overview/components/__tests__/OverviewApp-test.tsx View File

@@ -31,10 +31,10 @@ jest.mock('../../../../api/measures', () => {
return {
getMeasuresAndMeta: jest.fn().mockResolvedValue({
component: {
measures: [mockMeasure({ metric: 'ncloc' }), mockMeasure({ metric: 'coverage' })],
measures: [mockMeasure({ metric: 'lines' }), mockMeasure({ metric: 'coverage' })],
name: 'foo'
},
metrics: [mockMetric({ key: 'ncloc' }), mockMetric()]
metrics: [mockMetric({ key: 'lines' }), mockMetric()]
})
};
});
@@ -50,7 +50,7 @@ jest.mock('../../../../api/time-machine', () => ({
{ metric: 'vulnerabilities', history: [{ date: '2019-01-05', value: '0' }] },
{ metric: 'sqale_index', history: [{ date: '2019-01-01', value: '1.0' }] },
{ metric: 'duplicated_lines_density', history: [{ date: '2019-01-02', value: '1.0' }] },
{ metric: 'ncloc', history: [{ date: '2019-01-03', value: '10000' }] },
{ metric: 'lines', history: [{ date: '2019-01-03', value: '10000' }] },
{ metric: 'coverage', history: [{ date: '2019-01-04', value: '95.5' }] }
]
})
@@ -137,6 +137,25 @@ it('should show the correct message if the project has no lines of code', async
expect(wrapper.find('h3').text()).toBe('overview.project.no_lines_of_code');
});

it('should show a warning if the project has new measures, but no period info', async () => {
(getMeasuresAndMeta as jest.Mock).mockResolvedValue({
component: {
measures: [mockMeasure({ metric: 'bugs' }), mockMeasure({ metric: 'new_bugs' })],
name: 'foo'
},
metrics: [mockMetric({ key: 'bugs' }), mockMetric({ key: 'new_bugs' })]
});

const wrapper = shallowRender();
await waitAndUpdate(wrapper);
expect(
wrapper
.find('Alert')
.dive()
.text()
).toContain('overview.project.branch_needs_new_analysis');
});

function getMockHelpers() {
// We use this little "force-requiring" instead of an import statement in
// order to prevent a hoisting race condition while mocking. If we want to use

+ 13
- 13
server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/OverviewApp-test.tsx.snap View File

@@ -61,7 +61,7 @@ exports[`should render correctly 2`] = `
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "ncloc",
"key": "lines",
"name": "Coverage",
"type": "PERCENT",
},
@@ -149,7 +149,7 @@ exports[`should render correctly 2`] = `
"value": "1.0",
},
],
"ncloc": Array [
"lines": Array [
Object {
"date": "2019-01-03",
"value": "10000",
@@ -176,7 +176,7 @@ exports[`should render correctly 2`] = `
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "ncloc",
"key": "lines",
"name": "Coverage",
"type": "PERCENT",
},
@@ -261,7 +261,7 @@ exports[`should render correctly 2`] = `
"value": "1.0",
},
],
"ncloc": Array [
"lines": Array [
Object {
"date": "2019-01-03",
"value": "10000",
@@ -288,7 +288,7 @@ exports[`should render correctly 2`] = `
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "ncloc",
"key": "lines",
"name": "Coverage",
"type": "PERCENT",
},
@@ -373,7 +373,7 @@ exports[`should render correctly 2`] = `
"value": "1.0",
},
],
"ncloc": Array [
"lines": Array [
Object {
"date": "2019-01-03",
"value": "10000",
@@ -400,7 +400,7 @@ exports[`should render correctly 2`] = `
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "ncloc",
"key": "lines",
"name": "Coverage",
"type": "PERCENT",
},
@@ -485,7 +485,7 @@ exports[`should render correctly 2`] = `
"value": "1.0",
},
],
"ncloc": Array [
"lines": Array [
Object {
"date": "2019-01-03",
"value": "10000",
@@ -512,7 +512,7 @@ exports[`should render correctly 2`] = `
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "ncloc",
"key": "lines",
"name": "Coverage",
"type": "PERCENT",
},
@@ -597,7 +597,7 @@ exports[`should render correctly 2`] = `
"value": "1.0",
},
],
"ncloc": Array [
"lines": Array [
Object {
"date": "2019-01-03",
"value": "10000",
@@ -624,7 +624,7 @@ exports[`should render correctly 2`] = `
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "ncloc",
"key": "lines",
"name": "Coverage",
"type": "PERCENT",
},
@@ -714,7 +714,7 @@ exports[`should render correctly 2`] = `
"value": "1.0",
},
],
"ncloc": Array [
"lines": Array [
Object {
"date": "2019-01-03",
"value": "10000",
@@ -740,7 +740,7 @@ exports[`should render correctly 2`] = `
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "ncloc",
"key": "lines",
"name": "Coverage",
"type": "PERCENT",
},

+ 5
- 3
server/sonar-web/src/main/js/apps/overview/main/Bugs.tsx View File

@@ -54,18 +54,20 @@ export class Bugs extends React.PureComponent<ComposedProps> {

renderLeak() {
const { branchLike, component, leakPeriod } = this.props;
if (!leakPeriod) {
if (!this.props.hasDiffMetrics()) {
return null;
}

return (
<div className="overview-domain-leak">
{component.qualifier === 'APP' ? (
{component.qualifier === 'APP' && (
<ApplicationLeakPeriodLegend
branch={isBranch(branchLike) && !isMainBranch(branchLike) ? branchLike : undefined}
component={component}
/>
) : (
)}

{component.qualifier !== 'APP' && leakPeriod !== undefined && (
<LeakPeriodLegend period={leakPeriod} />
)}


+ 1
- 2
server/sonar-web/src/main/js/apps/overview/main/CodeSmells.tsx View File

@@ -47,8 +47,7 @@ export class CodeSmells extends React.PureComponent<ComposedProps> {
}

renderLeak() {
const { leakPeriod } = this.props;
if (!leakPeriod) {
if (!this.props.hasDiffMetrics()) {
return null;
}


+ 4
- 11
server/sonar-web/src/main/js/apps/overview/main/Coverage.tsx View File

@@ -26,7 +26,6 @@ import {
import DocTooltip from '../../../components/docs/DocTooltip';
import DrilldownLink from '../../../components/shared/DrilldownLink';
import CoverageRating from '../../../components/ui/CoverageRating';
import { getPeriodValue } from '../../../helpers/measures';
import { getMetricName, getThreshold } from '../utils';
import enhance, { ComposedProps } from './enhance';

@@ -89,14 +88,10 @@ export class Coverage extends React.PureComponent<ComposedProps> {
}

renderNewCoverage() {
const { branchLike, component, leakPeriod, measures } = this.props;
if (!leakPeriod) {
return null;
}
const { branchLike, component, measures } = this.props;

const newCoverageMeasure = measures.find(measure => measure.metric.key === 'new_coverage');
const newCoverageValue =
newCoverageMeasure && getPeriodValue(newCoverageMeasure, leakPeriod.index);
const newCoverageValue = newCoverageMeasure && this.props.getValue(newCoverageMeasure);
const formattedValue =
newCoverageMeasure && newCoverageValue !== undefined ? (
<div>
@@ -119,8 +114,7 @@ export class Coverage extends React.PureComponent<ComposedProps> {
);

const newLinesToCover = measures.find(measure => measure.metric.key === 'new_lines_to_cover');
const newLinesToCoverValue =
newLinesToCover && getPeriodValue(newLinesToCover, leakPeriod.index);
const newLinesToCoverValue = newLinesToCover && this.props.getValue(newLinesToCover);
const label =
newLinesToCover && newLinesToCoverValue !== undefined && Number(newLinesToCoverValue) > 0 ? (
<div className="overview-domain-measure-label">
@@ -165,8 +159,7 @@ export class Coverage extends React.PureComponent<ComposedProps> {
}

renderLeak() {
const { leakPeriod } = this.props;
if (!leakPeriod) {
if (!this.props.hasDiffMetrics()) {
return null;
}
return (

+ 4
- 9
server/sonar-web/src/main/js/apps/overview/main/Duplications.tsx View File

@@ -26,7 +26,6 @@ import {
} from 'sonar-ui-common/helpers/measures';
import DocTooltip from '../../../components/docs/DocTooltip';
import DrilldownLink from '../../../components/shared/DrilldownLink';
import { getPeriodValue } from '../../../helpers/measures';
import { getMetricName, getThreshold } from '../utils';
import enhance, { ComposedProps } from './enhance';

@@ -88,15 +87,12 @@ export class Duplications extends React.PureComponent<ComposedProps> {
}

renderNewDuplications() {
const { branchLike, component, measures, leakPeriod } = this.props;
if (!leakPeriod) {
return null;
}
const { branchLike, component, measures } = this.props;
const newDuplicationsMeasure = measures.find(
measure => measure.metric.key === 'new_duplicated_lines_density'
);
const newDuplicationsValue =
newDuplicationsMeasure && getPeriodValue(newDuplicationsMeasure, leakPeriod.index);
newDuplicationsMeasure && this.props.getValue(newDuplicationsMeasure);
const formattedValue =
newDuplicationsMeasure && newDuplicationsValue ? (
<div>
@@ -119,7 +115,7 @@ export class Duplications extends React.PureComponent<ComposedProps> {
);

const newLinesMeasure = measures.find(measure => measure.metric.key === 'new_lines');
const newLinesValue = newLinesMeasure && getPeriodValue(newLinesMeasure, leakPeriod.index);
const newLinesValue = newLinesMeasure && this.props.getValue(newLinesMeasure);
const label =
newLinesMeasure && newLinesValue !== undefined && Number(newLinesValue) > 0 ? (
<div className="overview-domain-measure-label">
@@ -162,8 +158,7 @@ export class Duplications extends React.PureComponent<ComposedProps> {
}

renderLeak() {
const { leakPeriod } = this.props;
if (leakPeriod == null) {
if (!this.props.hasDiffMetrics()) {
return null;
}
return (

+ 1
- 2
server/sonar-web/src/main/js/apps/overview/main/VulnerabilitiesAndHotspots.tsx View File

@@ -34,8 +34,7 @@ export class VulnerabiltiesAndHotspots extends React.PureComponent<ComposedProps
}

renderLeak() {
const { leakPeriod } = this.props;
if (!leakPeriod) {
if (!this.props.hasDiffMetrics()) {
return null;
}


+ 10
- 10
server/sonar-web/src/main/js/apps/overview/main/enhance.tsx View File

@@ -25,14 +25,10 @@ import Rating from 'sonar-ui-common/components/ui/Rating';
import { getLocalizedMetricName, translate } from 'sonar-ui-common/helpers/l10n';
import { formatMeasure } from 'sonar-ui-common/helpers/measures';
import { getWrappedDisplayName } from '../../../components/hoc/utils';
import { getLeakValue } from '../../../components/measure/utils';
import DrilldownLink from '../../../components/shared/DrilldownLink';
import { getBranchLikeQuery } from '../../../helpers/branch-like';
import {
getPeriodValue,
getRatingTooltip,
getShortType,
isDiffMetric
} from '../../../helpers/measures';
import { getRatingTooltip, getShortType, isDiffMetric } from '../../../helpers/measures';
import { getPeriodDate } from '../../../helpers/periods';
import {
getComponentDrilldownUrl,
@@ -55,6 +51,7 @@ export interface EnhanceProps {

export interface ComposedProps extends EnhanceProps {
getValue: (measure: T.MeasureEnhanced) => string | undefined;
hasDiffMetrics: () => boolean;
renderHeader: (domain: string, label?: string) => React.ReactNode;
renderMeasure: (metricKey: string, tooltip?: React.ReactNode) => React.ReactNode;
renderRating: (metricKey: string) => React.ReactNode;
@@ -68,13 +65,15 @@ export default function enhance(ComposedComponent: React.ComponentType<ComposedP
static displayName = getWrappedDisplayName(ComposedComponent, 'enhance');

getValue = (measure: T.MeasureEnhanced) => {
const { leakPeriod } = this.props;
if (!measure) {
return '0';
}
return isDiffMetric(measure.metric.key)
? getPeriodValue(measure, leakPeriod ? leakPeriod.index : 0)
: measure.value;
return isDiffMetric(measure.metric.key) ? getLeakValue(measure) : measure.value;
};

hasDiffMetrics = () => {
const { measures } = this.props;
return measures.some(m => isDiffMetric(m.metric.key));
};

renderHeader = (domain: string, label?: string) => {
@@ -202,6 +201,7 @@ export default function enhance(ComposedComponent: React.ComponentType<ComposedP
<ComposedComponent
{...this.props}
getValue={this.getValue}
hasDiffMetrics={this.hasDiffMetrics}
renderHeader={this.renderHeader}
renderHistoryLink={this.renderHistoryLink}
renderIssues={this.renderIssues}

+ 1
- 0
server/sonar-web/src/main/js/apps/overview/utils.ts View File

@@ -65,6 +65,7 @@ export const METRICS = [

// size
'ncloc',
'lines',
'ncloc_language_distribution',
'projects',
'new_lines'

+ 1
- 1
server/sonar-web/src/main/js/components/measure/utils.ts View File

@@ -35,7 +35,7 @@ export function enhanceMeasure(measure: T.Measure, metrics: T.Dict<T.Metric>): T
};
}

export function getLeakValue(measure: T.Measure | undefined): string | undefined {
export function getLeakValue(measure: T.MeasureIntern | undefined): string | undefined {
if (!measure || !measure.periods) {
return undefined;
}

+ 1
- 0
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

@@ -2588,6 +2588,7 @@ overview.project.branch_X_no_lines_of_code=The "{0}" branch has no lines of code
overview.project.branch_X_empty=The "{0}" branch of this project is empty.
overview.project.main_branch_no_lines_of_code=The main branch has no lines of code.
overview.project.main_branch_empty=The main branch of this project is empty.
overview.project.branch_needs_new_analysis=The branch data is incomplete. Run a new analysis to update it.

overview.metric.code_smells=Code Smells
overview.metric.new_code_smells=New Code Smells

Loading…
Cancel
Save