diff options
author | Wouter Admiraal <wouter.admiraal@sonarsource.com> | 2019-12-17 16:55:03 +0100 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2020-02-10 20:46:14 +0100 |
commit | 26f66a70c8de871cc93f234398412966f160b1b8 (patch) | |
tree | 708aea302109ba6f9b296001f7b60e36fe80010a /server | |
parent | ea0e05cedbe604baa4b9ad50148353d7356237c2 (diff) | |
download | sonarqube-26f66a70c8de871cc93f234398412966f160b1b8.tar.gz sonarqube-26f66a70c8de871cc93f234398412966f160b1b8.zip |
Extract metric keys to a global Enum, simplify mocking
Diffstat (limited to 'server')
21 files changed, 546 insertions, 289 deletions
diff --git a/server/sonar-web/src/main/js/apps/code/components/__tests__/__snapshots__/Component-test.tsx.snap b/server/sonar-web/src/main/js/apps/code/components/__tests__/__snapshots__/Component-test.tsx.snap index 138b237b2e5..2bfb8507609 100644 --- a/server/sonar-web/src/main/js/apps/code/components/__tests__/__snapshots__/Component-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/code/components/__tests__/__snapshots__/Component-test.tsx.snap @@ -75,9 +75,9 @@ exports[`should render correctly 1`] = ` } metric={ Object { - "id": "coverage", + "id": "bugs", "key": "bugs", - "name": "Coverage", + "name": "Bugs", "type": "PERCENT", } } @@ -111,9 +111,9 @@ exports[`should render correctly 1`] = ` } metric={ Object { - "id": "coverage", + "id": "vulnerabilities", "key": "vulnerabilities", - "name": "Coverage", + "name": "Vulnerabilities", "type": "PERCENT", } } @@ -205,9 +205,9 @@ exports[`should render correctly for a file 1`] = ` } metric={ Object { - "id": "coverage", + "id": "bugs", "key": "bugs", - "name": "Coverage", + "name": "Bugs", "type": "PERCENT", } } @@ -239,9 +239,9 @@ exports[`should render correctly for a file 1`] = ` } metric={ Object { - "id": "coverage", + "id": "vulnerabilities", "key": "vulnerabilities", - "name": "Coverage", + "name": "Vulnerabilities", "type": "PERCENT", } } diff --git a/server/sonar-web/src/main/js/apps/code/utils.ts b/server/sonar-web/src/main/js/apps/code/utils.ts index 88f97c1929f..675c33e0a1e 100644 --- a/server/sonar-web/src/main/js/apps/code/utils.ts +++ b/server/sonar-web/src/main/js/apps/code/utils.ts @@ -20,6 +20,7 @@ import { getBreadcrumbs, getChildren, getComponent } from '../../api/components'; import { getBranchLikeQuery, isPullRequest } from '../../helpers/branch-like'; import { BranchLike } from '../../types/branch-like'; +import { MetricKey } from '../../types/metrics'; import { addComponent, addComponentBreadcrumbs, @@ -30,34 +31,34 @@ import { } from './bucket'; const METRICS = [ - 'ncloc', - 'bugs', - 'vulnerabilities', - 'code_smells', - 'security_hotspots', - 'coverage', - 'duplicated_lines_density' + MetricKey.ncloc, + MetricKey.bugs, + MetricKey.vulnerabilities, + MetricKey.code_smells, + MetricKey.security_hotspots, + MetricKey.coverage, + MetricKey.duplicated_lines_density ]; -const APPLICATION_METRICS = ['alert_status', ...METRICS]; +const APPLICATION_METRICS = [MetricKey.alert_status, ...METRICS]; const PORTFOLIO_METRICS = [ - 'releasability_rating', - 'reliability_rating', - 'security_rating', - 'security_review_rating', - 'sqale_rating', - 'ncloc' + MetricKey.releasability_rating, + MetricKey.reliability_rating, + MetricKey.security_rating, + MetricKey.security_review_rating, + MetricKey.sqale_rating, + MetricKey.ncloc ]; const LEAK_METRICS = [ - 'new_lines', - 'bugs', - 'vulnerabilities', - 'code_smells', - 'security_hotspots', - 'new_coverage', - 'new_duplicated_lines_density' + MetricKey.new_lines, + MetricKey.bugs, + MetricKey.vulnerabilities, + MetricKey.code_smells, + MetricKey.security_hotspots, + MetricKey.new_coverage, + MetricKey.new_duplicated_lines_density ]; const PAGE_SIZE = 100; @@ -107,7 +108,7 @@ export function getCodeMetrics( ) { if (['VW', 'SVW'].includes(qualifier)) { const metrics = [...PORTFOLIO_METRICS]; - return options.includeQGStatus ? metrics.concat('alert_status') : metrics; + return options.includeQGStatus ? metrics.concat(MetricKey.alert_status) : metrics; } if (qualifier === 'APP') { return [...APPLICATION_METRICS]; diff --git a/server/sonar-web/src/main/js/apps/component-measures/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/component-measures/__tests__/utils-test.ts index baec3b1404f..5b59046f0dc 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/__tests__/utils-test.ts +++ b/server/sonar-web/src/main/js/apps/component-measures/__tests__/utils-test.ts @@ -17,13 +17,14 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { MetricKey } from '../../../types/metrics'; import * as utils from '../utils'; const MEASURES = [ { metric: { id: '1', - key: 'lines_to_cover', + key: MetricKey.lines_to_cover, type: 'INT', name: 'Lines to Cover', domain: 'Coverage' @@ -35,7 +36,7 @@ const MEASURES = [ { metric: { id: '2', - key: 'coverage', + key: MetricKey.coverage, type: 'PERCENT', name: 'Coverage', domain: 'Coverage' @@ -47,7 +48,7 @@ const MEASURES = [ { metric: { id: '3', - key: 'duplicated_lines_density', + key: MetricKey.duplicated_lines_density, type: 'PERCENT', name: 'Duplicated Lines (%)', domain: 'Duplications' @@ -62,9 +63,14 @@ describe('filterMeasures', () => { it('should exclude banned measures', () => { expect( utils.filterMeasures([ - { metric: { id: '1', key: 'bugs', name: 'Bugs', type: 'INT' } }, + { metric: { id: '1', key: MetricKey.bugs, name: 'Bugs', type: 'INT' } }, { - metric: { id: '2', key: 'critical_violations', name: 'Critical Violations', type: 'INT' } + metric: { + id: '2', + key: MetricKey.critical_violations, + name: 'Critical Violations', + type: 'INT' + } } ]) ).toHaveLength(1); @@ -76,13 +82,23 @@ describe('sortMeasures', () => { expect( utils.sortMeasures('Reliability', [ { - metric: { id: '1', key: 'reliability_remediation_effort', name: 'new_bugs', type: 'INT' } + metric: { + id: '1', + key: MetricKey.reliability_remediation_effort, + name: 'new_bugs', + type: 'INT' + } }, { - metric: { id: '2', key: 'new_reliability_remediation_effort', name: 'bugs', type: 'INT' } + metric: { + id: '2', + key: MetricKey.new_reliability_remediation_effort, + name: 'bugs', + type: 'INT' + } }, - { metric: { id: '3', key: 'new_bugs', name: 'new_bugs', type: 'INT' } }, - { metric: { id: '4', key: 'bugs', name: 'bugs', type: 'INT' } }, + { metric: { id: '3', key: MetricKey.new_bugs, name: 'new_bugs', type: 'INT' } }, + { metric: { id: '4', key: MetricKey.bugs, name: 'bugs', type: 'INT' } }, 'overall_category' ]) ).toMatchSnapshot(); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.tsx index c4c40940def..73e6a4c22e5 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/MeasureContent.tsx @@ -30,6 +30,7 @@ import { getBranchLikeQuery, isSameBranchLike } from '../../../helpers/branch-li import { getPeriodValue, isDiffMetric } from '../../../helpers/measures'; import { getProjectUrl } from '../../../helpers/urls'; import { BranchLike } from '../../../types/branch-like'; +import { MetricKey } from '../../../types/metrics'; import { complementary } from '../config/complementary'; import FilesView from '../drilldown/FilesView'; import TreeMapView from '../drilldown/TreeMapView'; @@ -100,7 +101,7 @@ export default class MeasureContent extends React.PureComponent<Props, State> { ); const componentKey = this.props.selected || this.props.rootComponent.key; const baseComponentMetrics = [this.props.requestedMetric.key]; - if (this.props.requestedMetric.key === 'ncloc') { + if (this.props.requestedMetric.key === MetricKey.ncloc) { baseComponentMetrics.push('ncloc_language_distribution'); } Promise.all([ diff --git a/server/sonar-web/src/main/js/apps/component-measures/config/bubbles.ts b/server/sonar-web/src/main/js/apps/component-measures/config/bubbles.ts index bc87c9bc4ca..faa31be14f1 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/config/bubbles.ts +++ b/server/sonar-web/src/main/js/apps/component-measures/config/bubbles.ts @@ -17,6 +17,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { MetricKey } from '../../../types/metrics'; + export const bubbles: { [domain: string]: { x: string; @@ -27,30 +29,39 @@ export const bubbles: { }; } = { Reliability: { - x: 'ncloc', - y: 'reliability_remediation_effort', - size: 'bugs', - colors: ['reliability_rating'] + x: MetricKey.ncloc, + y: MetricKey.reliability_remediation_effort, + size: MetricKey.bugs, + colors: [MetricKey.reliability_rating] }, Security: { - x: 'ncloc', - y: 'security_remediation_effort', - size: 'vulnerabilities', - colors: ['security_rating'] + x: MetricKey.ncloc, + y: MetricKey.security_remediation_effort, + size: MetricKey.vulnerabilities, + colors: [MetricKey.security_rating] }, Maintainability: { - x: 'ncloc', - y: 'sqale_index', - size: 'code_smells', - colors: ['sqale_rating'] + x: MetricKey.ncloc, + y: MetricKey.sqale_index, + size: MetricKey.code_smells, + colors: [MetricKey.sqale_rating] + }, + Coverage: { + x: MetricKey.complexity, + y: MetricKey.coverage, + size: MetricKey.uncovered_lines, + yDomain: [100, 0] + }, + Duplications: { + x: MetricKey.ncloc, + y: MetricKey.duplicated_lines, + size: MetricKey.duplicated_blocks }, - Coverage: { x: 'complexity', y: 'coverage', size: 'uncovered_lines', yDomain: [100, 0] }, - Duplications: { x: 'ncloc', y: 'duplicated_lines', size: 'duplicated_blocks' }, project_overview: { - x: 'sqale_index', - y: 'coverage', - size: 'ncloc', - colors: ['reliability_rating', 'security_rating'], + x: MetricKey.sqale_index, + y: MetricKey.coverage, + size: MetricKey.ncloc, + colors: [MetricKey.reliability_rating, MetricKey.security_rating], yDomain: [100, 0] } }; diff --git a/server/sonar-web/src/main/js/apps/component-measures/config/domains.ts b/server/sonar-web/src/main/js/apps/component-measures/config/domains.ts index a9a24eca4e4..eb9d15604b2 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/config/domains.ts +++ b/server/sonar-web/src/main/js/apps/component-measures/config/domains.ts @@ -17,6 +17,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { MetricKey } from '../../../types/metrics'; + interface Domains { [domain: string]: { categories?: string[]; order: string[] }; } @@ -26,14 +28,14 @@ export const domains: Domains = { categories: ['new_code_category', 'overall_category'], order: [ 'new_code_category', - 'new_bugs', - 'new_reliability_rating', - 'new_reliability_remediation_effort', + MetricKey.new_bugs, + MetricKey.new_reliability_rating, + MetricKey.new_reliability_remediation_effort, 'overall_category', - 'bugs', - 'reliability_rating', - 'reliability_remediation_effort' + MetricKey.bugs, + MetricKey.reliability_rating, + MetricKey.reliability_remediation_effort ] }, @@ -41,16 +43,16 @@ export const domains: Domains = { categories: ['new_code_category', 'overall_category'], order: [ 'new_code_category', - 'new_vulnerabilities', - 'new_security_rating', - 'new_security_remediation_effort', - 'new_security_hotspots', + MetricKey.new_vulnerabilities, + MetricKey.new_security_rating, + MetricKey.new_security_remediation_effort, + MetricKey.new_security_hotspots, 'overall_category', - 'vulnerabilities', - 'security_rating', - 'security_remediation_effort', - 'security_hotspots' + MetricKey.vulnerabilities, + MetricKey.security_rating, + MetricKey.security_remediation_effort, + MetricKey.security_hotspots ] }, @@ -58,17 +60,17 @@ export const domains: Domains = { categories: ['new_code_category', 'overall_category'], order: [ 'new_code_category', - 'new_code_smells', - 'new_technical_debt', - 'new_sqale_debt_ratio', - 'new_maintainability_rating', + MetricKey.new_code_smells, + MetricKey.new_technical_debt, + MetricKey.new_sqale_debt_ratio, + MetricKey.new_maintainability_rating, 'overall_category', - 'code_smells', - 'sqale_index', - 'sqale_debt_ratio', - 'sqale_rating', - 'effort_to_reach_maintainability_rating_a' + MetricKey.code_smells, + MetricKey.sqale_index, + MetricKey.sqale_debt_ratio, + MetricKey.sqale_rating, + MetricKey.effort_to_reach_maintainability_rating_a ] }, @@ -76,31 +78,30 @@ export const domains: Domains = { categories: ['new_code_category', 'overall_category', 'tests_category'], order: [ 'new_code_category', - 'new_coverage', - 'new_lines_to_cover', - 'new_uncovered_lines', - 'new_line_coverage', - 'new_conditions_to_cover', - 'new_uncovered_conditions', - 'new_branch_coverage', + MetricKey.new_coverage, + MetricKey.new_lines_to_cover, + MetricKey.new_uncovered_lines, + MetricKey.new_line_coverage, + MetricKey.new_conditions_to_cover, + MetricKey.new_uncovered_conditions, + MetricKey.new_branch_coverage, 'overall_category', - 'coverage', - 'lines_to_cover', - 'uncovered_lines', - 'line_coverage', - 'conditions_to_cover', - 'uncovered_conditions', - 'branch_coverage', + MetricKey.coverage, + MetricKey.lines_to_cover, + MetricKey.uncovered_lines, + MetricKey.line_coverage, + MetricKey.conditions_to_cover, + MetricKey.uncovered_conditions, + MetricKey.branch_coverage, 'tests_category', - 'tests', - 'test_success', - 'test_errors', - 'test_failures', - 'skipped_tests', - 'test_success_density', - 'test_execution_time' + MetricKey.tests, + MetricKey.test_errors, + MetricKey.test_failures, + MetricKey.skipped_tests, + MetricKey.test_success_density, + MetricKey.test_execution_time ] }, @@ -108,29 +109,29 @@ export const domains: Domains = { categories: ['new_code_category', 'overall_category'], order: [ 'new_code_category', - 'new_duplicated_lines_density', - 'new_duplicated_lines', - 'new_duplicated_blocks', + MetricKey.new_duplicated_lines_density, + MetricKey.new_duplicated_lines, + MetricKey.new_duplicated_blocks, 'overall_category', - 'duplicated_lines_density', - 'duplicated_lines', - 'duplicated_blocks', - 'duplicated_files' + MetricKey.duplicated_lines_density, + MetricKey.duplicated_lines, + MetricKey.duplicated_blocks, + MetricKey.duplicated_files ] }, Size: { order: [ - 'new_lines', - - 'ncloc', - 'lines', - 'statements', - 'functions', - 'classes', - 'files', - 'directories' + MetricKey.new_lines, + + MetricKey.ncloc, + MetricKey.lines, + MetricKey.statements, + MetricKey.functions, + MetricKey.classes, + MetricKey.files, + MetricKey.directories ] }, @@ -144,23 +145,23 @@ export const domains: Domains = { Issues: { order: [ - 'new_violations', - 'new_blocker_violations', - 'new_critical_violations', - 'new_major_violations', - 'new_minor_violations', - 'new_info_violations', - - 'violations', - 'blocker_violations', - 'critical_violations', - 'major_violations', - 'minor_violations', - 'info_violations', - 'open_issues', - 'reopened_issues', - 'confirmed_issues', - 'false_positive_issues' + MetricKey.new_violations, + MetricKey.new_blocker_violations, + MetricKey.new_critical_violations, + MetricKey.new_major_violations, + MetricKey.new_minor_violations, + MetricKey.new_info_violations, + + MetricKey.violations, + MetricKey.blocker_violations, + MetricKey.critical_violations, + MetricKey.major_violations, + MetricKey.minor_violations, + MetricKey.info_violations, + MetricKey.open_issues, + MetricKey.reopened_issues, + MetricKey.confirmed_issues, + MetricKey.false_positive_issues ] } }; diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/TreeMapView.tsx b/server/sonar-web/src/main/js/apps/component-measures/drilldown/TreeMapView.tsx index c7904688e52..ff9c186403f 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/TreeMapView.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/TreeMapView.tsx @@ -34,6 +34,7 @@ import { colors } from '../../../app/theme'; import ColorBoxLegend from '../../../components/charts/ColorBoxLegend'; import { isDiffMetric } from '../../../helpers/measures'; import { BranchLike } from '../../../types/branch-like'; +import { MetricKey } from '../../../types/metrics'; import EmptyResult from './EmptyResult'; interface Props { @@ -207,7 +208,7 @@ export default class TreeMapView extends React.PureComponent<Props, State> { 'component_measures.legend.size_x', translate( 'metric', - sizeMeasure && sizeMeasure.metric ? sizeMeasure.metric.key : 'ncloc', + sizeMeasure && sizeMeasure.metric ? sizeMeasure.metric.key : MetricKey.ncloc, 'name' ) )} diff --git a/server/sonar-web/src/main/js/apps/overview/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/overview/__tests__/utils-test.ts index fced030fc86..927b36415e2 100644 --- a/server/sonar-web/src/main/js/apps/overview/__tests__/utils-test.ts +++ b/server/sonar-web/src/main/js/apps/overview/__tests__/utils-test.ts @@ -33,7 +33,7 @@ describe('getThreshold', () => { getThreshold( [ { - metric: mockMetric({ key: 'quality_gate_details' }), + metric: mockMetric({ key: MetricKey.quality_gate_details }), value: 'badly typed json should fail' } ], @@ -45,23 +45,23 @@ describe('getThreshold', () => { }); it('should return the threshold for the right metric', () => { - expect(getThreshold([mockMeasure()], 'new_coverage')).toBe(85); - expect(getThreshold([mockMeasure()], 'new_duplicated_lines_density')).toBe(5); + expect(getThreshold([mockMeasure()], MetricKey.new_coverage)).toBe(85); + expect(getThreshold([mockMeasure()], MetricKey.new_duplicated_lines_density)).toBe(5); }); }); function mockMeasure() { return mockMeasureEnhanced({ - metric: mockMetric({ key: 'quality_gate_details' }), + metric: mockMetric({ key: MetricKey.quality_gate_details }), value: JSON.stringify({ conditions: [ mockQualityGateStatusCondition({ - metric: 'new_coverage', + metric: MetricKey.new_coverage, level: 'ERROR', error: '85' }), mockQualityGateStatusCondition({ - metric: 'new_duplicated_lines_density', + metric: MetricKey.new_duplicated_lines_density, level: 'WARNING', warning: '5' }) diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx index a9dfbe269ed..8c124a65a98 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx @@ -26,6 +26,7 @@ import { getLocalizedMetricName, translate } from 'sonar-ui-common/helpers/l10n' import { isDiffMetric } from 'sonar-ui-common/helpers/measures'; import DocTooltip from '../../../components/docs/DocTooltip'; import { withAppState } from '../../../components/hoc/withAppState'; +import { MetricKey } from '../../../types/metrics'; import Condition from './Condition'; import ConditionModal from './ConditionModal'; @@ -42,7 +43,11 @@ interface Props { } const FORBIDDEN_METRIC_TYPES = ['DATA', 'DISTRIB', 'STRING', 'BOOL']; -const FORBIDDEN_METRICS = ['alert_status', 'releasability_rating', 'security_review_rating']; +const FORBIDDEN_METRICS: string[] = [ + MetricKey.alert_status, + MetricKey.releasability_rating, + MetricKey.security_review_rating +]; export class Conditions extends React.PureComponent<Props> { renderConditionsTable = (conditions: T.Condition[], scope: 'new' | 'overall') => { diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Condition-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Condition-test.tsx index 79fd0689c2d..0e3f8d201ff 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Condition-test.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Condition-test.tsx @@ -19,7 +19,8 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import { mockCondition, mockMetric, mockQualityGate } from '../../../../helpers/testMocks'; +import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; +import { mockCondition, mockMetric } from '../../../../helpers/testMocks'; import Condition from '../Condition'; it('should render correctly', () => { diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ConditionModal-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ConditionModal-test.tsx index 5816d741f93..ab6e843fb9f 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ConditionModal-test.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ConditionModal-test.tsx @@ -19,7 +19,9 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import { mockMetric, mockQualityGate } from '../../../../helpers/testMocks'; +import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; +import { mockMetric } from '../../../../helpers/testMocks'; +import { MetricKey } from '../../../../types/metrics'; import ConditionModal from '../ConditionModal'; it('should render correctly', () => { @@ -40,14 +42,12 @@ it('should correctly handle a metric selection', () => { it('should correctly switch scope', () => { const wrapper = shallowRender({ metrics: [ - mockMetric({ id: 'new_coverage', key: 'new_coverage', name: 'Coverage on New Code' }), + mockMetric({ key: MetricKey.new_coverage }), mockMetric({ - id: 'new_duplication', - key: 'new_duplication', - name: 'Duplication on New Code' + key: MetricKey.new_duplicated_lines }), mockMetric(), - mockMetric({ id: 'duplication', key: 'duplication', name: 'Duplication' }) + mockMetric({ key: MetricKey.duplicated_lines }) ] }); expect(wrapper).toMatchSnapshot(); @@ -64,12 +64,8 @@ function shallowRender(props: Partial<ConditionModal['props']> = {}) { <ConditionModal header="header" metrics={[ - mockMetric({ id: 'new_coverage', key: 'new_coverage', name: 'Coverage on New Code' }), - mockMetric({ - id: 'new_duplication', - key: 'new_duplication', - name: 'Duplication on New Code' - }) + mockMetric({ key: MetricKey.new_coverage }), + mockMetric({ key: MetricKey.new_duplicated_lines }) ]} onAddCondition={jest.fn()} onClose={jest.fn()} diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Conditions-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Conditions-test.tsx index c2602951c03..41db990356f 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Conditions-test.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Conditions-test.tsx @@ -19,7 +19,9 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import { mockCondition, mockMetric, mockQualityGate } from '../../../../helpers/testMocks'; +import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; +import { mockCondition, mockMetric } from '../../../../helpers/testMocks'; +import { MetricKey } from '../../../../types/metrics'; import { Conditions } from '../Conditions'; it('should render correctly', () => { @@ -30,9 +32,9 @@ it('should render correctly with new code conditions', () => { const wrapper = shallowRender({ conditions: [ mockCondition(), - mockCondition({ id: 2, metric: 'duplication' }), - mockCondition({ id: 3, metric: 'new_coverage' }), - mockCondition({ id: 4, metric: 'new_duplication' }) + mockCondition({ id: 2, metric: MetricKey.duplicated_lines }), + mockCondition({ id: 3, metric: MetricKey.new_coverage }), + mockCondition({ id: 4, metric: MetricKey.new_duplicated_lines }) ] }); expect(wrapper).toMatchSnapshot(); @@ -53,19 +55,15 @@ function shallowRender(props: Partial<Conditions['props']> = {}) { <Conditions appState={{ branchesEnabled: true }} canEdit={false} - conditions={[mockCondition(), mockCondition({ id: 2, metric: 'duplication' })]} + conditions={[mockCondition(), mockCondition({ id: 2, metric: MetricKey.duplicated_lines })]} metrics={{ - coverage: mockMetric(), - duplication: mockMetric({ id: 'duplication', key: 'duplication', name: 'Duplication' }), - new_coverage: mockMetric({ - id: 'new_coverage', - key: 'new_coverage', - name: 'Coverage on New Code' + [MetricKey.coverage]: mockMetric(), + [MetricKey.duplicated_lines]: mockMetric({ key: MetricKey.duplicated_lines }), + [MetricKey.new_coverage]: mockMetric({ + key: MetricKey.new_coverage }), - new_duplication: mockMetric({ - id: 'new_duplication', - key: 'new_duplication', - name: 'Duplication on New Code' + [MetricKey.new_duplicated_lines]: mockMetric({ + key: MetricKey.new_duplicated_lines }) }} onAddCondition={jest.fn()} diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/CopyQualityGateForm-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/CopyQualityGateForm-test.tsx index 2a9b4b4a113..492e8fa6b2f 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/CopyQualityGateForm-test.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/CopyQualityGateForm-test.tsx @@ -19,7 +19,7 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import { mockQualityGate } from '../../../../helpers/testMocks'; +import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; import CopyQualityGateForm from '../CopyQualityGateForm'; it('should render correctly', () => { diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ConditionModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ConditionModal-test.tsx.snap index 711a500cdf5..d634c60d729 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ConditionModal-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ConditionModal-test.tsx.snap @@ -50,13 +50,13 @@ exports[`should correctly switch scope 1`] = ` Object { "id": "new_coverage", "key": "new_coverage", - "name": "Coverage on New Code", + "name": "New_coverage", "type": "PERCENT", }, Object { - "id": "new_duplication", - "key": "new_duplication", - "name": "Duplication on New Code", + "id": "new_duplicated_lines", + "key": "new_duplicated_lines", + "name": "New_duplicated_lines", "type": "PERCENT", }, ] @@ -121,9 +121,9 @@ exports[`should correctly switch scope 2`] = ` "type": "PERCENT", }, Object { - "id": "duplication", - "key": "duplication", - "name": "Duplication", + "id": "duplicated_lines", + "key": "duplicated_lines", + "name": "Duplicated_lines", "type": "PERCENT", }, ] @@ -184,13 +184,13 @@ exports[`should correctly switch scope 3`] = ` Object { "id": "new_coverage", "key": "new_coverage", - "name": "Coverage on New Code", + "name": "New_coverage", "type": "PERCENT", }, Object { - "id": "new_duplication", - "key": "new_duplication", - "name": "Duplication on New Code", + "id": "new_duplicated_lines", + "key": "new_duplicated_lines", + "name": "New_duplicated_lines", "type": "PERCENT", }, ] @@ -251,13 +251,13 @@ exports[`should render correctly 1`] = ` Object { "id": "new_coverage", "key": "new_coverage", - "name": "Coverage on New Code", + "name": "New_coverage", "type": "PERCENT", }, Object { - "id": "new_duplication", - "key": "new_duplication", - "name": "Duplication on New Code", + "id": "new_duplicated_lines", + "key": "new_duplicated_lines", + "name": "New_duplicated_lines", "type": "PERCENT", }, ] @@ -299,13 +299,13 @@ exports[`should render correctly 2`] = ` Object { "id": "new_coverage", "key": "new_coverage", - "name": "Coverage on New Code", + "name": "New_coverage", "type": "PERCENT", }, Object { - "id": "new_duplication", - "key": "new_duplication", - "name": "Duplication on New Code", + "id": "new_duplicated_lines", + "key": "new_duplicated_lines", + "name": "New_duplicated_lines", "type": "PERCENT", }, ] diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Conditions-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Conditions-test.tsx.snap index d3db47fc642..e5019f06076 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Conditions-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Conditions-test.tsx.snap @@ -89,16 +89,16 @@ exports[`should render correctly 1`] = ` Object { "error": "10", "id": 2, - "metric": "duplication", + "metric": "duplicated_lines", "op": "LT", } } key="2" metric={ Object { - "id": "duplication", - "key": "duplication", - "name": "Duplication", + "id": "duplicated_lines", + "key": "duplicated_lines", + "name": "Duplicated_lines", "type": "PERCENT", } } @@ -210,7 +210,7 @@ exports[`should render correctly with new code conditions 1`] = ` Object { "id": "new_coverage", "key": "new_coverage", - "name": "Coverage on New Code", + "name": "New_coverage", "type": "PERCENT", } } @@ -229,16 +229,16 @@ exports[`should render correctly with new code conditions 1`] = ` Object { "error": "10", "id": 4, - "metric": "new_duplication", + "metric": "new_duplicated_lines", "op": "LT", } } key="4" metric={ Object { - "id": "new_duplication", - "key": "new_duplication", - "name": "Duplication on New Code", + "id": "new_duplicated_lines", + "key": "new_duplicated_lines", + "name": "New_duplicated_lines", "type": "PERCENT", } } @@ -328,16 +328,16 @@ exports[`should render correctly with new code conditions 1`] = ` Object { "error": "10", "id": 2, - "metric": "duplication", + "metric": "duplicated_lines", "op": "LT", } } key="2" metric={ Object { - "id": "duplication", - "key": "duplication", - "name": "Duplication", + "id": "duplicated_lines", + "key": "duplicated_lines", + "name": "Duplicated_lines", "type": "PERCENT", } } @@ -464,16 +464,16 @@ exports[`should render the add conditions button and modal 1`] = ` Object { "error": "10", "id": 2, - "metric": "duplication", + "metric": "duplicated_lines", "op": "LT", } } key="2" metric={ Object { - "id": "duplication", - "key": "duplication", - "name": "Duplication", + "id": "duplicated_lines", + "key": "duplicated_lines", + "name": "Duplicated_lines", "type": "PERCENT", } } diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/MeasuresOverlayMeasure.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/MeasuresOverlayMeasure.tsx index 0ff4afc2ba8..52450c42784 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/components/MeasuresOverlayMeasure.tsx +++ b/server/sonar-web/src/main/js/components/SourceViewer/components/MeasuresOverlayMeasure.tsx @@ -20,6 +20,7 @@ import * as React from 'react'; import IssueTypeIcon from 'sonar-ui-common/components/icons/IssueTypeIcon'; import { getLocalizedMetricName } from 'sonar-ui-common/helpers/l10n'; +import { isMetricKey, MetricKey } from '../../../types/metrics'; import Measure from '../../measure/Measure'; export interface MeasureWithMetric { @@ -38,9 +39,10 @@ export default function MeasuresOverlayMeasure({ measure }: Props) { data-metric={measure.metric.key} key={measure.metric.key}> <span className="measure-name"> - {['bugs', 'vulnerabilities', 'code_smells'].includes(measure.metric.key) && ( - <IssueTypeIcon className="little-spacer-right" query={measure.metric.key} /> - )} + {isMetricKey(measure.metric.key) && + [MetricKey.bugs, MetricKey.vulnerabilities, MetricKey.code_smells].includes( + measure.metric.key + ) && <IssueTypeIcon className="little-spacer-right" query={measure.metric.key} />} {getLocalizedMetricName(measure.metric)} </span> <span className="measure-value"> diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/MeasuresOverlay-test.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/MeasuresOverlay-test.tsx index 2017997e0a6..ef77fc3c614 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/MeasuresOverlay-test.tsx +++ b/server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/MeasuresOverlay-test.tsx @@ -21,6 +21,7 @@ import { shallow } from 'enzyme'; import * as React from 'react'; import { click, waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; import { mockBranch } from '../../../../helpers/mocks/branch-like'; +import { MetricKey } from '../../../../types/metrics'; import MeasuresOverlay from '../MeasuresOverlay'; jest.mock('../../../../api/issues', () => ({ @@ -60,78 +61,78 @@ jest.mock('../../../../api/issues', () => ({ jest.mock('../../../../api/measures', () => ({ getMeasures: () => Promise.resolve([ - { metric: 'vulnerabilities', value: '0' }, - { metric: 'complexity', value: '1' }, - { metric: 'test_errors', value: '1' }, - { metric: 'comment_lines_density', value: '20.0' }, - { metric: 'wont_fix_issues', value: '0' }, - { metric: 'uncovered_lines', value: '1' }, - { metric: 'functions', value: '1' }, - { metric: 'duplicated_files', value: '1' }, - { metric: 'duplicated_blocks', value: '3' }, - { metric: 'line_coverage', value: '75.0' }, - { metric: 'duplicated_lines_density', value: '0.0' }, - { metric: 'comment_lines', value: '2' }, - { metric: 'ncloc', value: '8' }, - { metric: 'reliability_rating', value: '1.0' }, - { metric: 'false_positive_issues', value: '0' }, - { metric: 'reliability_remediation_effort', value: '0' }, - { metric: 'code_smells', value: '2' }, - { metric: 'security_rating', value: '1.0' }, - { metric: 'test_success_density', value: '100.0' }, - { metric: 'cognitive_complexity', value: '0' }, - { metric: 'files', value: '1' }, - { metric: 'duplicated_lines', value: '0' }, - { metric: 'lines', value: '18' }, - { metric: 'classes', value: '1' }, - { metric: 'bugs', value: '0' }, - { metric: 'lines_to_cover', value: '4' }, - { metric: 'sqale_index', value: '40' }, - { metric: 'sqale_debt_ratio', value: '16.7' }, - { metric: 'coverage', value: '75.0' }, - { metric: 'security_remediation_effort', value: '0' }, - { metric: 'statements', value: '3' }, - { metric: 'skipped_tests', value: '0' }, - { metric: 'test_failures', value: '0' }, - { metric: 'violations', value: '1' } + { metric: MetricKey.vulnerabilities, value: '0' }, + { metric: MetricKey.complexity, value: '1' }, + { metric: MetricKey.test_errors, value: '1' }, + { metric: MetricKey.comment_lines_density, value: '20.0' }, + { metric: MetricKey.wont_fix_issues, value: '0' }, + { metric: MetricKey.uncovered_lines, value: '1' }, + { metric: MetricKey.functions, value: '1' }, + { metric: MetricKey.duplicated_files, value: '1' }, + { metric: MetricKey.duplicated_blocks, value: '3' }, + { metric: MetricKey.line_coverage, value: '75.0' }, + { metric: MetricKey.duplicated_lines_density, value: '0.0' }, + { metric: MetricKey.comment_lines, value: '2' }, + { metric: MetricKey.ncloc, value: '8' }, + { metric: MetricKey.reliability_rating, value: '1.0' }, + { metric: MetricKey.false_positive_issues, value: '0' }, + { metric: MetricKey.reliability_remediation_effort, value: '0' }, + { metric: MetricKey.code_smells, value: '2' }, + { metric: MetricKey.security_rating, value: '1.0' }, + { metric: MetricKey.test_success_density, value: '100.0' }, + { metric: MetricKey.cognitive_complexity, value: '0' }, + { metric: MetricKey.files, value: '1' }, + { metric: MetricKey.duplicated_lines, value: '0' }, + { metric: MetricKey.lines, value: '18' }, + { metric: MetricKey.classes, value: '1' }, + { metric: MetricKey.bugs, value: '0' }, + { metric: MetricKey.lines_to_cover, value: '4' }, + { metric: MetricKey.sqale_index, value: '40' }, + { metric: MetricKey.sqale_debt_ratio, value: '16.7' }, + { metric: MetricKey.coverage, value: '75.0' }, + { metric: MetricKey.security_remediation_effort, value: '0' }, + { metric: MetricKey.statements, value: '3' }, + { metric: MetricKey.skipped_tests, value: '0' }, + { metric: MetricKey.test_failures, value: '0' }, + { metric: MetricKey.violations, value: '1' } ]) })); jest.mock('../../../../api/metrics', () => ({ getAllMetrics: () => Promise.resolve([ - { key: 'vulnerabilities', type: 'INT', domain: 'Security' }, - { key: 'complexity', type: 'INT', domain: 'Complexity' }, - { key: 'test_errors', type: 'INT', domain: 'Tests' }, - { key: 'comment_lines_density', type: 'PERCENT', domain: 'Size' }, - { key: 'wont_fix_issues', type: 'INT', domain: 'Issues' }, - { key: 'uncovered_lines', type: 'INT', domain: 'Coverage' }, - { key: 'functions', type: 'INT', domain: 'Size' }, - { key: 'duplicated_files', type: 'INT', domain: 'Duplications' }, - { key: 'duplicated_blocks', type: 'INT', domain: 'Duplications' }, - { key: 'line_coverage', type: 'PERCENT', domain: 'Coverage' }, - { key: 'duplicated_lines_density', type: 'PERCENT', domain: 'Duplications' }, - { key: 'comment_lines', type: 'INT', domain: 'Size' }, - { key: 'ncloc', type: 'INT', domain: 'Size' }, - { key: 'reliability_rating', type: 'RATING', domain: 'Reliability' }, - { key: 'false_positive_issues', type: 'INT', domain: 'Issues' }, - { key: 'code_smells', type: 'INT', domain: 'Maintainability' }, - { key: 'security_rating', type: 'RATING', domain: 'Security' }, - { key: 'test_success_density', type: 'PERCENT', domain: 'Tests' }, - { key: 'cognitive_complexity', type: 'INT', domain: 'Complexity' }, - { key: 'files', type: 'INT', domain: 'Size' }, - { key: 'duplicated_lines', type: 'INT', domain: 'Duplications' }, - { key: 'lines', type: 'INT', domain: 'Size' }, - { key: 'classes', type: 'INT', domain: 'Size' }, - { key: 'bugs', type: 'INT', domain: 'Reliability' }, - { key: 'lines_to_cover', type: 'INT', domain: 'Coverage' }, - { key: 'sqale_index', type: 'WORK_DUR', domain: 'Maintainability' }, - { key: 'sqale_debt_ratio', type: 'PERCENT', domain: 'Maintainability' }, - { key: 'coverage', type: 'PERCENT', domain: 'Coverage' }, - { key: 'statements', type: 'INT', domain: 'Size' }, - { key: 'skipped_tests', type: 'INT', domain: 'Tests' }, - { key: 'test_failures', type: 'INT', domain: 'Tests' }, - { key: 'violations', type: 'INT', domain: 'Issues' }, + { key: MetricKey.vulnerabilities, type: 'INT', domain: 'Security' }, + { key: MetricKey.complexity, type: 'INT', domain: 'Complexity' }, + { key: MetricKey.test_errors, type: 'INT', domain: 'Tests' }, + { key: MetricKey.comment_lines_density, type: 'PERCENT', domain: 'Size' }, + { key: MetricKey.wont_fix_issues, type: 'INT', domain: 'Issues' }, + { key: MetricKey.uncovered_lines, type: 'INT', domain: 'Coverage' }, + { key: MetricKey.functions, type: 'INT', domain: 'Size' }, + { key: MetricKey.duplicated_files, type: 'INT', domain: 'Duplications' }, + { key: MetricKey.duplicated_blocks, type: 'INT', domain: 'Duplications' }, + { key: MetricKey.line_coverage, type: 'PERCENT', domain: 'Coverage' }, + { key: MetricKey.duplicated_lines_density, type: 'PERCENT', domain: 'Duplications' }, + { key: MetricKey.comment_lines, type: 'INT', domain: 'Size' }, + { key: MetricKey.ncloc, type: 'INT', domain: 'Size' }, + { key: MetricKey.reliability_rating, type: 'RATING', domain: 'Reliability' }, + { key: MetricKey.false_positive_issues, type: 'INT', domain: 'Issues' }, + { key: MetricKey.code_smells, type: 'INT', domain: 'Maintainability' }, + { key: MetricKey.security_rating, type: 'RATING', domain: 'Security' }, + { key: MetricKey.test_success_density, type: 'PERCENT', domain: 'Tests' }, + { key: MetricKey.cognitive_complexity, type: 'INT', domain: 'Complexity' }, + { key: MetricKey.files, type: 'INT', domain: 'Size' }, + { key: MetricKey.duplicated_lines, type: 'INT', domain: 'Duplications' }, + { key: MetricKey.lines, type: 'INT', domain: 'Size' }, + { key: MetricKey.classes, type: 'INT', domain: 'Size' }, + { key: MetricKey.bugs, type: 'INT', domain: 'Reliability' }, + { key: MetricKey.lines_to_cover, type: 'INT', domain: 'Coverage' }, + { key: MetricKey.sqale_index, type: 'WORK_DUR', domain: 'Maintainability' }, + { key: MetricKey.sqale_debt_ratio, type: 'PERCENT', domain: 'Maintainability' }, + { key: MetricKey.coverage, type: 'PERCENT', domain: 'Coverage' }, + { key: MetricKey.statements, type: 'INT', domain: 'Size' }, + { key: MetricKey.skipped_tests, type: 'INT', domain: 'Tests' }, + { key: MetricKey.test_failures, type: 'INT', domain: 'Tests' }, + { key: MetricKey.violations, type: 'INT', domain: 'Issues' }, // next two must be filtered out { key: 'data', type: 'DATA' }, { key: 'hidden', hidden: true } diff --git a/server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts new file mode 100644 index 00000000000..ea9bffaf05a --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/__tests__/measures-test.ts @@ -0,0 +1,50 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import { enhanceConditionWithMeasure } from '../measures'; +import { mockQualityGateStatusCondition } from '../mocks/quality-gates'; +import { mockMeasureEnhanced, mockMetric } from '../testMocks'; + +describe('enhanceConditionWithMeasure', () => { + it('should correctly map enhance conditions with measure data', () => { + const measures = [ + mockMeasureEnhanced({ metric: mockMetric({ key: 'bugs' }), periods: undefined }), + mockMeasureEnhanced({ metric: mockMetric({ key: 'new_bugs' }) }) + ]; + + expect( + enhanceConditionWithMeasure(mockQualityGateStatusCondition({ metric: 'bugs' }), measures) + ).toMatchObject({ + measure: expect.objectContaining({ metric: expect.objectContaining({ key: 'bugs' }) }) + }); + + expect( + enhanceConditionWithMeasure(mockQualityGateStatusCondition({ metric: 'new_bugs' }), measures) + ).toMatchObject({ + measure: expect.objectContaining({ + metric: expect.objectContaining({ key: 'new_bugs' }) + }), + period: 1 + }); + }); + + it('should return undefined if no match can be found', () => { + expect(enhanceConditionWithMeasure(mockQualityGateStatusCondition(), [])).toBeUndefined(); + }); +}); diff --git a/server/sonar-web/src/main/js/helpers/measures.ts b/server/sonar-web/src/main/js/helpers/measures.ts index 283ebfdf7bd..0c180278b2c 100644 --- a/server/sonar-web/src/main/js/helpers/measures.ts +++ b/server/sonar-web/src/main/js/helpers/measures.ts @@ -20,9 +20,14 @@ import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n'; import { formatMeasure } from 'sonar-ui-common/helpers/measures'; import { isDefined } from 'sonar-ui-common/helpers/types'; +import { MetricKey } from '../types/metrics'; +import { + QualityGateStatusCondition, + QualityGateStatusConditionEnhanced +} from '../types/quality-gates'; /** Return a localized metric name */ -export function localizeMetric(metricKey: string): string { +export function localizeMetric(metricKey: MetricKey | string): string { return translate('metric', metricKey, 'name'); } @@ -48,6 +53,22 @@ export function enhanceMeasuresWithMetrics( .filter(isDefined); } +export function enhanceConditionWithMeasure( + condition: QualityGateStatusCondition, + measures: T.MeasureEnhanced[] +): QualityGateStatusConditionEnhanced | undefined { + const measure = measures.find(m => m.metric.key === condition.metric); + + // Make sure we have a period index. This is necessary when dealing with + // applications. + let { period } = condition; + if (measure && measure.periods && !period) { + period = measure.periods[0].index; + } + + return measure && { ...condition, period, measure }; +} + /** Get period value of a measure */ export function getPeriodValue( measure: T.Measure | T.MeasureEnhanced, @@ -68,7 +89,7 @@ export function isPeriodBestValue( } /** Check if metric is differential */ -export function isDiffMetric(metricKey: string): boolean { +export function isDiffMetric(metricKey: MetricKey | string): boolean { return metricKey.indexOf('new_') === 0; } @@ -124,7 +145,7 @@ function getMaintainabilityRatingTooltip(rating: number): string { ); } -export function getRatingTooltip(metricKey: string, value: number | string): string { +export function getRatingTooltip(metricKey: MetricKey | string, value: number | string): string { const ratingLetter = formatMeasure(value, 'RATING'); const finalMetricKey = isDiffMetric(metricKey) ? metricKey.substr(4) : metricKey; @@ -138,6 +159,6 @@ export function getDisplayMetrics(metrics: T.Metric[]) { return metrics.filter(metric => !metric.hidden && !['DATA', 'DISTRIB'].includes(metric.type)); } -export function findMeasure(measures: T.Measure[], metric: string) { - return measures.find(measure => measure.metric === metric); +export function findMeasure(measures: T.MeasureEnhanced[], metric: MetricKey | string) { + return measures.find(measure => measure.metric.key === metric); } diff --git a/server/sonar-web/src/main/js/helpers/testMocks.ts b/server/sonar-web/src/main/js/helpers/testMocks.ts index 9b43cec23f3..b9f034fff2a 100644 --- a/server/sonar-web/src/main/js/helpers/testMocks.ts +++ b/server/sonar-web/src/main/js/helpers/testMocks.ts @@ -451,13 +451,17 @@ export function mockLocation(overrides: Partial<Location> = {}): Location { }; } -export function mockMetric(overrides: Partial<T.Metric> = {}): T.Metric { - return { - id: 'coverage', - key: 'coverage', - name: 'Coverage', - type: 'PERCENT', - ...overrides +export function mockMetric( + overrides: Partial<Pick<T.Metric, 'key' | 'name' | 'type'>> = {} +): T.Metric { + const key = overrides.key || 'coverage'; + const name = overrides.name || key[0].toUpperCase() + key.substr(1); + const type = overrides.type || 'PERCENT'; + return { + id: key, + key, + name, + type }; } diff --git a/server/sonar-web/src/main/js/types/metrics.ts b/server/sonar-web/src/main/js/types/metrics.ts new file mode 100644 index 00000000000..f205a778f11 --- /dev/null +++ b/server/sonar-web/src/main/js/types/metrics.ts @@ -0,0 +1,148 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +export enum MetricKey { + alert_status = 'alert_status', + blocker_violations = 'blocker_violations', + branch_coverage = 'branch_coverage', + bugs = 'bugs', + burned_budget = 'burned_budget', + business_value = 'business_value', + class_complexity = 'class_complexity', + classes = 'classes', + code_smells = 'code_smells', + cognitive_complexity = 'cognitive_complexity', + comment_lines = 'comment_lines', + comment_lines_data = 'comment_lines_data', + comment_lines_density = 'comment_lines_density', + complexity = 'complexity', + complexity_in_classes = 'complexity_in_classes', + complexity_in_functions = 'complexity_in_functions', + conditions_to_cover = 'conditions_to_cover', + confirmed_issues = 'confirmed_issues', + coverage = 'coverage', + critical_violations = 'critical_violations', + development_cost = 'development_cost', + directories = 'directories', + duplicated_blocks = 'duplicated_blocks', + duplicated_files = 'duplicated_files', + duplicated_lines = 'duplicated_lines', + duplicated_lines_density = 'duplicated_lines_density', + duplications_data = 'duplications_data', + effort_to_reach_maintainability_rating_a = 'effort_to_reach_maintainability_rating_a', + executable_lines_data = 'executable_lines_data', + false_positive_issues = 'false_positive_issues', + file_complexity = 'file_complexity', + file_complexity_distribution = 'file_complexity_distribution', + filename_size = 'filename_size', + filename_size_rating = 'filename_size_rating', + files = 'files', + function_complexity = 'function_complexity', + function_complexity_distribution = 'function_complexity_distribution', + functions = 'functions', + generated_lines = 'generated_lines', + generated_ncloc = 'generated_ncloc', + info_violations = 'info_violations', + last_change_on_maintainability_rating = 'last_change_on_maintainability_rating', + last_change_on_releasability_rating = 'last_change_on_releasability_rating', + last_change_on_reliability_rating = 'last_change_on_reliability_rating', + last_change_on_security_rating = 'last_change_on_security_rating', + last_change_on_security_review_rating = 'last_change_on_security_review_rating', + last_commit_date = 'last_commit_date', + leak_projects = 'leak_projects', + line_coverage = 'line_coverage', + lines = 'lines', + lines_to_cover = 'lines_to_cover', + maintainability_rating_effort = 'maintainability_rating_effort', + major_violations = 'major_violations', + minor_violations = 'minor_violations', + ncloc = 'ncloc', + ncloc_data = 'ncloc_data', + ncloc_language_distribution = 'ncloc_language_distribution', + new_blocker_violations = 'new_blocker_violations', + new_branch_coverage = 'new_branch_coverage', + new_bugs = 'new_bugs', + new_code_smells = 'new_code_smells', + new_conditions_to_cover = 'new_conditions_to_cover', + new_coverage = 'new_coverage', + new_critical_violations = 'new_critical_violations', + new_development_cost = 'new_development_cost', + new_duplicated_blocks = 'new_duplicated_blocks', + new_duplicated_lines = 'new_duplicated_lines', + new_duplicated_lines_density = 'new_duplicated_lines_density', + new_info_violations = 'new_info_violations', + new_line_coverage = 'new_line_coverage', + new_lines = 'new_lines', + new_lines_to_cover = 'new_lines_to_cover', + new_maintainability_rating = 'new_maintainability_rating', + new_major_violations = 'new_major_violations', + new_minor_violations = 'new_minor_violations', + new_reliability_rating = 'new_reliability_rating', + new_reliability_remediation_effort = 'new_reliability_remediation_effort', + new_security_hotspots = 'new_security_hotspots', + new_security_rating = 'new_security_rating', + new_security_remediation_effort = 'new_security_remediation_effort', + new_sqale_debt_ratio = 'new_sqale_debt_ratio', + new_technical_debt = 'new_technical_debt', + new_uncovered_conditions = 'new_uncovered_conditions', + new_uncovered_lines = 'new_uncovered_lines', + new_violations = 'new_violations', + new_vulnerabilities = 'new_vulnerabilities', + open_issues = 'open_issues', + projects = 'projects', + public_api = 'public_api', + public_documented_api_density = 'public_documented_api_density', + public_undocumented_api = 'public_undocumented_api', + quality_gate_details = 'quality_gate_details', + quality_profiles = 'quality_profiles', + releasability_effort = 'releasability_effort', + releasability_rating = 'releasability_rating', + reliability_rating = 'reliability_rating', + reliability_rating_effort = 'reliability_rating_effort', + reliability_remediation_effort = 'reliability_remediation_effort', + reopened_issues = 'reopened_issues', + security_hotspots = 'security_hotspots', + security_rating = 'security_rating', + security_rating_effort = 'security_rating_effort', + security_remediation_effort = 'security_remediation_effort', + security_review_rating = 'security_review_rating', + security_review_rating_effort = 'security_review_rating_effort', + skipped_tests = 'skipped_tests', + sonarjava_feedback = 'sonarjava_feedback', + sqale_debt_ratio = 'sqale_debt_ratio', + sqale_index = 'sqale_index', + sqale_rating = 'sqale_rating', + statements = 'statements', + team_at_sonarsource = 'team_at_sonarsource', + team_size = 'team_size', + test_errors = 'test_errors', + test_execution_time = 'test_execution_time', + test_failures = 'test_failures', + test_success_density = 'test_success_density', + tests = 'tests', + uncovered_conditions = 'uncovered_conditions', + uncovered_lines = 'uncovered_lines', + violations = 'violations', + vulnerabilities = 'vulnerabilities', + wont_fix_issues = 'wont_fix_issues' +} + +export function isMetricKey(key: string): key is MetricKey { + return (Object.values(MetricKey) as string[]).includes(key); +} |