Browse Source

SONAR-13569 Fix missleading message when referencing same branch for new code.

tags/8.5.0.37579
Mathieu Suen 3 years ago
parent
commit
7562d01e1f

+ 17
- 18
server/sonar-web/src/main/js/apps/overview/branches/BranchOverview.tsx View File

@@ -43,7 +43,7 @@ import {
extractStatusConditionsFromProjectStatus
} from '../../../helpers/qualityGates';
import { ApplicationPeriod } from '../../../types/application';
import { BranchLike } from '../../../types/branch-like';
import { Branch, BranchLike } from '../../../types/branch-like';
import { ComponentQualifier } from '../../../types/component';
import { MetricKey } from '../../../types/metrics';
import { GraphType, MeasureHistory } from '../../../types/project-activity';
@@ -53,7 +53,7 @@ import { HISTORY_METRICS_LIST, METRICS } from '../utils';
import BranchOverviewRenderer from './BranchOverviewRenderer';

interface Props {
branchLike?: BranchLike;
branch?: Branch;
component: T.Component;
}

@@ -95,7 +95,7 @@ export default class BranchOverview extends React.PureComponent<Props, State> {
componentDidUpdate(prevProps: Props) {
if (
this.props.component.key !== prevProps.component.key ||
!isSameBranchLike(this.props.branchLike, prevProps.branchLike)
!isSameBranchLike(this.props.branch, prevProps.branch)
) {
this.loadStatus();
this.loadHistory();
@@ -115,22 +115,21 @@ export default class BranchOverview extends React.PureComponent<Props, State> {
};

loadApplicationStatus = async () => {
const { branchLike, component } = this.props;
const { branch, component } = this.props;
this.setState({ loadingStatus: true });
// Start by loading the application quality gate info, as well as the meta
// data for the application as a whole.
const appStatus = await getApplicationQualityGate({
application: component.key,
...getBranchLikeQuery(branchLike)
...getBranchLikeQuery(branch)
});
const { measures: appMeasures, metrics, period } = await this.loadMeasuresAndMeta(
component.key,
branchLike
branch
);

const appBranchName =
(branchLike && !isMainBranch(branchLike) && getBranchLikeDisplayName(branchLike)) ||
undefined;
(branch && !isMainBranch(branch) && getBranchLikeDisplayName(branch)) || undefined;

const appDetails = await getApplicationDetails(component.key, appBranchName);

@@ -212,14 +211,14 @@ export default class BranchOverview extends React.PureComponent<Props, State> {

loadProjectStatus = async () => {
const {
branchLike,
branch,
component: { key, name }
} = this.props;
this.setState({ loadingStatus: true });

const projectStatus = await getQualityGateProjectStatus({
projectKey: key,
...getBranchLikeQuery(branchLike)
...getBranchLikeQuery(branch)
});

// Get failing condition metric keys. We need measures for them as well to
@@ -229,7 +228,7 @@ export default class BranchOverview extends React.PureComponent<Props, State> {
? uniq([...METRICS, ...projectStatus.conditions.map(c => c.metricKey)])
: METRICS;

this.loadMeasuresAndMeta(key, branchLike, metricKeys).then(
this.loadMeasuresAndMeta(key, branch, metricKeys).then(
({ measures, metrics, period }) => {
if (this.mounted && measures) {
const { ignoredConditions, status } = projectStatus;
@@ -242,7 +241,7 @@ export default class BranchOverview extends React.PureComponent<Props, State> {
key,
name,
status,
branchLike
branchLike: branch
};

this.setState({
@@ -292,14 +291,14 @@ export default class BranchOverview extends React.PureComponent<Props, State> {
};

loadHistoryMeasures = () => {
const { branchLike, component } = this.props;
const { branch, component } = this.props;
const { graph } = this.state;

const graphMetrics = getHistoryMetrics(graph, []);
const metrics = uniq([...HISTORY_METRICS_LIST, ...graphMetrics]);

return getAllTimeMachineData({
...getBranchLikeQuery(branchLike),
...getBranchLikeQuery(branch),
from: FROM_DATE,
component: component.key,
metrics: metrics.join()
@@ -322,10 +321,10 @@ export default class BranchOverview extends React.PureComponent<Props, State> {
};

loadAnalyses = () => {
const { branchLike } = this.props;
const { branch } = this.props;

return getProjectActivity({
...getBranchLikeQuery(branchLike),
...getBranchLikeQuery(branch),
project: this.getTopLevelComponent(),
from: FROM_DATE
}).then(
@@ -389,7 +388,7 @@ export default class BranchOverview extends React.PureComponent<Props, State> {
};

render() {
const { branchLike, component } = this.props;
const { branch, component } = this.props;
const {
analyses,
appLeak,
@@ -414,7 +413,7 @@ export default class BranchOverview extends React.PureComponent<Props, State> {
<BranchOverviewRenderer
analyses={analyses}
appLeak={appLeak}
branchLike={branchLike}
branch={branch}
component={component}
graph={graph}
loadingHistory={loadingHistory}

+ 6
- 6
server/sonar-web/src/main/js/apps/overview/branches/BranchOverviewRenderer.tsx View File

@@ -21,7 +21,7 @@ import * as React from 'react';
import { parseDate } from 'sonar-ui-common/helpers/dates';
import A11ySkipTarget from '../../../app/components/a11y/A11ySkipTarget';
import { ApplicationPeriod } from '../../../types/application';
import { BranchLike } from '../../../types/branch-like';
import { Branch } from '../../../types/branch-like';
import { ComponentQualifier } from '../../../types/component';
import { GraphType, MeasureHistory } from '../../../types/project-activity';
import { QualityGateStatus } from '../../../types/quality-gates';
@@ -33,7 +33,7 @@ import QualityGatePanel from './QualityGatePanel';
export interface BranchOverviewRendererProps {
analyses?: T.Analysis[];
appLeak?: ApplicationPeriod;
branchLike?: BranchLike;
branch?: Branch;
component: T.Component;
graph?: GraphType;
loadingHistory?: boolean;
@@ -51,7 +51,7 @@ export function BranchOverviewRenderer(props: BranchOverviewRendererProps) {
const {
analyses,
appLeak,
branchLike,
branch,
component,
graph,
loadingHistory,
@@ -73,7 +73,7 @@ export function BranchOverviewRenderer(props: BranchOverviewRendererProps) {
<A11ySkipTarget anchor="overview_main" />

{projectIsEmpty ? (
<NoCodeWarning branchLike={branchLike} component={component} measures={measures} />
<NoCodeWarning branchLike={branch} component={component} measures={measures} />
) : (
<div className="display-flex-row">
<div className="width-25 big-spacer-right">
@@ -88,7 +88,7 @@ export function BranchOverviewRenderer(props: BranchOverviewRendererProps) {
<div className="display-flex-column">
<MeasuresPanel
appLeak={appLeak}
branchLike={branchLike}
branch={branch}
component={component}
loading={loadingStatus}
measures={measures}
@@ -97,7 +97,7 @@ export function BranchOverviewRenderer(props: BranchOverviewRendererProps) {

<ActivityPanel
analyses={analyses}
branchLike={branchLike}
branchLike={branch}
component={component}
graph={graph}
leakPeriodDate={leakPeriod && parseDate(leakPeriod.date)}

+ 9
- 13
server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanel.tsx View File

@@ -25,7 +25,7 @@ import { isDiffMetric } from 'sonar-ui-common/helpers/measures';
import { rawSizes } from '../../../app/theme';
import { findMeasure } from '../../../helpers/measures';
import { ApplicationPeriod } from '../../../types/application';
import { BranchLike } from '../../../types/branch-like';
import { Branch } from '../../../types/branch-like';
import { ComponentQualifier } from '../../../types/component';
import { IssueType } from '../../../types/issues';
import { MetricKey } from '../../../types/metrics';
@@ -38,7 +38,7 @@ import MeasuresPanelNoNewCode from './MeasuresPanelNoNewCode';

export interface MeasuresPanelProps {
appLeak?: ApplicationPeriod;
branchLike?: BranchLike;
branch?: Branch;
component: T.Component;
loading?: boolean;
measures?: T.MeasureEnhanced[];
@@ -51,7 +51,7 @@ export enum MeasuresPanelTabs {
}

export function MeasuresPanel(props: MeasuresPanelProps) {
const { appLeak, branchLike, component, loading, measures = [], period } = props;
const { appLeak, branch, component, loading, measures = [], period } = props;

const hasDiffMeasures = measures.some(m => isDiffMetric(m.metric.key));
const isApp = component.qualifier === ComponentQualifier.Application;
@@ -107,11 +107,7 @@ export function MeasuresPanel(props: MeasuresPanelProps) {

<div className="overview-panel-content flex-1 bordered">
{!hasDiffMeasures && isNewCodeTab ? (
<MeasuresPanelNoNewCode
branchLike={branchLike}
component={component}
period={period}
/>
<MeasuresPanelNoNewCode branch={branch} component={component} period={period} />
) : (
<>
{[
@@ -121,7 +117,7 @@ export function MeasuresPanel(props: MeasuresPanelProps) {
IssueType.CodeSmell
].map((type: IssueType) => (
<MeasuresPanelIssueMeasureRow
branchLike={branchLike}
branchLike={branch}
component={component}
isNewCodeTab={isNewCodeTab}
key={type}
@@ -137,7 +133,7 @@ export function MeasuresPanel(props: MeasuresPanelProps) {
className="overview-panel-huge-padded flex-1 bordered-right display-flex-center"
data-test="overview__measures-coverage">
<MeasurementLabel
branchLike={branchLike}
branchLike={branch}
centered={isNewCodeTab}
component={component}
measures={measures}
@@ -148,7 +144,7 @@ export function MeasuresPanel(props: MeasuresPanelProps) {
{tab === MeasuresPanelTabs.Overall && (
<div className="huge-spacer-left">
<DrilldownMeasureValue
branchLike={branchLike}
branchLike={branch}
component={component}
measures={measures}
metric={MetricKey.tests}
@@ -159,7 +155,7 @@ export function MeasuresPanel(props: MeasuresPanelProps) {
)}
<div className="overview-panel-huge-padded flex-1 display-flex-center">
<MeasurementLabel
branchLike={branchLike}
branchLike={branch}
centered={isNewCodeTab}
component={component}
measures={measures}
@@ -170,7 +166,7 @@ export function MeasuresPanel(props: MeasuresPanelProps) {
{tab === MeasuresPanelTabs.Overall && (
<div className="huge-spacer-left">
<DrilldownMeasureValue
branchLike={branchLike}
branchLike={branch}
component={component}
measures={measures}
metric={MetricKey.duplicated_blocks}

+ 16
- 12
server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelNoNewCode.tsx View File

@@ -23,27 +23,35 @@ import { Link } from 'react-router';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { getBaseUrl } from 'sonar-ui-common/helpers/urls';
import { getBranchLikeQuery } from '../../../helpers/branch-like';
import { BranchLike } from '../../../types/branch-like';
import { Branch } from '../../../types/branch-like';
import { ComponentQualifier } from '../../../types/component';

export interface MeasuresPanelNoNewCodeProps {
branchLike?: BranchLike;
branch?: Branch;
component: T.Component;
period?: T.Period;
}

export default function MeasuresPanelNoNewCode(props: MeasuresPanelNoNewCodeProps) {
const { branchLike, component, period } = props;
const { branch, component, period } = props;

const isApp = component.qualifier === ComponentQualifier.Application;

const hasBadReferenceBranch =
!isApp && !!period && !period.date && period.mode === 'REFERENCE_BRANCH';
/*
* If the period is "reference branch"-based, and if there's no date, it means
* that we're not lacking a second analysis, but that we'll never have new code because the
* selected reference branch is itself, or has disappeared for some reason.
* Makes no sense for Apps (project aggregate)
*/
const hasBadNewCodeSetting =
!isApp && !!period && !period.date && period.mode === 'REFERENCE_BRANCH';
const hasBadNewCodeSettingSameRef = hasBadReferenceBranch && branch?.name === period?.parameter;

const badExplanationKey = hasBadReferenceBranch
? hasBadNewCodeSettingSameRef
? 'overview.measures.same_reference.explanation'
: 'overview.measures.bad_reference.explanation'
: 'overview.measures.empty_explanation';

const showSettingsLink = !!(component.configuration && component.configuration.showSettings);

@@ -56,12 +64,8 @@ export default function MeasuresPanelNoNewCode(props: MeasuresPanelNoNewCodeProp
src={`${getBaseUrl()}/images/source-code.svg`}
/>
<div className="big-spacer-left text-muted" style={{ maxWidth: 500 }}>
<p className="spacer-bottom big-spacer-top big">
{hasBadNewCodeSetting
? translate('overview.measures.bad_setting.explanation')
: translate('overview.measures.empty_explanation')}
</p>
{hasBadNewCodeSetting ? (
<p className="spacer-bottom big-spacer-top big">{translate(badExplanationKey)}</p>
{hasBadNewCodeSettingSameRef ? (
showSettingsLink && (
<p>
<FormattedMessage
@@ -72,7 +76,7 @@ export default function MeasuresPanelNoNewCode(props: MeasuresPanelNoNewCodeProp
<Link
to={{
pathname: '/project/baseline',
query: { id: component.key, ...getBranchLikeQuery(branchLike) }
query: { id: component.key, ...getBranchLikeQuery(branch) }
}}>
{translate('settings.new_code_period.category')}
</Link>

+ 2
- 2
server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-test.tsx View File

@@ -254,7 +254,7 @@ describe('application overview', () => {
});

it('should fetch correctly other branch', async () => {
const wrapper = shallowRender({ branchLike: mockBranch(), component });
const wrapper = shallowRender({ branch: mockBranch(), component });
await waitAndUpdate(wrapper);
expect(getApplicationDetails).toHaveBeenCalled();
expect(wrapper).toMatchSnapshot();
@@ -358,7 +358,7 @@ it('should correctly handle graph type storage', () => {
function shallowRender(props: Partial<BranchOverview['props']> = {}) {
return shallow<BranchOverview>(
<BranchOverview
branchLike={mockMainBranch()}
branch={mockMainBranch()}
component={mockComponent({
breadcrumbs: [mockComponent({ key: 'foo' })],
key: 'foo',

+ 1
- 1
server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverviewRenderer-test.tsx View File

@@ -33,7 +33,7 @@ it('should render correctly', () => {
function shallowRender(props: Partial<BranchOverviewRendererProps> = {}) {
return shallow(
<BranchOverviewRenderer
branchLike={mockMainBranch()}
branch={mockMainBranch()}
component={mockComponent()}
graph={GraphType.issues}
loadingHistory={false}

+ 2
- 2
server/sonar-web/src/main/js/apps/overview/branches/__tests__/MeasuresPanel-test.tsx View File

@@ -60,7 +60,7 @@ it('should render correctly if there is no new code measures', () => {

it('should render correctly if branch is misconfigured', () => {
const wrapper = shallowRender({
branchLike: mockBranch({ name: 'own-reference' }),
branch: mockBranch({ name: 'own-reference' }),
measures: [
mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.coverage }) }),
mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.bugs }) })
@@ -92,7 +92,7 @@ it('should render correctly if the data is still loading', () => {
function shallowRender(props: Partial<MeasuresPanelProps> = {}) {
return shallow<MeasuresPanelProps>(
<MeasuresPanel
branchLike={mockMainBranch()}
branch={mockMainBranch()}
component={mockComponent()}
measures={[
mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.coverage }) }),

+ 11
- 1
server/sonar-web/src/main/js/apps/overview/branches/__tests__/MeasuresPanelNoNewCode-test.tsx View File

@@ -84,6 +84,16 @@ it('should render the default message', () => {
expect(
shallowRender({ period: mockPeriod({ date: '2018-05-23', mode: 'PREVIOUS_VERSION' }) })
).toMatchInlineSnapshot(defaultMessage);
expect(
shallowRender({
period: mockPeriod({ date: undefined, mode: 'REFERENCE_BRANCH', parameter: 'master' })
})
).toMatchSnapshot();
expect(
shallowRender({
period: mockPeriod({ date: undefined, mode: 'REFERENCE_BRANCH', parameter: 'notsame' })
})
).toMatchSnapshot();
});

it('should render "bad code setting" explanation', () => {
@@ -96,6 +106,6 @@ it('should render "bad code setting" explanation', () => {

function shallowRender(props: Partial<MeasuresPanelNoNewCodeProps> = {}) {
return shallow<MeasuresPanelNoNewCodeProps>(
<MeasuresPanelNoNewCode branchLike={mockMainBranch()} component={mockComponent()} {...props} />
<MeasuresPanelNoNewCode branch={mockMainBranch()} component={mockComponent()} {...props} />
);
}

+ 3
- 3
server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/BranchOverview-test.tsx.snap View File

@@ -43,7 +43,7 @@ exports[`application overview should fetch correctly other branch 1`] = `
"projectName": "Foo",
}
}
branchLike={
branch={
Object {
"analysisDate": "2018-01-01",
"excludedFromPurge": true,
@@ -965,7 +965,7 @@ exports[`application overview should render correctly 1`] = `
"projectName": "Foo",
}
}
branchLike={
branch={
Object {
"analysisDate": "2018-01-01",
"excludedFromPurge": true,
@@ -1880,7 +1880,7 @@ exports[`project overview should render correctly 1`] = `
},
]
}
branchLike={
branch={
Object {
"analysisDate": "2018-01-01",
"excludedFromPurge": true,

+ 2
- 2
server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/BranchOverviewRenderer-test.tsx.snap View File

@@ -50,7 +50,7 @@ exports[`should render correctly 1`] = `
className="display-flex-column"
>
<MeasuresPanel
branchLike={
branch={
Object {
"analysisDate": "2018-01-01",
"excludedFromPurge": true,
@@ -265,7 +265,7 @@ exports[`should render correctly 3`] = `
className="display-flex-column"
>
<MeasuresPanel
branchLike={
branch={
Object {
"analysisDate": "2018-01-01",
"excludedFromPurge": true,

+ 3
- 3
server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanel-test.tsx.snap View File

@@ -3254,7 +3254,7 @@ exports[`should render correctly if branch is misconfigured: hide settings 1`] =
className="overview-panel-content flex-1 bordered"
>
<MeasuresPanelNoNewCode
branchLike={
branch={
Object {
"analysisDate": "2018-01-01",
"excludedFromPurge": true,
@@ -3360,7 +3360,7 @@ exports[`should render correctly if branch is misconfigured: show settings 1`] =
className="overview-panel-content flex-1 bordered"
>
<MeasuresPanelNoNewCode
branchLike={
branch={
Object {
"analysisDate": "2018-01-01",
"excludedFromPurge": true,
@@ -3903,7 +3903,7 @@ exports[`should render correctly if there is no new code measures 1`] = `
className="overview-panel-content flex-1 bordered"
>
<MeasuresPanelNoNewCode
branchLike={
branch={
Object {
"analysisDate": "2018-01-01",
"excludedFromPurge": true,

+ 105
- 14
server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanelNoNewCode-test.tsx.snap View File

@@ -26,7 +26,24 @@ exports[`should render "bad code setting" explanation: no link 1`] = `
<p
className="spacer-bottom big-spacer-top big"
>
overview.measures.bad_setting.explanation
overview.measures.bad_reference.explanation
</p>
<p>
<FormattedMessage
defaultMessage="overview.measures.empty_link"
id="overview.measures.empty_link"
values={
Object {
"learn_more_link": <Link
onlyActiveOnIndex={false}
style={Object {}}
to="/documentation/user-guide/clean-as-you-code/"
>
learn_more
</Link>,
}
}
/>
</p>
</div>
</div>
@@ -58,27 +75,101 @@ exports[`should render "bad code setting" explanation: with link 1`] = `
<p
className="spacer-bottom big-spacer-top big"
>
overview.measures.bad_setting.explanation
overview.measures.bad_reference.explanation
</p>
<p>
<FormattedMessage
defaultMessage="overview.measures.empty_link"
id="overview.measures.empty_link"
values={
Object {
"learn_more_link": <Link
onlyActiveOnIndex={false}
style={Object {}}
to="/documentation/user-guide/clean-as-you-code/"
>
learn_more
</Link>,
}
}
/>
</p>
</div>
</div>
`;

exports[`should render the default message 5`] = `
<div
className="display-flex-center display-flex-justify-center"
style={
Object {
"height": 500,
}
}
>
<img
alt=""
className="spacer-right"
height={52}
src="/images/source-code.svg"
/>
<div
className="big-spacer-left text-muted"
style={
Object {
"maxWidth": 500,
}
}
>
<p
className="spacer-bottom big-spacer-top big"
>
overview.measures.same_reference.explanation
</p>
</div>
</div>
`;

exports[`should render the default message 6`] = `
<div
className="display-flex-center display-flex-justify-center"
style={
Object {
"height": 500,
}
}
>
<img
alt=""
className="spacer-right"
height={52}
src="/images/source-code.svg"
/>
<div
className="big-spacer-left text-muted"
style={
Object {
"maxWidth": 500,
}
}
>
<p
className="spacer-bottom big-spacer-top big"
>
overview.measures.bad_reference.explanation
</p>
<p>
<FormattedMessage
defaultMessage="overview.measures.bad_setting.link"
id="overview.measures.bad_setting.link"
defaultMessage="overview.measures.empty_link"
id="overview.measures.empty_link"
values={
Object {
"setting_link": <Link
"learn_more_link": <Link
onlyActiveOnIndex={false}
style={Object {}}
to={
Object {
"pathname": "/project/baseline",
"query": Object {
"id": "my-project",
},
}
}
to="/documentation/user-guide/clean-as-you-code/"
>
settings.new_code_period.category
learn_more
</Link>,
}
}

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

@@ -67,7 +67,7 @@ export class App extends React.PureComponent<Props> {
hasAnalyses={this.props.isPending || this.props.isInProgress}
/>
) : (
<BranchOverview branchLike={branchLike} component={component} />
<BranchOverview branch={branchLike} component={component} />
)}
</>
);

+ 0
- 12
server/sonar-web/src/main/js/helpers/branch-like.ts View File

@@ -59,18 +59,6 @@ export function getBranchLikeKey(branchLike: BranchLike) {
return isPullRequest(branchLike) ? `pull-request-${branchLike.key}` : `branch-${branchLike.name}`;
}

export function getBranchQualityGateColor(status: string) {
let indicatorColor = 'gray';
if (status === 'ERROR') {
indicatorColor = 'red';
} else if (status === 'WARN') {
indicatorColor = 'orange';
} else if (status === 'OK') {
indicatorColor = 'green';
}
return indicatorColor;
}

export function isSameBranchLike(a: BranchLike | undefined, b: BranchLike | undefined) {
// main branches are always equal
if (isMainBranch(a) && isMainBranch(b)) {

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

@@ -2768,7 +2768,8 @@ overview.recent_activity=Recent Activity
overview.measures=Measures
overview.measures.empty_explanation=Measures on New Code will appear after the second analysis of this branch.
overview.measures.empty_link={learn_more_link} about the Clean as You Code approach.
overview.measures.bad_setting.explanation=This branch is configured to use itself as reference branch. It will never have New Code.
overview.measures.same_reference.explanation=This branch is configured to use itself as reference branch. It will never have New Code.
overview.measures.bad_reference.explanation=This branch could not be compared to its reference branch. See the SCM or analysis report for more details.
overview.measures.bad_setting.link=This can be fixed in the {setting_link} setting.
overview.measures.security_hotspots_reviewed=Reviewed


Loading…
Cancel
Save