From c498831a11a373cc23604e5defe95602028304b8 Mon Sep 17 00:00:00 2001 From: Viktor Vorona Date: Thu, 15 Aug 2024 11:54:57 +0200 Subject: [PATCH] SONAR-22727 Fetch real data --- .../src/main/js/api/mocks/data/measures.ts | 52 +- .../components/metrics/RatingComponent.tsx | 21 +- .../__tests__/ComponentMeasures-it.tsx | 120 +++- .../components/LeakPeriodLegend.tsx | 4 +- .../apps/component-measures/config/bubbles.ts | 8 +- .../main/js/apps/component-measures/hooks.ts | 4 +- .../branches/BranchOverviewRenderer.tsx | 9 +- .../branches/QualityGateCondition.tsx | 1 + .../branches/SoftwareImpactMeasureCard.tsx | 6 +- .../branches/__tests__/BranchOverview-it.tsx | 109 +++- .../components/__tests__/QualityGate-it.tsx | 2 + .../components/measure/MeasureIndicator.tsx | 1 + .../measure/RatingTooltipContent.tsx | 13 +- .../src/main/js/components/measure/utils.ts | 13 +- .../sonar-web/src/main/js/helpers/measures.ts | 2 +- .../src/main/js/helpers/mocks/metrics.ts | 528 +++++++++++++++--- .../sonar-web/src/main/js/queries/measures.ts | 32 +- .../components/measure/Measure.tsx | 3 + server/sonar-web/src/main/js/types/types.ts | 1 + .../resources/org/sonar/l10n/core.properties | 70 +++ 20 files changed, 848 insertions(+), 151 deletions(-) diff --git a/server/sonar-web/src/main/js/api/mocks/data/measures.ts b/server/sonar-web/src/main/js/api/mocks/data/measures.ts index a08c608b4ed..315fd23504c 100644 --- a/server/sonar-web/src/main/js/api/mocks/data/measures.ts +++ b/server/sonar-web/src/main/js/api/mocks/data/measures.ts @@ -218,12 +218,17 @@ function mockComponentMeasure(tree: ComponentTree, issueList: IssueData[], metri ...computeRating(issues, IssueType.Bug), }); - case MetricKey.software_quality_reliability_rating: + case MetricKey.software_quality_reliability_rating: { + const rating = computeRating(issues, IssueType.Bug); + if (rating.value === '5.0') { + rating.value = '4.0'; + } return mockMeasure({ metric: metricKey, period: undefined, ...computeRating(issues, IssueType.Bug), }); + } case MetricKey.new_reliability_rating: return mockMeasure({ @@ -235,15 +240,20 @@ function mockComponentMeasure(tree: ComponentTree, issueList: IssueData[], metri value: undefined, }); - case MetricKey.new_software_quality_reliability_rating: + case MetricKey.new_software_quality_reliability_rating: { + const rating = computeRating(issues, IssueType.Bug); + if (rating.value === '5.0') { + rating.value = '4.0'; + } return mockMeasure({ metric: metricKey, period: { index: 0, - ...computeRating(issues, IssueType.Bug), + ...rating, }, value: undefined, }); + } case MetricKey.sqale_rating: return mockMeasure({ @@ -252,12 +262,17 @@ function mockComponentMeasure(tree: ComponentTree, issueList: IssueData[], metri ...computeRating(issues, IssueType.CodeSmell), }); - case MetricKey.software_quality_maintainability_rating: + case MetricKey.software_quality_maintainability_rating: { + const rating = computeRating(issues, IssueType.CodeSmell); + if (rating.value === '5.0') { + rating.value = '4.0'; + } return mockMeasure({ metric: metricKey, period: undefined, - ...computeRating(issues, IssueType.CodeSmell), + ...rating, }); + } case MetricKey.new_maintainability_rating: return mockMeasure({ @@ -269,15 +284,20 @@ function mockComponentMeasure(tree: ComponentTree, issueList: IssueData[], metri value: undefined, }); - case MetricKey.new_software_quality_maintainability_rating: + case MetricKey.new_software_quality_maintainability_rating: { + const rating = computeRating(issues, IssueType.CodeSmell); + if (rating.value === '5.0') { + rating.value = '4.0'; + } return mockMeasure({ metric: metricKey, period: { index: 0, - ...computeRating(issues, IssueType.CodeSmell), + ...rating, }, value: undefined, }); + } case MetricKey.security_rating: return mockMeasure({ @@ -286,12 +306,17 @@ function mockComponentMeasure(tree: ComponentTree, issueList: IssueData[], metri ...computeRating(issues, IssueType.Vulnerability), }); - case MetricKey.software_quality_security_rating: + case MetricKey.software_quality_security_rating: { + const rating = computeRating(issues, IssueType.Vulnerability); + if (rating.value === '5.0') { + rating.value = '4.0'; + } return mockMeasure({ metric: metricKey, period: undefined, - ...computeRating(issues, IssueType.Vulnerability), + ...rating, }); + } case MetricKey.new_security_rating: return mockMeasure({ @@ -303,15 +328,20 @@ function mockComponentMeasure(tree: ComponentTree, issueList: IssueData[], metri value: undefined, }); - case MetricKey.new_software_quality_security_rating: + case MetricKey.new_software_quality_security_rating: { + const rating = computeRating(issues, IssueType.Vulnerability); + if (rating.value === '5.0') { + rating.value = '4.0'; + } return mockMeasure({ metric: metricKey, period: { index: 0, - ...computeRating(issues, IssueType.Vulnerability), + ...rating, }, value: undefined, }); + } } } diff --git a/server/sonar-web/src/main/js/app/components/metrics/RatingComponent.tsx b/server/sonar-web/src/main/js/app/components/metrics/RatingComponent.tsx index 03de2c241b6..5029f84679a 100644 --- a/server/sonar-web/src/main/js/app/components/metrics/RatingComponent.tsx +++ b/server/sonar-web/src/main/js/app/components/metrics/RatingComponent.tsx @@ -35,6 +35,7 @@ interface Props { branchLike?: BranchLike; className?: string; componentKey: string; + forceMetric?: boolean; getLabel?: (rating: RatingEnum) => string; getTooltip?: (rating: RatingEnum) => React.ReactNode; ratingMetric: MetricKey; @@ -66,23 +67,35 @@ const useGetMetricKeyForRating = (ratingMetric: RatingMetricKeys): MetricKey | n }; export default function RatingComponent(props: Readonly) { - const { componentKey, ratingMetric, size, className, getLabel, branchLike, getTooltip } = props; + const { + componentKey, + ratingMetric, + size, + forceMetric, + className, + getLabel, + branchLike, + getTooltip, + } = props; const metricKey = useGetMetricKeyForRating(ratingMetric as RatingMetricKeys); const { data: isLegacy } = useIsLegacyCCTMode(); const { data: targetMeasure, isLoading: isLoadingTargetMeasure } = useMeasureQuery( { componentKey, metricKey: metricKey ?? '', branchLike }, - { enabled: !!metricKey }, + { enabled: !forceMetric && !!metricKey }, ); const { data: oldMeasure, isLoading: isLoadingOldMeasure } = useMeasureQuery( { componentKey, metricKey: ratingMetric, branchLike }, - { enabled: !isLegacy && !isNewRatingMetric(ratingMetric) && targetMeasure === null }, + { + enabled: + forceMetric || (!isLegacy && !isNewRatingMetric(ratingMetric) && targetMeasure === null), + }, ); const isLoading = isLoadingTargetMeasure || isLoadingOldMeasure; - const measure = targetMeasure ?? oldMeasure; + const measure = forceMetric ? oldMeasure : targetMeasure ?? oldMeasure; const value = isDiffMetric(metricKey ?? '') ? getLeakValue(measure) : measure?.value; const rating = formatMeasure(value, MetricType.Rating) as RatingEnum; diff --git a/server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx b/server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx index 6da61a2b489..01043b60288 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx @@ -33,6 +33,7 @@ import { mockMeasure, mockMetric } from '../../../helpers/testMocks'; import { renderAppWithComponentContext } from '../../../helpers/testReactTestingUtils'; import { ComponentContextShape } from '../../../types/component'; import { Feature } from '../../../types/features'; +import { SettingsKey } from '../../../types/settings'; import routes from '../routes'; jest.mock('lodash', () => ({ @@ -91,10 +92,50 @@ describe('rendering', () => { await user.click(ui.maintainabilityDomainBtn.get()); [ 'component_measures.metric.new_maintainability_issues.name 5', + 'Software Quality Maintainability Remediation Effort on new code work_duration.x_minutes.1', + 'Software Quality Technical Debt Ratio on New Code 1.0%', + 'Software Quality Maintainability Rating on New Code metric.has_rating_X.D metric.software_quality_maintainability_rating.tooltip.D.0.0%', + 'component_measures.metric.maintainability_issues.name 2', + 'Software Quality Maintainability Remediation Effort work_duration.x_minutes.1', + 'Software Quality Technical Debt Ratio 1.0%', + 'Software Quality Maintainability Rating metric.has_rating_X.D metric.software_quality_maintainability_rating.tooltip.D.0.0%', + 'Software Quality Effort to Reach Maintainability Rating A work_duration.x_minutes.1', + ].forEach((measure) => { + expect(ui.measureLink(measure).get()).toBeInTheDocument(); + }); + }); + + it('should correctly render the default overview and navigation in legacy mode', async () => { + settingsHandler.set(SettingsKey.LegacyMode, 'true'); + const { ui, user } = getPageObject(); + renderMeasuresApp(); + + // Overview. + expect(await ui.seeDataAsListLink.find()).toBeInTheDocument(); + expect(ui.overviewDomainLink.get()).toHaveAttribute('aria-current', 'true'); + expect(ui.bubbleChart.get()).toBeInTheDocument(); + expect(within(ui.bubbleChart.get()).getAllByRole('link')).toHaveLength(8); + expect(ui.newCodePeriodTxt.get()).toBeInTheDocument(); + + // Sidebar. + expect(ui.reliabilityDomainBtn.get()).toBeInTheDocument(); + expect(ui.securityDomainBtn.get()).toBeInTheDocument(); + expect(ui.securityReviewDomainBtn.get()).toBeInTheDocument(); + expect(ui.maintainabilityDomainBtn.get()).toBeInTheDocument(); + expect(ui.coverageDomainBtn.get()).toBeInTheDocument(); + expect(ui.duplicationsDomainBtn.get()).toBeInTheDocument(); + expect(ui.sizeDomainBtn.get()).toBeInTheDocument(); + expect(ui.complexityDomainBtn.get()).toBeInTheDocument(); + expect(ui.issuesDomainBtn.get()).toBeInTheDocument(); + + // Check one of the domains. + await user.click(ui.maintainabilityDomainBtn.get()); + [ + 'component_measures.metric.new_code_smells.name 9', 'Added Technical Debt work_duration.x_minutes.1', 'Technical Debt Ratio on New Code 1.0%', 'Maintainability Rating on New Code metric.has_rating_X.E metric.sqale_rating.tooltip.E.0.0%', - 'component_measures.metric.maintainability_issues.name 2', + 'component_measures.metric.code_smells.name 9', 'Technical Debt work_duration.x_minutes.1', 'Technical Debt Ratio 1.0%', 'Maintainability Rating metric.has_rating_X.E metric.sqale_rating.tooltip.E.0.0%', @@ -107,6 +148,14 @@ describe('rendering', () => { it('should correctly revert to old measures when analysis is missing', async () => { measuresHandler.deleteComponentMeasure('foo', MetricKey.maintainability_issues); measuresHandler.deleteComponentMeasure('foo', MetricKey.new_maintainability_issues); + measuresHandler.deleteComponentMeasure( + 'foo', + MetricKey.software_quality_maintainability_rating, + ); + measuresHandler.deleteComponentMeasure( + 'foo', + MetricKey.new_software_quality_maintainability_rating, + ); const { ui, user } = getPageObject(); renderMeasuresApp(); @@ -130,6 +179,71 @@ describe('rendering', () => { expect(screen.getByText('overview.missing_project_dataTRK')).toBeInTheDocument(); }); + it('should show new counts but not ratings if no rating measures', async () => { + measuresHandler.deleteComponentMeasure( + 'foo', + MetricKey.software_quality_maintainability_rating, + ); + measuresHandler.deleteComponentMeasure( + 'foo', + MetricKey.new_software_quality_maintainability_rating, + ); + + const { ui, user } = getPageObject(); + renderMeasuresApp(); + await ui.appLoaded(); + + // Check one of the domains. + await user.click(ui.maintainabilityDomainBtn.get()); + [ + 'component_measures.metric.new_maintainability_issues.name 5', + 'Added Technical Debt work_duration.x_minutes.1', + 'Technical Debt Ratio on New Code 1.0%', + 'Maintainability Rating on New Code metric.has_rating_X.E metric.sqale_rating.tooltip.E.0.0%', + 'component_measures.metric.maintainability_issues.name 2', + 'Technical Debt work_duration.x_minutes.1', + 'Technical Debt Ratio 1.0%', + 'Maintainability Rating metric.has_rating_X.E metric.sqale_rating.tooltip.E.0.0%', + 'Effort to Reach Maintainability Rating A work_duration.x_minutes.1', + ].forEach((measure) => { + expect(ui.measureLink(measure).get()).toBeInTheDocument(); + }); + expect(screen.getByText('overview.missing_project_dataTRK')).toBeInTheDocument(); + }); + + it('should show old measures and no flag message if no rating measures and legacy mode', async () => { + settingsHandler.set(SettingsKey.LegacyMode, 'true'); + measuresHandler.deleteComponentMeasure( + 'foo', + MetricKey.software_quality_maintainability_rating, + ); + measuresHandler.deleteComponentMeasure( + 'foo', + MetricKey.new_software_quality_maintainability_rating, + ); + + const { ui, user } = getPageObject(); + renderMeasuresApp(); + await ui.appLoaded(); + + // Check one of the domains. + await user.click(ui.maintainabilityDomainBtn.get()); + [ + 'component_measures.metric.new_code_smells.name 9', + 'Added Technical Debt work_duration.x_minutes.1', + 'Technical Debt Ratio on New Code 1.0%', + 'Maintainability Rating on New Code metric.has_rating_X.E metric.sqale_rating.tooltip.E.0.0%', + 'component_measures.metric.code_smells.name 9', + 'Technical Debt work_duration.x_minutes.1', + 'Technical Debt Ratio 1.0%', + 'Maintainability Rating metric.has_rating_X.E metric.sqale_rating.tooltip.E.0.0%', + 'Effort to Reach Maintainability Rating A work_duration.x_minutes.1', + ].forEach((measure) => { + expect(ui.measureLink(measure).get()).toBeInTheDocument(); + }); + expect(screen.queryByText('overview.missing_project_dataTRK')).not.toBeInTheDocument(); + }); + it('should correctly render a list view', async () => { const { ui } = getPageObject(); renderMeasuresApp('component_measures?id=foo&metric=code_smells&view=list'); @@ -192,7 +306,7 @@ describe('rendering', () => { await ui.appLoaded(); // Fall back to a known metric. - expect(screen.getAllByText('Releasability rating').length).toBeGreaterThan(0); + expect((await screen.findAllByText('Releasability rating')).length).toBeGreaterThan(0); }); it('should render issues measures when query by open_issues', async () => { @@ -403,7 +517,7 @@ describe('navigation', () => { await user.click( ui .measureLink( - 'Maintainability Rating metric.has_rating_X.E metric.sqale_rating.tooltip.E.0.0%', + 'Software Quality Maintainability Rating metric.has_rating_X.D metric.software_quality_maintainability_rating.tooltip.D.0.0%', ) .get(), ); diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx index 4fb5f846278..6875d248493 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/components/LeakPeriodLegend.tsx @@ -27,7 +27,7 @@ import Tooltip from '../../../components/controls/Tooltip'; import DateFormatter, { longFormatterOption } from '../../../components/intl/DateFormatter'; import DateFromNow from '../../../components/intl/DateFromNow'; import DateTimeFormatter, { formatterOption } from '../../../components/intl/DateTimeFormatter'; -import { translate, translateWithParameters } from '../../../helpers/l10n'; +import { translate } from '../../../helpers/l10n'; import { getNewCodePeriodDate, getNewCodePeriodLabel } from '../../../helpers/new-code-period'; import { NewCodeDefinitionType } from '../../../types/new-code-definition'; import { ComponentMeasure, Period } from '../../../types/types'; @@ -64,7 +64,7 @@ class LeakPeriodLegend extends React.PureComponent - {translateWithParameters('component_measures.leak_legend.new_code')}{' '} + {translate('component_measures.leak_legend.new_code')}{' '} {leakPeriodLabel} ); 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 b5fedf2ce56..74b1325d3d6 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 @@ -33,19 +33,19 @@ export type BubblesByDomain = Record< export const newTaxonomyBubbles: BubblesByDomain = { Reliability: { x: MetricKey.ncloc, - y: MetricKey.reliability_remediation_effort, + y: MetricKey.software_quality_reliability_remediation_effort, size: MetricKey.reliability_issues, colors: [MetricKey.software_quality_reliability_rating], }, Security: { x: MetricKey.ncloc, - y: MetricKey.security_remediation_effort, + y: MetricKey.software_quality_security_remediation_effort, size: MetricKey.security_issues, colors: [MetricKey.software_quality_security_rating], }, Maintainability: { x: MetricKey.ncloc, - y: MetricKey.sqale_index, + y: MetricKey.software_quality_maintainability_remediation_effort, size: MetricKey.maintainability_issues, colors: [MetricKey.software_quality_maintainability_rating], }, @@ -61,7 +61,7 @@ export const newTaxonomyBubbles: BubblesByDomain = { size: MetricKey.duplicated_blocks, }, project_overview: { - x: MetricKey.sqale_index, + x: MetricKey.software_quality_maintainability_remediation_effort, y: MetricKey.coverage, size: MetricKey.ncloc, colors: [ diff --git a/server/sonar-web/src/main/js/apps/component-measures/hooks.ts b/server/sonar-web/src/main/js/apps/component-measures/hooks.ts index 6cf2f3042bb..d0fa433ba1f 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/hooks.ts +++ b/server/sonar-web/src/main/js/apps/component-measures/hooks.ts @@ -28,9 +28,9 @@ import { } from './config/bubbles'; export function useBubbleChartMetrics(measures: MeasureEnhanced[]) { - const { data: isLegacyFlag } = useIsLegacyCCTMode(); + const { data: isLegacy } = useIsLegacyCCTMode(); - if (isLegacyFlag || !areCCTMeasuresComputed(measures)) { + if (isLegacy || !areCCTMeasuresComputed(measures)) { return legacyBubbles; } diff --git a/server/sonar-web/src/main/js/apps/overview/branches/BranchOverviewRenderer.tsx b/server/sonar-web/src/main/js/apps/overview/branches/BranchOverviewRenderer.tsx index cf0210ff8e7..419ea64ef89 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/BranchOverviewRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/BranchOverviewRenderer.tsx @@ -28,7 +28,11 @@ import { CurrentUserContext } from '../../../app/components/current-user/Current import AnalysisMissingInfoMessage from '../../../components/shared/AnalysisMissingInfoMessage'; import { parseDate } from '../../../helpers/dates'; import { translate } from '../../../helpers/l10n'; -import { areCCTMeasuresComputed, isDiffMetric } from '../../../helpers/measures'; +import { + areCCTMeasuresComputed, + areSoftwareQualityRatingsComputed, + isDiffMetric, +} from '../../../helpers/measures'; import { CodeScope } from '../../../helpers/urls'; import { useDismissNoticeMutation } from '../../../queries/users'; import { ApplicationPeriod } from '../../../types/application'; @@ -115,7 +119,8 @@ export default function BranchOverviewRenderer(props: BranchOverviewRendererProp const hasNewCodeMeasures = measures.some((m) => isDiffMetric(m.metric.key)); // Check if any potentially missing uncomputed measure is not present - const isMissingMeasures = !areCCTMeasuresComputed(measures); + const isMissingMeasures = + !areCCTMeasuresComputed(measures) || !areSoftwareQualityRatingsComputed(measures); const selectTab = (tab: CodeScope) => { router.replace({ query: { ...query, codeScope: tab } }); diff --git a/server/sonar-web/src/main/js/apps/overview/branches/QualityGateCondition.tsx b/server/sonar-web/src/main/js/apps/overview/branches/QualityGateCondition.tsx index 9a56ff4a132..1f4bbdcaede 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/QualityGateCondition.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/QualityGateCondition.tsx @@ -157,6 +157,7 @@ export class QualityGateCondition extends React.PureComponent { return this.wrapWithLink(
m.metric.key === metricKey); - const measure = JSON.parse(measureRaw?.value ?? 'null') as SoftwareImpactMeasureData; + const measure = isLegacy + ? undefined + : (JSON.parse(measureRaw?.value ?? 'null') as SoftwareImpactMeasureData); const alternativeMeasure = measures.find( (m) => m.metric.key === SOFTWARE_QUALITIES_METRIC_KEYS_MAP[softwareQuality].deprecatedMetric, ); diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx index a3e938ee67c..e79b7b7126a 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx @@ -46,6 +46,7 @@ import { renderComponent } from '../../../../helpers/testReactTestingUtils'; import { ComponentPropsType } from '../../../../helpers/testUtils'; import { SoftwareImpactSeverity, SoftwareQuality } from '../../../../types/clean-code-taxonomy'; import { ProjectAnalysisEventCategory } from '../../../../types/project-activity'; +import { SettingsKey } from '../../../../types/settings'; import { CaycStatus } from '../../../../types/types'; import BranchOverview, { NO_CI_DETECTED } from '../BranchOverview'; import { getPageObjects } from '../test-utils'; @@ -332,7 +333,7 @@ describe('project overview', () => { ui.expectSoftwareImpactMeasureCard( SoftwareQuality.Maintainability, - 'E', + 'D', { total: 2, [SoftwareImpactSeverity.High]: 0, @@ -343,8 +344,8 @@ describe('project overview', () => { ); await ui.expectSoftwareImpactMeasureCardRatingTooltip( SoftwareQuality.Maintainability, - 'E', - 'overview.measures.software_impact.improve_rating_tooltip.MAINTAINABILITY.software_quality.MAINTAINABILITY.software_quality.maintainability.E.overview.measures.software_impact.severity.HIGH.improve_tooltip', + 'D', + 'overview.measures.software_impact.improve_rating_tooltip.MAINTAINABILITY.software_quality.MAINTAINABILITY.software_quality.maintainability.D.overview.measures.software_impact.severity.HIGH.improve_tooltip', ); }); @@ -357,7 +358,7 @@ describe('project overview', () => { ui.expectSoftwareImpactMeasureCard( SoftwareQuality.Maintainability, - 'E', + 'D', { total: 2, [SoftwareImpactSeverity.High]: 0, @@ -372,8 +373,14 @@ describe('project overview', () => { it('should render old measures if software impact are missing', async () => { // Make as if new analysis after upgrade is missing measuresHandler.deleteComponentMeasure('foo', MetricKey.maintainability_issues); + measuresHandler.deleteComponentMeasure( + 'foo', + MetricKey.software_quality_maintainability_rating, + ); measuresHandler.deleteComponentMeasure('foo', MetricKey.security_issues); + measuresHandler.deleteComponentMeasure('foo', MetricKey.software_quality_security_rating); measuresHandler.deleteComponentMeasure('foo', MetricKey.reliability_issues); + measuresHandler.deleteComponentMeasure('foo', MetricKey.software_quality_reliability_rating); const { user, ui } = getPageObjects(); renderBranchOverview(); @@ -406,12 +413,18 @@ describe('project overview', () => { // Make as if no measures at all measuresHandler.deleteComponentMeasure('foo', MetricKey.maintainability_issues); measuresHandler.deleteComponentMeasure('foo', MetricKey.code_smells); + measuresHandler.deleteComponentMeasure( + 'foo', + MetricKey.software_quality_maintainability_rating, + ); measuresHandler.deleteComponentMeasure('foo', MetricKey.security_issues); measuresHandler.deleteComponentMeasure('foo', MetricKey.vulnerabilities); + measuresHandler.deleteComponentMeasure('foo', MetricKey.software_quality_security_rating); measuresHandler.deleteComponentMeasure('foo', MetricKey.reliability_issues); measuresHandler.deleteComponentMeasure('foo', MetricKey.bugs); + measuresHandler.deleteComponentMeasure('foo', MetricKey.software_quality_reliability_rating); const { user, ui } = getPageObjects(); renderBranchOverview(); @@ -461,6 +474,94 @@ describe('project overview', () => { }, ); + it('should display info about missing analysis if a project did not compute ratings', async () => { + measuresHandler.deleteComponentMeasure('foo', MetricKey.software_quality_security_rating); + measuresHandler.deleteComponentMeasure( + 'foo', + MetricKey.software_quality_maintainability_rating, + ); + measuresHandler.deleteComponentMeasure('foo', MetricKey.software_quality_reliability_rating); + const { user, ui } = getPageObjects(); + renderBranchOverview(); + + await user.click(await ui.overallCodeButton.find()); + + expect(await ui.softwareImpactMeasureCard(SoftwareQuality.Security).find()).toBeInTheDocument(); + + await user.click(await ui.overallCodeButton.find()); + + expect(await screen.findByText('overview.missing_project_dataTRK')).toBeInTheDocument(); + ui.expectSoftwareImpactMeasureCard(SoftwareQuality.Security); + expect( + ui.softwareImpactMeasureCardRating(SoftwareQuality.Security, 'B').get(), + ).toBeInTheDocument(); + + ui.expectSoftwareImpactMeasureCard(SoftwareQuality.Reliability); + expect( + ui.softwareImpactMeasureCardRating(SoftwareQuality.Reliability, 'A').get(), + ).toBeInTheDocument(); + + ui.expectSoftwareImpactMeasureCard(SoftwareQuality.Maintainability); + expect( + ui.softwareImpactMeasureCardRating(SoftwareQuality.Maintainability, 'E').get(), + ).toBeInTheDocument(); + }); + + it('should display old measures if in legacy mode', async () => { + settingsHandler.set(SettingsKey.LegacyMode, 'true'); + const { user, ui } = getPageObjects(); + renderBranchOverview(); + + await user.click(await ui.overallCodeButton.find()); + + expect(await ui.softwareImpactMeasureCard(SoftwareQuality.Security).find()).toBeInTheDocument(); + + await user.click(await ui.overallCodeButton.find()); + + expect(await ui.softwareImpactMeasureCard(SoftwareQuality.Security).find()).toBeInTheDocument(); + + ui.expectSoftwareImpactMeasureCard(SoftwareQuality.Security); + ui.expectSoftwareImpactMeasureCardToHaveOldMeasures( + SoftwareQuality.Security, + 'B', + 2, + 'VULNERABILITY', + ); + + ui.expectSoftwareImpactMeasureCard(SoftwareQuality.Reliability); + ui.expectSoftwareImpactMeasureCardToHaveOldMeasures(SoftwareQuality.Reliability, 'A', 0, 'BUG'); + + ui.expectSoftwareImpactMeasureCard(SoftwareQuality.Maintainability); + ui.expectSoftwareImpactMeasureCardToHaveOldMeasures( + SoftwareQuality.Maintainability, + 'E', + 9, + 'CODE_SMELL', + ); + }); + + it('should not show analysis is missing message in legacy mode', async () => { + measuresHandler.deleteComponentMeasure('foo', MetricKey.software_quality_security_rating); + measuresHandler.deleteComponentMeasure( + 'foo', + MetricKey.software_quality_maintainability_rating, + ); + measuresHandler.deleteComponentMeasure('foo', MetricKey.software_quality_reliability_rating); + settingsHandler.set(SettingsKey.LegacyMode, 'true'); + const { user, ui } = getPageObjects(); + renderBranchOverview(); + + await user.click(await ui.overallCodeButton.find()); + + expect(await ui.softwareImpactMeasureCard(SoftwareQuality.Security).find()).toBeInTheDocument(); + + await user.click(await ui.overallCodeButton.find()); + + expect(await ui.softwareImpactMeasureCard(SoftwareQuality.Security).find()).toBeInTheDocument(); + + expect(screen.queryByText('overview.missing_project_dataTRK')).not.toBeInTheDocument(); + }); + it('should dismiss CaYC promoted section', async () => { qualityGatesHandler.setQualityGateProjectStatus( mockQualityGateProjectStatus({ diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx index f37c00c96a1..42f453267d2 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx @@ -237,6 +237,8 @@ it('should be able to add a condition on overall code', async () => { const dialog = byRole('dialog'); await selectEvent.select(dialog.byRole('combobox').get(), ['Info Issues']); + // In real app there are no metrics with selectable condition operator + // so we manually changed direction for Info Issues to 0 to test this behavior await user.click(dialog.byRole('radio', { name: 'quality_gates.conditions.overall_code' }).get()); await user.click(dialog.byLabelText('quality_gates.conditions.operator').get()); diff --git a/server/sonar-web/src/main/js/components/measure/MeasureIndicator.tsx b/server/sonar-web/src/main/js/components/measure/MeasureIndicator.tsx index 2048193ac0b..0754a3d529a 100644 --- a/server/sonar-web/src/main/js/components/measure/MeasureIndicator.tsx +++ b/server/sonar-web/src/main/js/components/measure/MeasureIndicator.tsx @@ -29,6 +29,7 @@ interface Props { className?: string; componentKey: string; decimals?: number; + forceRatingMetric?: boolean; metricKey: string; metricType: string; small?: boolean; diff --git a/server/sonar-web/src/main/js/components/measure/RatingTooltipContent.tsx b/server/sonar-web/src/main/js/components/measure/RatingTooltipContent.tsx index e64ede3682b..693c9dddc8d 100644 --- a/server/sonar-web/src/main/js/components/measure/RatingTooltipContent.tsx +++ b/server/sonar-web/src/main/js/components/measure/RatingTooltipContent.tsx @@ -57,7 +57,11 @@ export function RatingTooltipContent(props: Readonly) const rating = Number(value); const ratingLetter = formatMeasure(value, MetricType.Rating); - if (finalMetricKey !== MetricKey.sqale_rating && finalMetricKey !== 'maintainability_rating') { + if ( + finalMetricKey !== MetricKey.sqale_rating && + finalMetricKey !== 'maintainability_rating' && + finalMetricKey !== MetricKey.software_quality_maintainability_rating + ) { return <>{translate('metric', finalMetricKey, 'tooltip', ratingLetter)}; } @@ -65,17 +69,20 @@ export function RatingTooltipContent(props: Readonly) const maintainabilityRatingThreshold = maintainabilityGrid[Math.floor(rating) - GRID_INDEX_OFFSET]; + const metricForTooltipText = + finalMetricKey === 'maintainability_rating' ? MetricKey.sqale_rating : finalMetricKey; + return ( // Required to correctly satisfy the context typing // eslint-disable-next-line react/jsx-no-useless-fragment <> {rating === 1 ? translateWithParameters( - 'metric.sqale_rating.tooltip.A', + `metric.${metricForTooltipText}.tooltip.A`, formatMeasure(maintainabilityGrid[0] * PERCENT_MULTIPLIER, MetricType.Percent), ) : translateWithParameters( - 'metric.sqale_rating.tooltip', + `metric.${metricForTooltipText}.tooltip`, ratingLetter, formatMeasure(maintainabilityRatingThreshold * PERCENT_MULTIPLIER, MetricType.Percent), )} diff --git a/server/sonar-web/src/main/js/components/measure/utils.ts b/server/sonar-web/src/main/js/components/measure/utils.ts index 18fe525c61d..60e1437baf7 100644 --- a/server/sonar-web/src/main/js/components/measure/utils.ts +++ b/server/sonar-web/src/main/js/components/measure/utils.ts @@ -17,14 +17,19 @@ * 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 '../../sonar-aligned/types/metrics'; import { Dict, Measure, MeasureEnhanced, MeasureIntern, Metric } from '../../types/types'; export const KNOWN_RATINGS = [ - 'sqale_rating', + MetricKey.sqale_rating, + MetricKey.reliability_rating, + MetricKey.security_rating, + MetricKey.security_review_rating, + MetricKey.software_quality_maintainability_rating, + MetricKey.software_quality_reliability_rating, + MetricKey.software_quality_security_rating, + MetricKey.software_quality_security_review_rating, 'maintainability_rating', // Needed to provide the label for "new_maintainability_rating" - 'reliability_rating', - 'security_rating', - 'security_review_rating', ]; export function enhanceMeasure(measure: Measure, metrics: Dict): MeasureEnhanced { diff --git a/server/sonar-web/src/main/js/helpers/measures.ts b/server/sonar-web/src/main/js/helpers/measures.ts index 315faee7fad..12aa7e736b0 100644 --- a/server/sonar-web/src/main/js/helpers/measures.ts +++ b/server/sonar-web/src/main/js/helpers/measures.ts @@ -116,7 +116,7 @@ export function areCCTMeasuresComputed(measures?: Measure[] | MeasureEnhanced[]) } export function areSoftwareQualityRatingsComputed(measures?: Measure[] | MeasureEnhanced[]) { return [ - MetricKey.software_quality_security_rating, + MetricKey.software_quality_reliability_rating, MetricKey.software_quality_security_rating, MetricKey.software_quality_maintainability_rating, ].every((metric) => diff --git a/server/sonar-web/src/main/js/helpers/mocks/metrics.ts b/server/sonar-web/src/main/js/helpers/mocks/metrics.ts index d191dd1e76b..4bb0a7f82b6 100644 --- a/server/sonar-web/src/main/js/helpers/mocks/metrics.ts +++ b/server/sonar-web/src/main/js/helpers/mocks/metrics.ts @@ -17,11 +17,22 @@ * 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 '../../sonar-aligned/types/metrics'; import { Dict, Metric } from '../../types/types'; export const DEFAULT_METRICS: Dict = { + accepted_issues: { + id: 'AXJMbIl_PAOIsUIE3gt5', + key: 'accepted_issues', + type: 'INT', + name: 'Accepted Issues', + description: 'Accepted issues', + domain: 'Issues', + direction: -1, + qualitative: false, + hidden: false, + }, new_technical_debt: { + id: 'AXJMbIl_PAOIsUIE3guE', key: 'new_technical_debt', type: 'WORK_DUR', name: 'Added Technical Debt', @@ -31,7 +42,20 @@ export const DEFAULT_METRICS: Dict = { qualitative: true, hidden: false, }, + analysis_from_sonarqube_9_4: { + id: 'AX_iDGfBRf9uEywNDdeh', + key: 'analysis_from_sonarqube_9_4', + type: 'BOOL', + name: 'Analysis From SonarQube 9.4', + description: + 'Indicates whether the analysis has been run after the upgrade to SonarQube 9.4. It affects how the issues will be detected for branches that use reference branch as the strategy for detecting new code.', + domain: 'Issues', + direction: 0, + qualitative: false, + hidden: true, + }, blocker_violations: { + id: 'AXJMbIl_PAOIsUIE3gtt', key: 'blocker_violations', type: 'INT', name: 'Blocker Issues', @@ -42,6 +66,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, bugs: { + id: 'AXJMbIl_PAOIsUIE3gt_', key: 'bugs', type: 'INT', name: 'Bugs', @@ -52,6 +77,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, classes: { + id: 'AXJMbImPPAOIsUIE3gu5', key: 'classes', type: 'INT', name: 'Classes', @@ -62,6 +88,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, code_smells: { + id: 'AXJMbIl_PAOIsUIE3gt9', key: 'code_smells', type: 'INT', name: 'Code Smells', @@ -72,6 +99,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, cognitive_complexity: { + id: 'AXJMbIl9PAOIsUIE3gtZ', key: 'cognitive_complexity', type: 'INT', name: 'Cognitive Complexity', @@ -82,6 +110,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, comment_lines: { + id: 'AXJMbImPPAOIsUIE3gup', key: 'comment_lines', type: 'INT', name: 'Comment Lines', @@ -92,6 +121,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, comment_lines_data: { + id: 'AXJMbImPPAOIsUIE3guV', key: 'comment_lines_data', type: 'DATA', name: 'comment_lines_data', @@ -101,6 +131,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, comment_lines_density: { + id: 'AXJMbImPPAOIsUIE3guq', key: 'comment_lines_density', type: 'PERCENT', name: 'Comments (%)', @@ -112,6 +143,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, class_complexity: { + id: 'AXJMbImPPAOIsUIE3guw', key: 'class_complexity', type: 'FLOAT', name: 'Complexity / Class', @@ -123,6 +155,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, file_complexity: { + id: 'AXJMbImPPAOIsUIE3guu', key: 'file_complexity', type: 'FLOAT', name: 'Complexity / File', @@ -134,6 +167,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, function_complexity: { + id: 'AXJMbImPPAOIsUIE3guy', key: 'function_complexity', type: 'FLOAT', name: 'Complexity / Function', @@ -145,6 +179,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, complexity_in_classes: { + id: 'AXJMbImPPAOIsUIE3guv', key: 'complexity_in_classes', type: 'INT', name: 'Complexity in Classes', @@ -155,6 +190,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, complexity_in_functions: { + id: 'AXJMbImPPAOIsUIE3gux', key: 'complexity_in_functions', type: 'INT', name: 'Complexity in Functions', @@ -165,6 +201,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, branch_coverage: { + id: 'AXJMbIl9PAOIsUIE3gs-', key: 'branch_coverage', type: 'PERCENT', name: 'Condition Coverage', @@ -176,6 +213,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, new_branch_coverage: { + id: 'AXJMbIl9PAOIsUIE3gs_', key: 'new_branch_coverage', type: 'PERCENT', name: 'Condition Coverage on New Code', @@ -187,6 +225,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, conditions_to_cover: { + id: 'AXJMbIl9PAOIsUIE3gqt', key: 'conditions_to_cover', type: 'INT', name: 'Conditions to Cover', @@ -197,6 +236,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, new_conditions_to_cover: { + id: 'AXJMbIl9PAOIsUIE3gs7', key: 'new_conditions_to_cover', type: 'INT', name: 'Conditions to Cover on New Code', @@ -207,6 +247,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, confirmed_issues: { + id: 'AXJMbIl_PAOIsUIE3gt8', key: 'confirmed_issues', type: 'INT', name: 'Confirmed Issues', @@ -217,6 +258,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, coverage: { + id: 'AXJMbIl9PAOIsUIE3gtg', key: 'coverage', type: 'PERCENT', name: 'Coverage', @@ -228,6 +270,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, new_coverage: { + id: 'AXJMbIl_PAOIsUIE3gth', key: 'new_coverage', type: 'PERCENT', name: 'Coverage on New Code', @@ -239,6 +282,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, critical_violations: { + id: 'AXJMbIl_PAOIsUIE3gtu', key: 'critical_violations', type: 'INT', name: 'Critical Issues', @@ -249,6 +293,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, complexity: { + id: 'AXJMbImPPAOIsUIE3gut', key: 'complexity', type: 'INT', name: 'Cyclomatic Complexity', @@ -259,6 +304,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, last_commit_date: { + id: 'AXJMbImPPAOIsUIE3gua', key: 'last_commit_date', type: 'MILLISEC', name: 'Date of Last Commit', @@ -268,6 +314,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, development_cost: { + id: 'AXJMbIl_PAOIsUIE3guI', key: 'development_cost', type: 'STRING', name: 'Development Cost', @@ -278,6 +325,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, new_development_cost: { + id: 'AXJMbIl_PAOIsUIE3guJ', key: 'new_development_cost', type: 'FLOAT', name: 'Development Cost on New Code', @@ -288,17 +336,8 @@ export const DEFAULT_METRICS: Dict = { hidden: true, decimalScale: 1, }, - directories: { - key: 'directories', - type: 'INT', - name: 'Directories', - description: 'Directories', - domain: 'Size', - direction: -1, - qualitative: false, - hidden: false, - }, duplicated_blocks: { + id: 'AXJMbIl9PAOIsUIE3gsu', key: 'duplicated_blocks', type: 'INT', name: 'Duplicated Blocks', @@ -309,6 +348,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, new_duplicated_blocks: { + id: 'AXJMbIl_PAOIsUIE3gto', key: 'new_duplicated_blocks', type: 'INT', name: 'Duplicated Blocks on New Code', @@ -319,6 +359,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, duplicated_files: { + id: 'AXJMbImPPAOIsUIE3gvA', key: 'duplicated_files', type: 'INT', name: 'Duplicated Files', @@ -329,6 +370,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, duplicated_lines: { + id: 'AXJMbIl9PAOIsUIE3gss', key: 'duplicated_lines', type: 'INT', name: 'Duplicated Lines', @@ -339,6 +381,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, duplicated_lines_density: { + id: 'AXJMbIl_PAOIsUIE3gtp', key: 'duplicated_lines_density', type: 'PERCENT', name: 'Duplicated Lines (%)', @@ -350,6 +393,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, new_duplicated_lines_density: { + id: 'AXJMbIl_PAOIsUIE3gtq', key: 'new_duplicated_lines_density', type: 'PERCENT', name: 'Duplicated Lines (%) on New Code', @@ -361,6 +405,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, new_duplicated_lines: { + id: 'AXJMbIl9PAOIsUIE3gst', key: 'new_duplicated_lines', type: 'INT', name: 'Duplicated Lines on New Code', @@ -371,6 +416,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, duplications_data: { + id: 'AXJMbIl_PAOIsUIE3gtr', key: 'duplications_data', type: 'DATA', name: 'Duplication Details', @@ -381,6 +427,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, effort_to_reach_maintainability_rating_a: { + id: 'AXJMbIl_PAOIsUIE3guM', key: 'effort_to_reach_maintainability_rating_a', type: 'WORK_DUR', name: 'Effort to Reach Maintainability Rating A', @@ -391,6 +438,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, executable_lines_data: { + id: 'AXJMbImPPAOIsUIE3guW', key: 'executable_lines_data', type: 'DATA', name: 'executable_lines_data', @@ -400,6 +448,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, false_positive_issues: { + id: 'AXJMbIl_PAOIsUIE3gt4', key: 'false_positive_issues', type: 'INT', name: 'False Positive Issues', @@ -410,6 +459,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, file_complexity_distribution: { + id: 'AXJMbIl9PAOIsUIE3gtY', key: 'file_complexity_distribution', type: 'DISTRIB', name: 'File Distribution / Complexity', @@ -420,6 +470,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, files: { + id: 'AXJMbImPPAOIsUIE3gu6', key: 'files', type: 'INT', name: 'Files', @@ -430,6 +481,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, function_complexity_distribution: { + id: 'AXJMbIl9PAOIsUIE3gtX', key: 'function_complexity_distribution', type: 'DISTRIB', name: 'Function Distribution / Complexity', @@ -440,6 +492,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, functions: { + id: 'AXJMbImPPAOIsUIE3gu-', key: 'functions', type: 'INT', name: 'Functions', @@ -450,6 +503,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, generated_lines: { + id: 'AXJMbImPPAOIsUIE3gu0', key: 'generated_lines', type: 'INT', name: 'Generated Lines', @@ -460,6 +514,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, generated_ncloc: { + id: 'AXJMbImPPAOIsUIE3gu4', key: 'generated_ncloc', type: 'INT', name: 'Generated Lines of Code', @@ -469,17 +524,30 @@ export const DEFAULT_METRICS: Dict = { qualitative: false, hidden: false, }, + high_impact_accepted_issues: { + id: 'AY0aC41wVDhd53-OniNc', + key: 'high_impact_accepted_issues', + type: 'INT', + name: 'High Impact Accepted Issues', + description: 'Accepted issues with high impact', + domain: 'Issues', + direction: -1, + qualitative: false, + hidden: false, + }, info_violations: { + id: 'AXJMbIl_PAOIsUIE3gtx', key: 'info_violations', type: 'INT', name: 'Info Issues', description: 'Info issues', domain: 'Issues', - direction: 0, + direction: 0, // manually changed direction to test quality gate condition operator qualitative: true, hidden: false, }, violations: { + id: 'AXJMbImPPAOIsUIE3gul', key: 'violations', type: 'INT', name: 'Issues', @@ -489,7 +557,19 @@ export const DEFAULT_METRICS: Dict = { qualitative: true, hidden: false, }, + prioritized_rule_issues: { + id: '789e3a55-205b-46c8-b9dc-9fa92734c0fc', + key: 'prioritized_rule_issues', + type: 'INT', + name: 'Issues from prioritized rules', + description: 'Count of issues that have a flag Prioritized Rule.', + domain: 'Issues', + direction: -1, + qualitative: true, + hidden: false, + }, last_change_on_maintainability_rating: { + id: 'AXJMbImPPAOIsUIE3gud', key: 'last_change_on_maintainability_rating', type: 'DATA', name: 'Last Change on Maintainability Rating', @@ -499,6 +579,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, last_change_on_releasability_rating: { + id: 'AXJMbImPPAOIsUIE3gue', key: 'last_change_on_releasability_rating', type: 'DATA', name: 'Last Change on Releasability Rating', @@ -508,6 +589,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, last_change_on_reliability_rating: { + id: 'AXJMbImPPAOIsUIE3guf', key: 'last_change_on_reliability_rating', type: 'DATA', name: 'Last Change on Reliability Rating', @@ -517,6 +599,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, last_change_on_security_rating: { + id: 'AXJMbImPPAOIsUIE3gug', key: 'last_change_on_security_rating', type: 'DATA', name: 'Last Change on Security Rating', @@ -526,6 +609,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, last_change_on_security_review_rating: { + id: 'AXJMbIl9PAOIsUIE3gs4', key: 'last_change_on_security_review_rating', type: 'DATA', name: 'Last Change on Security Review Rating', @@ -535,6 +619,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, line_coverage: { + id: 'AXJMbIl_PAOIsUIE3gtl', key: 'line_coverage', type: 'PERCENT', name: 'Line Coverage', @@ -546,6 +631,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, new_line_coverage: { + id: 'AXJMbIl_PAOIsUIE3gtm', key: 'new_line_coverage', type: 'PERCENT', name: 'Line Coverage on New Code', @@ -557,6 +643,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, lines: { + id: 'AXJMbImPPAOIsUIE3guz', key: 'lines', type: 'INT', name: 'Lines', @@ -567,6 +654,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, ncloc: { + id: 'AXJMbImPPAOIsUIE3gu1', key: 'ncloc', type: 'INT', name: 'Lines of Code', @@ -577,6 +665,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, ncloc_language_distribution: { + id: 'AXJMbImPPAOIsUIE3gu3', key: 'ncloc_language_distribution', type: 'DATA', name: 'Lines of Code Per Language', @@ -587,6 +676,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, lines_to_cover: { + id: 'AXJMbImPPAOIsUIE3gu_', key: 'lines_to_cover', type: 'INT', name: 'Lines to Cover', @@ -597,6 +687,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, new_lines_to_cover: { + id: 'AXJMbIl_PAOIsUIE3gti', key: 'new_lines_to_cover', type: 'INT', name: 'Lines to Cover on New Code', @@ -607,6 +698,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, leak_projects: { + id: 'AXJMbImPPAOIsUIE3gvE', key: 'leak_projects', type: 'DATA', name: 'List of technical projects with their leaks', @@ -614,17 +706,30 @@ export const DEFAULT_METRICS: Dict = { qualitative: false, hidden: true, }, + maintainability_issues: { + id: 'acc8fd75-3acf-499f-809c-f104af89d16d', + key: 'maintainability_issues', + type: 'DATA', + name: 'Maintainability Issues', + description: 'Maintainability issues', + domain: 'Maintainability', + direction: 0, + qualitative: false, + hidden: false, + }, sqale_rating: { + id: 'AXJMbIl_PAOIsUIE3guF', key: 'sqale_rating', type: 'RATING', name: 'Maintainability Rating', description: 'A-to-E rating based on the technical debt ratio', domain: 'Maintainability', - direction: 0, + direction: -1, qualitative: true, hidden: false, }, maintainability_rating_distribution: { + id: 'AX3sJDjtJHBehddvNyhN', key: 'maintainability_rating_distribution', type: 'DATA', name: 'Maintainability Rating Distribution', @@ -635,6 +740,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, new_maintainability_rating_distribution: { + id: 'AX3sJDjvJHBehddvNyhR', key: 'new_maintainability_rating_distribution', type: 'DATA', name: 'Maintainability Rating Distribution on New Code', @@ -645,6 +751,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, new_maintainability_rating: { + id: 'AXJMbIl_PAOIsUIE3guH', key: 'new_maintainability_rating', type: 'RATING', name: 'Maintainability Rating on New Code', @@ -655,6 +762,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, major_violations: { + id: 'AXJMbIl_PAOIsUIE3gtv', key: 'major_violations', type: 'INT', name: 'Major Issues', @@ -665,6 +773,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, minor_violations: { + id: 'AXJMbIl_PAOIsUIE3gtw', key: 'minor_violations', type: 'INT', name: 'Minor Issues', @@ -675,6 +784,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, ncloc_data: { + id: 'AXJMbImPPAOIsUIE3guU', key: 'ncloc_data', type: 'DATA', name: 'ncloc_data', @@ -683,7 +793,19 @@ export const DEFAULT_METRICS: Dict = { qualitative: false, hidden: true, }, + new_accepted_issues: { + id: 'AY0aC41wVDhd53-OniNb', + key: 'new_accepted_issues', + type: 'INT', + name: 'New Accepted Issues', + description: 'New accepted issues', + domain: 'Issues', + direction: -1, + qualitative: false, + hidden: false, + }, new_blocker_violations: { + id: 'AXJMbIl_PAOIsUIE3gtz', key: 'new_blocker_violations', type: 'INT', name: 'New Blocker Issues', @@ -694,6 +816,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, new_bugs: { + id: 'AXJMbIl_PAOIsUIE3guA', key: 'new_bugs', type: 'INT', name: 'New Bugs', @@ -704,6 +827,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, new_code_smells: { + id: 'AXJMbIl_PAOIsUIE3gt-', key: 'new_code_smells', type: 'INT', name: 'New Code Smells', @@ -714,6 +838,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, new_critical_violations: { + id: 'AXJMbIl_PAOIsUIE3gt0', key: 'new_critical_violations', type: 'INT', name: 'New Critical Issues', @@ -724,6 +849,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, new_info_violations: { + id: 'AXJMbIl_PAOIsUIE3gt3', key: 'new_info_violations', type: 'INT', name: 'New Info Issues', @@ -734,6 +860,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, new_violations: { + id: 'AXJMbIl_PAOIsUIE3gty', key: 'new_violations', type: 'INT', name: 'New Issues', @@ -744,6 +871,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, new_lines: { + id: 'AXJMbImPPAOIsUIE3gu2', key: 'new_lines', type: 'INT', name: 'New Lines', @@ -753,7 +881,19 @@ export const DEFAULT_METRICS: Dict = { qualitative: false, hidden: false, }, + new_maintainability_issues: { + id: '9385d0e6-8991-40b1-b94a-5a260e6146f0', + key: 'new_maintainability_issues', + type: 'DATA', + name: 'New Maintainability Issues', + description: 'New maintainability issues', + domain: 'Maintainability', + direction: 0, + qualitative: false, + hidden: false, + }, new_major_violations: { + id: 'AXJMbIl_PAOIsUIE3gt1', key: 'new_major_violations', type: 'INT', name: 'New Major Issues', @@ -764,6 +904,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, new_minor_violations: { + id: 'AXJMbIl_PAOIsUIE3gt2', key: 'new_minor_violations', type: 'INT', name: 'New Minor Issues', @@ -773,7 +914,19 @@ export const DEFAULT_METRICS: Dict = { qualitative: true, hidden: false, }, + new_reliability_issues: { + id: 'e1cbc8a4-82d7-4d41-8c95-ad86fcd3d57d', + key: 'new_reliability_issues', + type: 'DATA', + name: 'New Reliability Issues', + description: 'New reliability issues', + domain: 'Reliability', + direction: 0, + qualitative: false, + hidden: false, + }, new_security_hotspots: { + id: 'AXJMbIl9PAOIsUIE3gsw', key: 'new_security_hotspots', type: 'INT', name: 'New Security Hotspots', @@ -783,7 +936,19 @@ export const DEFAULT_METRICS: Dict = { qualitative: true, hidden: false, }, + new_security_issues: { + id: '6887ef7d-ee21-449c-b1ff-f3f7930ba27f', + key: 'new_security_issues', + type: 'DATA', + name: 'New Security Issues', + description: 'New security issues', + domain: 'Security', + direction: 0, + qualitative: false, + hidden: false, + }, new_vulnerabilities: { + id: 'AXJMbIl_PAOIsUIE3guC', key: 'new_vulnerabilities', type: 'INT', name: 'New Vulnerabilities', @@ -794,6 +959,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, unanalyzed_c: { + id: 'AXTb6RMqLLQlB5osv3xN', key: 'unanalyzed_c', type: 'INT', name: 'Number of unanalyzed c files', @@ -803,6 +969,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, unanalyzed_cpp: { + id: 'AXTb6RMtLLQlB5osv3xO', key: 'unanalyzed_cpp', type: 'INT', name: 'Number of unanalyzed c++ files', @@ -812,6 +979,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, open_issues: { + id: 'AXJMbIl_PAOIsUIE3gt6', key: 'open_issues', type: 'INT', name: 'Open Issues', @@ -822,6 +990,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, quality_profiles: { + id: 'AXJMbImPPAOIsUIE3guZ', key: 'quality_profiles', type: 'DATA', name: 'Profiles', @@ -831,17 +1000,8 @@ export const DEFAULT_METRICS: Dict = { qualitative: false, hidden: true, }, - [MetricKey.prioritized_rule_issues]: { - key: 'prioritized_rule_issues', - type: 'INT', - name: 'Issues from prioritized rules', - description: 'Count of issues that have a flag Prioritized Rule.', - domain: 'Issues', - direction: -1, - qualitative: true, - hidden: false, - }, projects: { + id: 'AXJMbImPPAOIsUIE3guo', key: 'projects', type: 'INT', name: 'Project branches', @@ -852,6 +1012,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, public_api: { + id: 'AXJMbImPPAOIsUIE3gun', key: 'public_api', type: 'INT', name: 'Public API', @@ -862,6 +1023,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, public_documented_api_density: { + id: 'AXJMbImPPAOIsUIE3gur', key: 'public_documented_api_density', type: 'PERCENT', name: 'Public Documented API (%)', @@ -873,6 +1035,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, public_undocumented_api: { + id: 'AXJMbImPPAOIsUIE3gus', key: 'public_undocumented_api', type: 'INT', name: 'Public Undocumented API', @@ -882,7 +1045,19 @@ export const DEFAULT_METRICS: Dict = { qualitative: true, hidden: true, }, + pull_request_fixed_issues: { + id: 'AY0aC410VDhd53-OniNd', + key: 'pull_request_fixed_issues', + type: 'INT', + name: 'Pull request fixed issues', + description: 'Count of issues that would be fixed by the pull request.', + domain: 'Issues', + direction: 1, + qualitative: false, + hidden: true, + }, quality_gate_details: { + id: 'AXJMbImPPAOIsUIE3guY', key: 'quality_gate_details', type: 'DATA', name: 'Quality Gate Details', @@ -893,6 +1068,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, alert_status: { + id: 'AXJMbImPPAOIsUIE3guX', key: 'alert_status', type: 'LEVEL', name: 'Quality Gate Status', @@ -903,6 +1079,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, releasability_rating: { + id: 'AXJMbImPPAOIsUIE3guc', key: 'releasability_rating', type: 'RATING', name: 'Releasability rating', @@ -912,6 +1089,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, releasability_rating_distribution: { + id: 'AX3sJDivJHBehddvNyhM', key: 'releasability_rating_distribution', type: 'DATA', name: 'Releasability Rating Distribution', @@ -922,26 +1100,18 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, reliability_issues: { + id: 'b11a4b65-4070-487d-a973-8ec85e2858b3', key: 'reliability_issues', type: 'DATA', - name: 'Reliability', + name: 'Reliability Issues', description: 'Reliability issues', domain: 'Reliability', direction: 0, qualitative: false, hidden: false, }, - new_reliability_issues: { - key: 'new_reliability_issues', - type: 'DATA', - name: 'New Reliability', - description: 'New Reliability issues', - domain: 'Reliability', - direction: 0, - qualitative: false, - hidden: false, - }, reliability_rating: { + id: 'AXJMbIl_PAOIsUIE3guP', key: 'reliability_rating', type: 'RATING', name: 'Reliability Rating', @@ -952,6 +1122,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, reliability_rating_distribution: { + id: 'AX3sJDjuJHBehddvNyhO', key: 'reliability_rating_distribution', type: 'DATA', name: 'Reliability Rating Distribution', @@ -962,6 +1133,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, new_reliability_rating_distribution: { + id: 'AX3sJDjvJHBehddvNyhS', key: 'new_reliability_rating_distribution', type: 'DATA', name: 'Reliability Rating Distribution on New Code', @@ -972,6 +1144,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, new_reliability_rating: { + id: 'AXJMbIl_PAOIsUIE3guQ', key: 'new_reliability_rating', type: 'RATING', name: 'Reliability Rating on New Code', @@ -982,6 +1155,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, reliability_remediation_effort: { + id: 'AXJMbIl_PAOIsUIE3guN', key: 'reliability_remediation_effort', type: 'WORK_DUR', name: 'Reliability Remediation Effort', @@ -992,6 +1166,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, new_reliability_remediation_effort: { + id: 'AXJMbIl_PAOIsUIE3guO', key: 'new_reliability_remediation_effort', type: 'WORK_DUR', name: 'Reliability Remediation Effort on New Code', @@ -1002,6 +1177,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, reopened_issues: { + id: 'AXJMbIl_PAOIsUIE3gt7', key: 'reopened_issues', type: 'INT', name: 'Reopened Issues', @@ -1012,6 +1188,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, security_hotspots: { + id: 'AXJMbIl9PAOIsUIE3gsv', key: 'security_hotspots', type: 'INT', name: 'Security Hotspots', @@ -1022,6 +1199,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, security_hotspots_reviewed: { + id: 'AXJMbIl9PAOIsUIE3gs0', key: 'security_hotspots_reviewed', type: 'PERCENT', name: 'Security Hotspots Reviewed', @@ -1033,6 +1211,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, new_security_hotspots_reviewed: { + id: 'AXJMbIl9PAOIsUIE3gs1', key: 'new_security_hotspots_reviewed', type: 'PERCENT', name: 'Security Hotspots Reviewed on New Code', @@ -1044,26 +1223,18 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, security_issues: { + id: 'e6ddc573-16b7-4bc4-aff8-6d28b59035e0', key: 'security_issues', type: 'DATA', - name: 'Security', + name: 'Security Issues', description: 'Security issues', domain: 'Security', direction: 0, qualitative: false, hidden: false, }, - new_security_issues: { - key: 'new_security_issues', - type: 'DATA', - name: 'Security', - description: 'New Security issues', - domain: 'Security', - direction: 0, - qualitative: false, - hidden: false, - }, security_rating: { + id: 'AXJMbIl_PAOIsUIE3guS', key: 'security_rating', type: 'RATING', name: 'Security Rating', @@ -1074,6 +1245,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, security_rating_distribution: { + id: 'AX3sJDjuJHBehddvNyhP', key: 'security_rating_distribution', type: 'DATA', name: 'Security Rating Distribution', @@ -1084,6 +1256,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, new_security_rating_distribution: { + id: 'AX3sJDjvJHBehddvNyhT', key: 'new_security_rating_distribution', type: 'DATA', name: 'Security Rating Distribution on New Code', @@ -1094,6 +1267,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, new_security_rating: { + id: 'AXJMbImPPAOIsUIE3guT', key: 'new_security_rating', type: 'RATING', name: 'Security Rating on New Code', @@ -1104,6 +1278,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, security_remediation_effort: { + id: 'AXJMbIl_PAOIsUIE3guG', key: 'security_remediation_effort', type: 'WORK_DUR', name: 'Security Remediation Effort', @@ -1114,6 +1289,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, new_security_remediation_effort: { + id: 'AXJMbIl_PAOIsUIE3guR', key: 'new_security_remediation_effort', type: 'WORK_DUR', name: 'Security Remediation Effort on New Code', @@ -1124,6 +1300,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, security_review_rating: { + id: 'AXJMbIl9PAOIsUIE3gsx', key: 'security_review_rating', type: 'RATING', name: 'Security Review Rating', @@ -1134,6 +1311,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, security_review_rating_distribution: { + id: 'AX3sJDjuJHBehddvNyhQ', key: 'security_review_rating_distribution', type: 'DATA', name: 'Security Review Rating Distribution', @@ -1144,6 +1322,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, new_security_review_rating_distribution: { + id: 'AX3sJDjwJHBehddvNyhU', key: 'new_security_review_rating_distribution', type: 'DATA', name: 'Security Review Rating Distribution on New Code', @@ -1154,6 +1333,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, new_security_review_rating: { + id: 'AXJMbIl9PAOIsUIE3gtA', key: 'new_security_review_rating', type: 'RATING', name: 'Security Review Rating on New Code', @@ -1164,6 +1344,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, security_hotspots_reviewed_status: { + id: 'AXJMbIl9PAOIsUIE3gs2', key: 'security_hotspots_reviewed_status', type: 'INT', name: 'Security Review Reviewed Status', @@ -1174,6 +1355,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, new_security_hotspots_reviewed_status: { + id: 'AXJMbIl9PAOIsUIE3gtB', key: 'new_security_hotspots_reviewed_status', type: 'INT', name: 'Security Review Reviewed Status on New Code', @@ -1184,6 +1366,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, security_hotspots_to_review_status: { + id: 'AXJMbIl9PAOIsUIE3gs3', key: 'security_hotspots_to_review_status', type: 'INT', name: 'Security Review To Review Status', @@ -1194,6 +1377,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, new_security_hotspots_to_review_status: { + id: 'AXJMbIl9PAOIsUIE3gs5', key: 'new_security_hotspots_to_review_status', type: 'INT', name: 'Security Review To Review Status on New Code', @@ -1204,6 +1388,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, skipped_tests: { + id: 'AXJMbIl9PAOIsUIE3gtd', key: 'skipped_tests', type: 'INT', name: 'Skipped Unit Tests', @@ -1213,48 +1398,223 @@ export const DEFAULT_METRICS: Dict = { qualitative: true, hidden: false, }, - statements: { - key: 'statements', - type: 'INT', - name: 'Statements', - description: 'Number of statements', - domain: 'Size', + effort_to_reach_software_quality_maintainability_rating_a: { + id: '0f195cdf-5d79-4be0-90e4-c6e0afb58551', + key: 'effort_to_reach_software_quality_maintainability_rating_a', + type: 'WORK_DUR', + name: 'Software Quality Effort to Reach Maintainability Rating A', + description: 'Software quality effort to reach maintainability rating A', + domain: 'Maintainability', direction: -1, - qualitative: false, + qualitative: true, hidden: false, }, - maintainability_issues: { - key: 'maintainability_issues', - type: 'DATA', - name: 'Maintainability', - description: 'Maintainability issues', + software_quality_maintainability_rating: { + id: '9fc76baf-f660-4f65-a271-b2ae7f849239', + key: 'software_quality_maintainability_rating', + type: 'RATING', + name: 'Software Quality Maintainability Rating', + description: 'Software quality maintainability rating', domain: 'Maintainability', - direction: 0, - qualitative: false, + direction: -1, + qualitative: true, hidden: false, }, - new_maintainability_issues: { - key: 'new_maintainability_issues', - type: 'DATA', - name: 'Maintainability', - description: 'New Maintainability issues', + new_software_quality_maintainability_rating: { + id: 'c5d12cc4-e712-4701-a395-c9113ce13c3e', + key: 'new_software_quality_maintainability_rating', + type: 'RATING', + name: 'Software Quality Maintainability Rating on New Code', + description: 'Software quality maintainability rating on new code', domain: 'Maintainability', - direction: 0, + direction: -1, + qualitative: true, + hidden: false, + }, + software_quality_maintainability_remediation_effort: { + id: '24edda40-db1c-4acd-9c9b-66d5bcca8486', + key: 'software_quality_maintainability_remediation_effort', + type: 'WORK_DUR', + name: 'Software Quality Maintainability Remediation Effort', + description: + 'Software quality total effort (in minutes) to fix all the maintainability issues on the component and therefore to comply to all the requirements.', + domain: 'Maintainability', + direction: -1, + qualitative: true, + hidden: false, + }, + new_software_quality_maintainability_remediation_effort: { + id: 'bf182476-9397-4471-812d-7e40568ef1b0', + key: 'new_software_quality_maintainability_remediation_effort', + type: 'WORK_DUR', + name: 'Software Quality Maintainability Remediation Effort on new code', + description: + 'Software quality total effort (in minutes) to fix all the maintainability issues on new code on the component and therefore to comply to all the requirements.', + domain: 'Maintainability', + direction: -1, + qualitative: true, + hidden: false, + }, + software_quality_reliability_rating: { + id: '6548ffa4-8a5e-4445-a28d-e2fd9fdbba78', + key: 'software_quality_reliability_rating', + type: 'RATING', + name: 'Software Quality Reliability Rating', + description: 'Software quality reliability rating', + domain: 'Reliability', + direction: -1, + qualitative: true, + hidden: false, + }, + new_software_quality_reliability_rating: { + id: 'ab82dcac-cf81-4780-965d-1384ce9e8983', + key: 'new_software_quality_reliability_rating', + type: 'RATING', + name: 'Software Quality Reliability Rating on New Code', + description: 'Software quality reliability rating on new code', + domain: 'Reliability', + direction: -1, + qualitative: true, + hidden: false, + }, + software_quality_reliability_remediation_effort: { + id: 'f2094b93-e08c-4350-ad8f-f265974278a8', + key: 'software_quality_reliability_remediation_effort', + type: 'WORK_DUR', + name: 'Software Quality Reliability Remediation Effort', + description: 'Software quality reliability remediation effort', + domain: 'Reliability', + direction: -1, + qualitative: true, + hidden: false, + }, + new_software_quality_reliability_remediation_effort: { + id: '45f9a292-5f6e-459e-8d81-134d5aaedef9', + key: 'new_software_quality_reliability_remediation_effort', + type: 'WORK_DUR', + name: 'Software Quality Reliability Remediation Effort on New Code', + description: 'Software quality reliability remediation effort on new code', + domain: 'Reliability', + direction: -1, + qualitative: true, + hidden: false, + }, + software_quality_security_rating: { + id: 'db22dacd-a3fd-41d2-8617-0cb7cfc86429', + key: 'software_quality_security_rating', + type: 'RATING', + name: 'Software Quality Security Rating', + description: 'Software quality security rating', + domain: 'Security', + direction: -1, + qualitative: true, + hidden: false, + }, + new_software_quality_security_rating: { + id: '228b9a04-09a2-418e-9ea4-3584a57a95ba', + key: 'new_software_quality_security_rating', + type: 'RATING', + name: 'Software Quality Security Rating on New Code', + description: 'Software quality security rating on new code', + domain: 'Security', + direction: -1, + qualitative: true, + hidden: false, + }, + software_quality_security_remediation_effort: { + id: '43652a84-3ca7-4506-9c09-00ea2b6c6e71', + key: 'software_quality_security_remediation_effort', + type: 'WORK_DUR', + name: 'Software Quality Security Remediation Effort', + description: 'Software quality security remediation effort', + domain: 'Security', + direction: -1, + qualitative: true, + hidden: false, + }, + new_software_quality_security_remediation_effort: { + id: 'd5d0020a-419c-4387-b00f-523ad8a6a3e4', + key: 'new_software_quality_security_remediation_effort', + type: 'WORK_DUR', + name: 'Software Quality Security Remediation Effort on New Code', + description: 'Software quality security remediation effort on new code', + domain: 'Security', + direction: -1, + qualitative: true, + hidden: false, + }, + software_quality_security_review_rating: { + id: '6e09531b-dee8-4c23-9a76-dc335cf79019', + key: 'software_quality_security_review_rating', + type: 'RATING', + name: 'Software Quality Security Review Rating', + description: 'Software quality security review rating', + domain: 'SecurityReview', + direction: -1, + qualitative: true, + hidden: false, + }, + new_software_quality_security_review_rating: { + id: '4d4b1d18-da7e-403c-a3f0-99951c58b050', + key: 'new_software_quality_security_review_rating', + type: 'RATING', + name: 'Software Quality Security Review Rating on New Code', + description: 'Software quality security review rating on new code', + domain: 'SecurityReview', + direction: -1, + qualitative: true, + hidden: false, + }, + software_quality_maintainability_debt_ratio: { + id: '8a7a5279-9dfe-4fdf-9886-9203ae50be5c', + key: 'software_quality_maintainability_debt_ratio', + type: 'PERCENT', + name: 'Software Quality Technical Debt Ratio', + description: + 'Software quality ratio of the actual technical debt compared to the estimated cost to develop the whole source code from scratch', + domain: 'Maintainability', + direction: -1, + qualitative: true, + hidden: false, + decimalScale: 1, + }, + new_software_quality_maintainability_debt_ratio: { + id: '23330467-a21e-4254-a76a-2eb99aab6f0f', + key: 'new_software_quality_maintainability_debt_ratio', + type: 'PERCENT', + name: 'Software Quality Technical Debt Ratio on New Code', + description: 'Software quality technical debt ratio software quality of new/changed code.', + domain: 'Maintainability', + direction: -1, + qualitative: true, + hidden: false, + decimalScale: 1, + }, + statements: { + id: 'AXJMbImPPAOIsUIE3gum', + key: 'statements', + type: 'INT', + name: 'Statements', + description: 'Number of statements', + domain: 'Size', + direction: -1, qualitative: false, hidden: false, }, sqale_index: { + id: 'AXJMbIl_PAOIsUIE3guD', key: 'sqale_index', type: 'WORK_DUR', name: 'Technical Debt', description: - 'Total effort (in hours) to fix all the issues on the component and therefore to comply to all the requirements.', + 'Total effort (in minutes) to fix all the issues on the component and therefore to comply to all the requirements.', domain: 'Maintainability', direction: -1, qualitative: true, hidden: false, }, sqale_debt_ratio: { + id: 'AXJMbIl_PAOIsUIE3guK', key: 'sqale_debt_ratio', type: 'PERCENT', name: 'Technical Debt Ratio', @@ -1267,6 +1627,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, new_sqale_debt_ratio: { + id: 'AXJMbIl_PAOIsUIE3guL', key: 'new_sqale_debt_ratio', type: 'PERCENT', name: 'Technical Debt Ratio on New Code', @@ -1278,6 +1639,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, maintainability_rating_effort: { + id: 'AXJMbImPPAOIsUIE3gvD', key: 'maintainability_rating_effort', type: 'DATA', name: 'Total number of projects having worst maintainability rating', @@ -1287,6 +1649,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, reliability_rating_effort: { + id: 'AXJMbImPPAOIsUIE3gvC', key: 'reliability_rating_effort', type: 'DATA', name: 'Total number of projects having worst reliability rating', @@ -1296,6 +1659,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, security_rating_effort: { + id: 'AXJMbImPPAOIsUIE3gvB', key: 'security_rating_effort', type: 'DATA', name: 'Total number of projects having worst security rating', @@ -1305,6 +1669,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, security_review_rating_effort: { + id: 'AXJMbIl9PAOIsUIE3gs6', key: 'security_review_rating_effort', type: 'DATA', name: 'Total number of projects having worst security review rating', @@ -1314,6 +1679,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, releasability_effort: { + id: 'AXJMbImPPAOIsUIE3gub', key: 'releasability_effort', type: 'INT', name: 'Total number of projects not production ready', @@ -1323,6 +1689,7 @@ export const DEFAULT_METRICS: Dict = { hidden: true, }, uncovered_conditions: { + id: 'AXJMbIl9PAOIsUIE3gs8', key: 'uncovered_conditions', type: 'INT', name: 'Uncovered Conditions', @@ -1333,6 +1700,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, new_uncovered_conditions: { + id: 'AXJMbIl9PAOIsUIE3gs9', key: 'new_uncovered_conditions', type: 'INT', name: 'Uncovered Conditions on New Code', @@ -1343,6 +1711,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, uncovered_lines: { + id: 'AXJMbIl_PAOIsUIE3gtj', key: 'uncovered_lines', type: 'INT', name: 'Uncovered Lines', @@ -1353,6 +1722,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, new_uncovered_lines: { + id: 'AXJMbIl_PAOIsUIE3gtk', key: 'new_uncovered_lines', type: 'INT', name: 'Uncovered Lines on New Code', @@ -1363,6 +1733,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, test_execution_time: { + id: 'AXJMbIl9PAOIsUIE3gtb', key: 'test_execution_time', type: 'MILLISEC', name: 'Unit Test Duration', @@ -1373,6 +1744,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, test_errors: { + id: 'AXJMbIl9PAOIsUIE3gtc', key: 'test_errors', type: 'INT', name: 'Unit Test Errors', @@ -1383,6 +1755,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, test_failures: { + id: 'AXJMbIl9PAOIsUIE3gte', key: 'test_failures', type: 'INT', name: 'Unit Test Failures', @@ -1393,6 +1766,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, tests: { + id: 'AXJMbIl9PAOIsUIE3gta', key: 'tests', type: 'INT', name: 'Unit Tests', @@ -1403,6 +1777,7 @@ export const DEFAULT_METRICS: Dict = { hidden: false, }, test_success_density: { + id: 'AXJMbIl9PAOIsUIE3gtf', key: 'test_success_density', type: 'PERCENT', name: 'Unit Test Success (%)', @@ -1414,6 +1789,7 @@ export const DEFAULT_METRICS: Dict = { decimalScale: 1, }, vulnerabilities: { + id: 'AXJMbIl_PAOIsUIE3guB', key: 'vulnerabilities', type: 'INT', name: 'Vulnerabilities', @@ -1423,24 +1799,4 @@ export const DEFAULT_METRICS: Dict = { qualitative: false, hidden: false, }, - accepted_issues: { - key: 'accepted_issues', - type: 'INT', - name: 'Accepted Issues', - description: 'Accepted issues', - domain: 'Issues', - direction: -1, - qualitative: false, - hidden: false, - }, - new_accepted_issues: { - key: 'new_accepted_issues', - type: 'INT', - name: 'New Accepted Issues', - description: 'New Accepted issues', - domain: 'Issues', - direction: -1, - qualitative: false, - hidden: false, - }, }; diff --git a/server/sonar-web/src/main/js/queries/measures.ts b/server/sonar-web/src/main/js/queries/measures.ts index 2acbbaca5f6..57a5f6fb182 100644 --- a/server/sonar-web/src/main/js/queries/measures.ts +++ b/server/sonar-web/src/main/js/queries/measures.ts @@ -33,7 +33,6 @@ import { getMeasuresWithPeriodAndMetrics, } from '../api/measures'; import { getAllTimeMachineData } from '../api/time-machine'; -import { SOFTWARE_QUALITY_RATING_METRICS } from '../helpers/constants'; import { getNextPageParam, getPreviousPageParam } from '../helpers/react-query'; import { getBranchLikeQuery } from '../sonar-aligned/helpers/branch-like'; import { MetricKey } from '../sonar-aligned/types/metrics'; @@ -41,17 +40,6 @@ import { BranchLike } from '../types/branch-like'; import { Measure } from '../types/types'; import { createInfiniteQueryHook, createQueryHook } from './common'; -const NEW_METRICS = [ - MetricKey.software_quality_maintainability_rating, - MetricKey.software_quality_security_rating, - MetricKey.new_software_quality_security_rating, - MetricKey.software_quality_reliability_rating, - MetricKey.new_software_quality_reliability_rating, - MetricKey.software_quality_security_review_rating, - MetricKey.new_software_quality_security_review_rating, - MetricKey.new_software_quality_maintainability_rating, -]; - export function useAllMeasuresHistoryQuery( component: string | undefined, branchParams: BranchParameters, @@ -91,7 +79,9 @@ export const useMeasuresComponentQuery = createQueryHook( queryFn: async () => { const data = await getMeasuresWithPeriodAndMetrics( componentKey, - metricKeys.filter((m) => !SOFTWARE_QUALITY_RATING_METRICS.includes(m as MetricKey)), + metricKeys.filter( + (m) => ![MetricKey.software_quality_releasability_rating].includes(m as MetricKey), + ), branchLikeQuery, ); metricKeys.forEach((metricKey) => { @@ -136,7 +126,9 @@ export const useComponentTreeQuery = createInfiniteQueryHook( const result = await getComponentTree( strategy, component, - metrics?.filter((m) => !SOFTWARE_QUALITY_RATING_METRICS.includes(m as MetricKey)), + metrics?.filter( + (m) => ![MetricKey.software_quality_releasability_rating].includes(m as MetricKey), + ), { ...additionalData, p: pageParam, ...branchLikeQuery }, ); @@ -192,11 +184,7 @@ export const useMeasuresForProjectsQuery = createQueryHook( return queryOptions({ queryKey: ['measures', 'list', 'projects', projectKeys, metricKeys], queryFn: async () => { - // TODO remove this once all metrics are supported - const filteredMetricKeys = metricKeys.filter( - (metricKey) => !SOFTWARE_QUALITY_RATING_METRICS.includes(metricKey as MetricKey), - ); - const measures = await getMeasuresForProjects(projectKeys, filteredMetricKeys); + const measures = await getMeasuresForProjects(projectKeys, metricKeys); const measuresMapByProjectKey = groupBy(measures, 'component'); projectKeys.forEach((projectKey) => { const measuresForProject = measuresMapByProjectKey[projectKey] ?? []; @@ -239,13 +227,9 @@ export const useMeasuresAndLeakQuery = createQueryHook( branchParameters, ], queryFn: async () => { - // TODO remove this once all metrics are supported - const filteredMetricKeys = metricKeys.filter( - (metricKey) => !NEW_METRICS.includes(metricKey as MetricKey), - ); const { component, metrics, period } = await getMeasuresWithPeriodAndMetrics( componentKey, - filteredMetricKeys, + metricKeys, branchParameters, ); const measuresMapByMetricKey = groupBy(component.measures, 'metric'); diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/measure/Measure.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/measure/Measure.tsx index c9381dc62d4..dc0f4c4b28d 100644 --- a/server/sonar-web/src/main/js/sonar-aligned/components/measure/Measure.tsx +++ b/server/sonar-web/src/main/js/sonar-aligned/components/measure/Measure.tsx @@ -35,6 +35,7 @@ interface Props { componentKey: string; decimals?: number; fontClassName?: `sw-body-${string}` | `sw-heading-lg`; + forceRatingMetric?: boolean; metricKey: string; metricType: string; small?: boolean; @@ -50,6 +51,7 @@ export default function Measure({ metricKey, branchLike, metricType, + forceRatingMetric, small, value, }: Readonly) { @@ -109,6 +111,7 @@ export default function Measure({ const rating = ( 1 -- 2.39.5