Ver código fonte

SONAR-12965 Configure Security Review domain in measures page

tags/8.2.0.32929
Jeremy Davis 4 anos atrás
pai
commit
049128b4f1

+ 73
- 0
server/sonar-web/src/main/js/apps/component-measures/__tests__/utils-test.ts Ver arquivo

@@ -17,6 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { ComponentQualifier } from '../../../types/component';
import { MetricKey } from '../../../types/metrics';
import * as utils from '../utils';

@@ -151,3 +152,75 @@ describe('serializeQuery', () => {
expect(utils.serializeQuery(query)).toBe(utils.serializeQuery(query));
});
});

describe('extract measure', () => {
const componentBuilder = (qual: ComponentQualifier): T.ComponentMeasure => {
return {
qualifier: qual,
key: '1',
name: 'TEST',
measures: [
{
metric: 'alert_status',
value: '3.2',
periods: [{ index: 1, value: '0.0' }]
},
{
metric: 'releasability_rating',
value: '3.2',
periods: [{ index: 1, value: '0.0' }]
},
{
metric: 'releasability_effort',
value: '3.2',
periods: [{ index: 1, value: '0.0' }]
}
]
};
};
it('should ban quality gate for app', () => {
const measure = utils.banQualityGateMeasure(componentBuilder(ComponentQualifier.Application));
expect(measure).toHaveLength(0);
});

it('should ban quality gate for portfolio', () => {
const measure = utils.banQualityGateMeasure(componentBuilder(ComponentQualifier.Portfolio));
expect(measure).toHaveLength(3);
});

it('should ban quality gate for file', () => {
const measure = utils.banQualityGateMeasure(componentBuilder(ComponentQualifier.File));
expect(measure).toHaveLength(2);
measure.forEach(({ metric }) => {
expect(['releasability_rating', 'releasability_effort']).toContain(metric);
});
});
});

describe('Component classification', () => {
const componentBuilder = (qual: ComponentQualifier): T.ComponentMeasure => {
return {
qualifier: qual,
key: '1',
name: 'TEST'
};
};

it('should be file type', () => {
[ComponentQualifier.File, ComponentQualifier.TestFile].forEach(qual => {
const component = componentBuilder(qual);
expect(utils.isFileType(component)).toBeTruthy();
});
});

it('should be view type', () => {
[
ComponentQualifier.Portfolio,
ComponentQualifier.SubPortfolio,
ComponentQualifier.Application
].forEach(qual => {
const component = componentBuilder(qual);
expect(utils.isViewType(component)).toBeTruthy();
});
});
});

+ 2
- 12
server/sonar-web/src/main/js/apps/component-measures/components/App.tsx Ver arquivo

@@ -47,6 +47,7 @@ import { BranchLike } from '../../../types/branch-like';
import Sidebar from '../sidebar/Sidebar';
import '../style.css';
import {
banQualityGateMeasure,
getMeasuresPageMetricKeys,
groupByDomains,
hasBubbleChart,
@@ -136,24 +137,13 @@ export class App extends React.PureComponent<Props, State> {

const filteredKeys = getMeasuresPageMetricKeys(metrics, branchLike);

const banQualityGate = ({ measures = [], qualifier }: T.ComponentMeasure) => {
const bannedMetrics: string[] = [];
if (!['VW', 'SVW'].includes(qualifier)) {
bannedMetrics.push('alert_status', 'security_review_rating');
}
if (qualifier === 'APP') {
bannedMetrics.push('releasability_rating', 'releasability_effort');
}
return measures.filter(measure => !bannedMetrics.includes(measure.metric));
};

getMeasuresAndMeta(componentKey, filteredKeys, {
additionalFields: 'periods',
...getBranchLikeQuery(branchLike)
}).then(
({ component, periods }) => {
if (this.mounted) {
const measures = banQualityGate(component).map(measure =>
const measures = banQualityGateMeasure(component).map(measure =>
enhanceMeasure(measure, metrics)
);


+ 16
- 3
server/sonar-web/src/main/js/apps/component-measures/config/domains.ts Ver arquivo

@@ -46,13 +46,26 @@ export const domains: Domains = {
MetricKey.new_vulnerabilities,
MetricKey.new_security_rating,
MetricKey.new_security_remediation_effort,
MetricKey.new_security_hotspots,

'overall_category',
MetricKey.vulnerabilities,
MetricKey.security_rating,
MetricKey.security_remediation_effort,
MetricKey.security_hotspots
MetricKey.security_remediation_effort
]
},

SecurityReview: {
categories: ['new_code_category', 'overall_category'],
order: [
'new_code_category',
MetricKey.new_security_hotspots,
MetricKey.new_security_review_rating,
MetricKey.new_security_hotspots_reviewed,

'overall_category',
MetricKey.security_hotspots,
MetricKey.security_review_rating,
MetricKey.security_hotspots_reviewed
]
},


+ 24
- 2
server/sonar-web/src/main/js/apps/component-measures/utils.ts Ver arquivo

@@ -24,6 +24,7 @@ import { enhanceMeasure } from '../../components/measure/utils';
import { isBranch, isPullRequest } from '../../helpers/branch-like';
import { getDisplayMetrics, isDiffMetric } from '../../helpers/measures';
import { BranchLike } from '../../types/branch-like';
import { ComponentQualifier } from '../../types/component';
import { bubbles } from './config/bubbles';
import { domains } from './config/domains';

@@ -36,6 +37,7 @@ export const KNOWN_DOMAINS = [
'Releasability',
'Reliability',
'Security',
'SecurityReview',
'Maintainability',
'Coverage',
'Duplications',
@@ -103,11 +105,31 @@ export function enhanceComponent(
}

export function isFileType(component: T.ComponentMeasure): boolean {
return ['FIL', 'UTS'].includes(component.qualifier);
return [ComponentQualifier.File, ComponentQualifier.TestFile].includes(
component.qualifier as ComponentQualifier
);
}

export function isViewType(component: T.ComponentMeasure): boolean {
return ['VW', 'SVW', 'APP'].includes(component.qualifier);
return [
ComponentQualifier.Portfolio,
ComponentQualifier.SubPortfolio,
ComponentQualifier.Application
].includes(component.qualifier as ComponentQualifier);
}

export function banQualityGateMeasure({
measures = [],
qualifier
}: T.ComponentMeasure): T.Measure[] {
const bannedMetrics: string[] = [];
if (ComponentQualifier.Portfolio !== qualifier && ComponentQualifier.SubPortfolio !== qualifier) {
bannedMetrics.push('alert_status');
}
if (qualifier === ComponentQualifier.Application) {
bannedMetrics.push('releasability_rating', 'releasability_effort');
}
return measures.filter(measure => !bannedMetrics.includes(measure.metric));
}

export const groupByDomains = memoize((measures: T.MeasureEnhanced[]) => {

+ 1
- 1
server/sonar-web/src/main/js/components/SourceViewer/components/MeasuresOverlay.tsx Ver arquivo

@@ -329,7 +329,7 @@ export default class MeasuresOverlay extends React.PureComponent<Props, State> {
<div className="measures-viewer-card" key={domain}>
<div className="measures">
<div className="measure measure-big">
<span className="measure-name">{domain}</span>
<span className="measure-name">{translate('metric_domain', domain)}</span>
</div>
{sortBy(
measures.filter(measure => measure.value !== undefined),

+ 9
- 9
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/MeasuresOverlay-test.tsx.snap Ver arquivo

@@ -1146,7 +1146,7 @@ exports[`should render source file 2`] = `
<span
className="measure-name"
>
Complexity
metric_domain.Complexity
</span>
</div>
<MeasuresOverlayMeasure
@@ -1190,7 +1190,7 @@ exports[`should render source file 2`] = `
<span
className="measure-name"
>
Size
metric_domain.Size
</span>
</div>
<MeasuresOverlayMeasure
@@ -1312,7 +1312,7 @@ exports[`should render source file 2`] = `
<span
className="measure-name"
>
Coverage
metric_domain.Coverage
</span>
</div>
<MeasuresOverlayMeasure
@@ -1382,7 +1382,7 @@ exports[`should render source file 2`] = `
<span
className="measure-name"
>
Reliability
metric_domain.Reliability
</span>
</div>
<MeasuresOverlayMeasure
@@ -1430,7 +1430,7 @@ exports[`should render source file 2`] = `
<span
className="measure-name"
>
Security
metric_domain.Security
</span>
</div>
<MeasuresOverlayMeasure
@@ -1474,7 +1474,7 @@ exports[`should render source file 2`] = `
<span
className="measure-name"
>
Tests
metric_domain.Tests
</span>
</div>
<MeasuresOverlayMeasure
@@ -1544,7 +1544,7 @@ exports[`should render source file 2`] = `
<span
className="measure-name"
>
Issues
metric_domain.Issues
</span>
</div>
<MeasuresOverlayMeasure
@@ -1601,7 +1601,7 @@ exports[`should render source file 2`] = `
<span
className="measure-name"
>
Duplications
metric_domain.Duplications
</span>
</div>
<MeasuresOverlayMeasure
@@ -1671,7 +1671,7 @@ exports[`should render source file 2`] = `
<span
className="measure-name"
>
Maintainability
metric_domain.Maintainability
</span>
</div>
<MeasuresOverlayMeasure

+ 3
- 0
server/sonar-web/src/main/js/types/metrics.ts Ver arquivo

@@ -96,8 +96,10 @@ export enum MetricKey {
new_reliability_rating = 'new_reliability_rating',
new_reliability_remediation_effort = 'new_reliability_remediation_effort',
new_security_hotspots = 'new_security_hotspots',
new_security_hotspots_reviewed = 'new_security_hotspots_reviewed',
new_security_rating = 'new_security_rating',
new_security_remediation_effort = 'new_security_remediation_effort',
new_security_review_rating = 'new_security_review_rating',
new_sqale_debt_ratio = 'new_sqale_debt_ratio',
new_technical_debt = 'new_technical_debt',
new_uncovered_conditions = 'new_uncovered_conditions',
@@ -118,6 +120,7 @@ export enum MetricKey {
reliability_remediation_effort = 'reliability_remediation_effort',
reopened_issues = 'reopened_issues',
security_hotspots = 'security_hotspots',
security_hotspots_reviewed = 'security_hotspots_reviewed',
security_rating = 'security_rating',
security_rating_effort = 'security_rating_effort',
security_remediation_effort = 'security_remediation_effort',

+ 9
- 4
sonar-core/src/main/resources/org/sonar/l10n/core.properties Ver arquivo

@@ -2113,14 +2113,18 @@ metric.new_security_hotspots.name=New Security Hotspots
metric.new_security_hotspots.short_name=Security Hotspots
metric.new_security_hotspots_reviewed.description=Security Hotspots Reviewed on New Code
metric.new_security_hotspots_reviewed.name=Security Hotspots Reviewed on New Code
metric.new_security_hotspots_reviewed.short_name=Security Hotspots Reviewed
metric.new_security_rating.description=Security rating on new code
metric.new_security_rating.name=Security Rating on New Code
metric.new_security_rating.extra_short_name=Rating
metric.new_security_review_rating.description=Security Review rating on new code
metric.new_security_review_rating.name=Security Review Rating on New Code
metric.new_security_remediation_effort.description=Security remediation effort on new code
metric.new_security_remediation_effort.name=Security Remediation Effort on New Code
metric.new_security_remediation_effort.extra_short_name=Remediation Effort
metric.new_security_review_rating.description=Security Review Rating on New Code
metric.new_security_review_rating.name=Security Review Rating on New Code
metric.new_security_review_rating.extra_short_name=Rating
metric.new_sqale_debt_ratio.description=Technical Debt Ratio of new/changed code.
metric.new_sqale_debt_ratio.name=Technical Debt Ratio on New Code
metric.new_sqale_debt_ratio.short_name=Debt Ratio on new code
@@ -2217,6 +2221,9 @@ metric.rfc_distribution.description=Class distribution /RFC
metric.rfc_distribution.name=Class Distribution / RFC
metric.security_hotspots.description=Security Hotspots
metric.security_hotspots.name=Security Hotspots
metric.security_hotspots_reviewed.description=Security Hotspots Reviewed
metric.security_hotspots_reviewed.name=Security Hotspots Reviewed
metric.security_hotspots_reviewed.extra_short_name=Hotspots Reviewed
metric.security_rating.description=Security rating
metric.security_rating.name=Security Rating
metric.security_rating.extra_short_name=Rating
@@ -2230,10 +2237,7 @@ metric.security_remediation_effort.name=Security Remediation Effort
metric.security_remediation_effort.extra_short_name=Remediation Effort
metric.security_review_rating.description=Security Review Rating
metric.security_review_rating.name=Security Review Rating
metric.security_review_rating.extra_short_name=Review Rating
metric.security_hotspots_reviewed.description=Security Hotspots Reviewed
metric.security_hotspots_reviewed.name=Security Hotspots Reviewed
metric.security_hotspots_reviewed.extra_short_name=Hotspots Reviewed
metric.security_review_rating.extra_short_name=Rating
metric.skipped_tests.description=Number of skipped unit tests
metric.skipped_tests.name=Skipped Unit Tests
metric.skipped_tests.short_name=Skipped
@@ -2861,6 +2865,7 @@ component_measures.overview.Duplications.description=See duplications' long-term
component_measures.domain_facets.Reliability.help=Issues in this domain mark code where you will get behavior other than what was expected.
component_measures.domain_facets.Maintainability.help=Issues in this domain mark code that will be more difficult to update competently than it should.
component_measures.domain_facets.Security.help=Issues in this domain mark potential weaknesses to hackers.
component_measures.domain_facets.SecurityReview.help=This domain represents potential security risks in the form of hotspots and their review status.
component_measures.domain_facets.Complexity.help=How simple or complicated the control flow of the application is. Cyclomatic Complexity measures the minimum number of test cases required for full test coverage. Cognitive Complexity is a measure of how difficult the application is to understand

component_measures.facet_category.new_code_category=On new code

Carregando…
Cancelar
Salvar