Browse Source

SONAR-21766 Project list uses old measures if there are no new ones

tags/10.5.0.89998
Viktor Vorona 2 months ago
parent
commit
e06cde02ac

+ 22
- 6
server/sonar-web/src/main/js/apps/projects/components/project-card/ProjectCard.tsx View File

@@ -34,6 +34,7 @@ import {
themeBorder,
themeColor,
} from 'design-system';
import { isEmpty } from 'lodash';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import Favorite from '../../../../components/controls/Favorite';
@@ -66,6 +67,15 @@ function renderFirstLine(
isNewCode: boolean,
) {
const { analysisDate, isFavorite, key, measures, name, qualifier, tags, visibility } = project;
const awaitingScan =
[
MetricKey.reliability_issues,
MetricKey.maintainability_issues,
MetricKey.security_issues,
].every((key) => measures[key] === undefined) &&
!isNewCode &&
!isEmpty(analysisDate) &&
measures.ncloc !== undefined;
const formatted = formatMeasure(measures[MetricKey.alert_status], MetricType.Level);
const qualityGateLabel = translateWithParameters('overview.quality_gate_x', formatted);
return (
@@ -112,6 +122,16 @@ function renderFirstLine(
<Badge className="sw-ml-2">{translate('visibility', visibility)}</Badge>
</span>
</Tooltip>

{awaitingScan && !isNewCode && !isEmpty(analysisDate) && measures.ncloc !== undefined && (
<Tooltip overlay={translate(`projects.awaiting_scan.description.${qualifier}`)}>
<span>
<Badge variant="new" className="sw-ml-2">
{translate('projects.awaiting_scan')}
</Badge>
</span>
</Tooltip>
)}
</div>

{isDefined(analysisDate) && analysisDate !== '' && (
@@ -212,11 +232,7 @@ function renderSecondLine(
) {
const { analysisDate, key, leakPeriodDate, measures, qualifier, isScannable } = project;

if (
isDefined(analysisDate) &&
analysisDate !== '' &&
(!isNewCode || (isDefined(leakPeriodDate) && leakPeriodDate !== ''))
) {
if (!isEmpty(analysisDate) && (!isNewCode || !isEmpty(leakPeriodDate))) {
return (
<ProjectCardMeasures
measures={measures}
@@ -235,7 +251,7 @@ function renderSecondLine(
</Note>

{qualifier !== ComponentQualifier.Application &&
(analysisDate === undefined || analysisDate === '') &&
isEmpty(analysisDate) &&
isLoggedIn(currentUser) &&
isScannable && (
<Link className="sw-ml-2 sw-body-sm-highlight" to={getProjectUrl(key)}>

+ 12
- 3
server/sonar-web/src/main/js/apps/projects/components/project-card/ProjectCardMeasures.tsx View File

@@ -121,19 +121,28 @@ function renderRatings(props: ProjectCardMeasuresProps) {
{
iconLabel: translate(`metric.${MetricKey.security_issues}.short_name`),
noShrink: true,
metricKey: MetricKey.security_issues,
metricKey:
measures[MetricKey.security_issues] !== undefined
? MetricKey.security_issues
: MetricKey.vulnerabilities,
metricRatingKey: MetricKey.security_rating,
metricType: MetricType.ShortInteger,
},
{
iconLabel: translate(`metric.${MetricKey.reliability_issues}.short_name`),
metricKey: MetricKey.reliability_issues,
metricKey:
measures[MetricKey.reliability_issues] !== undefined
? MetricKey.reliability_issues
: MetricKey.bugs,
metricRatingKey: MetricKey.reliability_rating,
metricType: MetricType.ShortInteger,
},
{
iconLabel: translate(`metric.${MetricKey.maintainability_issues}.short_name`),
metricKey: MetricKey.maintainability_issues,
metricKey:
measures[MetricKey.maintainability_issues] !== undefined
? MetricKey.maintainability_issues
: MetricKey.code_smells,
metricRatingKey: MetricKey.sqale_rating,
metricType: MetricType.ShortInteger,
},

+ 91
- 4
server/sonar-web/src/main/js/apps/projects/components/project-card/__tests__/ProjectCard-test.tsx View File

@@ -22,15 +22,18 @@ import React from 'react';
import { mockCurrentUser, mockLoggedInUser } from '../../../../../helpers/testMocks';
import { renderComponent } from '../../../../../helpers/testReactTestingUtils';
import { ComponentQualifier, Visibility } from '../../../../../types/component';
import { MetricKey } from '../../../../../types/metrics';
import { CurrentUser } from '../../../../../types/users';
import { Project } from '../../../types';
import ProjectCard from '../ProjectCard';

const MEASURES = {
alert_status: 'OK',
reliability_rating: '1.0',
sqale_rating: '1.0',
new_bugs: '12',
[MetricKey.ncloc]: '1000',
[MetricKey.alert_status]: 'OK',
[MetricKey.reliability_rating]: '1.0',
[MetricKey.security_rating]: '1.0',
[MetricKey.sqale_rating]: '1.0',
[MetricKey.new_bugs]: '12',
};

const PROJECT: Project = {
@@ -81,6 +84,90 @@ it('should display applications', () => {
expect(screen.getByLabelText('qualifier.APP')).toBeInTheDocument();
});

it('should not display awaiting analysis badge and do not display old measures', () => {
renderProjectCard({
...PROJECT,
measures: {
...MEASURES,
[MetricKey.security_issues]: JSON.stringify({ LOW: 0, MEDIUM: 0, HIGH: 1, total: 1 }),
[MetricKey.reliability_issues]: JSON.stringify({ LOW: 0, MEDIUM: 2, HIGH: 0, total: 2 }),
[MetricKey.maintainability_issues]: JSON.stringify({ LOW: 3, MEDIUM: 0, HIGH: 0, total: 3 }),
[MetricKey.code_smells]: '4',
[MetricKey.bugs]: '5',
[MetricKey.vulnerabilities]: '6',
},
});
expect(screen.queryByRole('status', { name: 'projects.awaiting_scan' })).not.toBeInTheDocument();
expect(screen.getByText('1')).toBeInTheDocument();
expect(screen.getByText('2')).toBeInTheDocument();
expect(screen.getByText('3')).toBeInTheDocument();
expect(screen.queryByText('4')).not.toBeInTheDocument();
expect(screen.queryByText('5')).not.toBeInTheDocument();
expect(screen.queryByText('6')).not.toBeInTheDocument();
});

it('should display awaiting analysis badge and show the old measures', async () => {
renderProjectCard({
...PROJECT,
measures: {
...MEASURES,
[MetricKey.code_smells]: '4',
[MetricKey.bugs]: '5',
[MetricKey.vulnerabilities]: '6',
},
});
expect(screen.getByRole('status', { name: 'projects.awaiting_scan' })).toBeInTheDocument();
await expect(
screen.getByRole('status', { name: 'projects.awaiting_scan' }),
).toHaveATooltipWithContent('projects.awaiting_scan.description.TRK');
expect(screen.getByText('4')).toBeInTheDocument();
expect(screen.getByText('5')).toBeInTheDocument();
expect(screen.getByText('6')).toBeInTheDocument();
});

it('should display awaiting analysis badge and show the old measures for Application', async () => {
renderProjectCard({
...PROJECT,
qualifier: ComponentQualifier.Application,
measures: {
...MEASURES,
[MetricKey.code_smells]: '4',
[MetricKey.bugs]: '5',
[MetricKey.vulnerabilities]: '6',
},
});
expect(screen.getByRole('status', { name: 'projects.awaiting_scan' })).toBeInTheDocument();
await expect(
screen.getByRole('status', { name: 'projects.awaiting_scan' }),
).toHaveATooltipWithContent('projects.awaiting_scan.description.APP');
expect(screen.getByText('4')).toBeInTheDocument();
expect(screen.getByText('5')).toBeInTheDocument();
expect(screen.getByText('6')).toBeInTheDocument();
});

it('should not display awaiting analysis badge if project is not analyzed', () => {
renderProjectCard({
...PROJECT,
analysisDate: undefined,
});
expect(screen.queryByRole('status', { name: 'projects.awaiting_scan' })).not.toBeInTheDocument();
});

it('should not display awaiting analysis badge if project does not have lines of code', () => {
renderProjectCard({
...PROJECT,
measures: {
...(({ [MetricKey.ncloc]: _, ...rest }) => rest)(MEASURES),
},
});
expect(screen.queryByRole('status', { name: 'projects.awaiting_scan' })).not.toBeInTheDocument();
});

it('should not display awaiting analysis badge if it is a new code filter', () => {
renderProjectCard(PROJECT, undefined, 'leak');
expect(screen.queryByRole('status', { name: 'projects.awaiting_scan' })).not.toBeInTheDocument();
});

it('should display 3 aplication', () => {
renderProjectCard({
...PROJECT,

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

@@ -91,10 +91,13 @@ const PAGE_SIZE = 50;
export const METRICS = [
MetricKey.alert_status,
MetricKey.reliability_issues,
MetricKey.bugs,
MetricKey.reliability_rating,
MetricKey.security_issues,
MetricKey.vulnerabilities,
MetricKey.security_rating,
MetricKey.maintainability_issues,
MetricKey.code_smells,
MetricKey.sqale_rating,
MetricKey.security_hotspots_reviewed,
MetricKey.security_review_rating,

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

@@ -1329,6 +1329,10 @@ projects.sort.size=by size (smallest first)
projects.sort.-size=by size (biggest first)
projects.show_more=Show more projects
projects.security_hotspots_reviewed=Hotspots Reviewed
projects.awaiting_scan=Change in Calculation
projects.awaiting_scan.description.TRK=The way Security, Reliability, and Maintainability counts are calculated has changed. The values currently displayed may change after the next analysis.
projects.awaiting_scan.description.APP=The way Security, Reliability, and Maintainability counts are calculated has changed. The values currently displayed may change after all projects in this application have been analyzed.


#------------------------------------------------------------------------------
#

Loading…
Cancel
Save