From 1a992cf69d4dfc5b189b9d05fa64928bac9cfe17 Mon Sep 17 00:00:00 2001 From: Mathieu Suen Date: Thu, 16 May 2024 10:44:00 +0200 Subject: [PATCH] SONAR-22216 Add the after merge information in PRs overview --- .../overview/components/AfterMergeNote.tsx | 42 +++++++++++++++++++ .../components/MeasuresCardPercent.tsx | 21 ++++++---- .../pullRequests/MeasuresCardPanel.tsx | 2 + .../__tests__/PullRequestOverview-it.tsx | 7 ++++ .../resources/org/sonar/l10n/core.properties | 3 +- 5 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 server/sonar-web/src/main/js/apps/overview/components/AfterMergeNote.tsx diff --git a/server/sonar-web/src/main/js/apps/overview/components/AfterMergeNote.tsx b/server/sonar-web/src/main/js/apps/overview/components/AfterMergeNote.tsx new file mode 100644 index 00000000000..9bb4f6f2f5c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/components/AfterMergeNote.tsx @@ -0,0 +1,42 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 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 { Note } from 'design-system'; +import React from 'react'; +import { FormattedMessage } from 'react-intl'; +import { formatMeasure } from '~sonar-aligned/helpers/measures'; +import { MetricKey, MetricType } from '~sonar-aligned/types/metrics'; +import { findMeasure } from '../../../helpers/measures'; +import { MeasureEnhanced } from '../../../types/types'; + +interface Props { + measures: MeasureEnhanced[]; + overallMetric: MetricKey; +} + +export default function AfterMergeNote({ measures, overallMetric }: Readonly) { + const afterMergeValue = findMeasure(measures, overallMetric)?.value; + + return afterMergeValue ? ( + + {formatMeasure(afterMergeValue, MetricType.Percent)} + + + ) : null; +} diff --git a/server/sonar-web/src/main/js/apps/overview/components/MeasuresCardPercent.tsx b/server/sonar-web/src/main/js/apps/overview/components/MeasuresCardPercent.tsx index a225ca5dfa7..f29fc280146 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/MeasuresCardPercent.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/MeasuresCardPercent.tsx @@ -17,14 +17,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { LinkHighlight, LinkStandalone } from '@sonarsource/echoes-react'; import classNames from 'classnames'; -import { - ContentLink, - CoverageIndicator, - DuplicationsIndicator, - LightLabel, - TextError, -} from 'design-system'; +import { CoverageIndicator, DuplicationsIndicator, LightLabel, TextError } from 'design-system'; import * as React from 'react'; import { FormattedMessage, useIntl } from 'react-intl'; import { To } from 'react-router-dom'; @@ -34,6 +29,7 @@ import { duplicationRatingConverter, getLeakValue } from '../../../components/me import { translate, translateWithParameters } from '../../../helpers/l10n'; import { findMeasure, localizeMetric } from '../../../helpers/measures'; import { getComponentDrilldownUrl } from '../../../helpers/urls'; +import { isPullRequest } from '../../../sonar-aligned/helpers/branch-like'; import { BranchLike } from '../../../types/branch-like'; import { QualityGateStatusConditionEnhanced } from '../../../types/quality-gates'; import { MeasureEnhanced } from '../../../types/types'; @@ -43,6 +39,7 @@ import { getConditionRequiredLabel, getMeasurementMetricKey, } from '../utils'; +import AfterMergeNote from './AfterMergeNote'; import MeasuresCard from './MeasuresCard'; interface Props { @@ -55,6 +52,7 @@ interface Props { conditions: QualityGateStatusConditionEnhanced[]; conditionMetric: MetricKey; linesMetric: MetricKey; + overallConditionMetric?: MetricKey; useDiffMetric?: boolean; showRequired?: boolean; } @@ -71,6 +69,7 @@ export default function MeasuresCardPercent( measures, conditions, conditionMetric, + overallConditionMetric, linesMetric, useDiffMetric = false, showRequired = false, @@ -131,7 +130,8 @@ export default function MeasuresCardPercent( id={linesLabel} values={{ link: ( - {formatMeasure(linesValue ?? '0', MetricType.ShortInteger)} - + ), }} /> + {overallConditionMetric && isPullRequest(branchLike) && ( + + )} ); } diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/MeasuresCardPanel.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/MeasuresCardPanel.tsx index e1780472c0f..101f1cb5cfb 100644 --- a/server/sonar-web/src/main/js/apps/overview/pullRequests/MeasuresCardPanel.tsx +++ b/server/sonar-web/src/main/js/apps/overview/pullRequests/MeasuresCardPanel.tsx @@ -71,6 +71,7 @@ export default function MeasuresCardPanel(props: React.PropsWithChildren) })} conditions={conditions} conditionMetric={MetricKey.new_coverage} + overallConditionMetric={MetricKey.coverage} linesMetric={MetricKey.new_lines_to_cover} measures={measures} showRequired @@ -106,6 +107,7 @@ export default function MeasuresCardPanel(props: React.PropsWithChildren) })} conditions={conditions} conditionMetric={MetricKey.new_duplicated_lines_density} + overallConditionMetric={MetricKey.duplicated_lines_density} linesMetric={MetricKey.new_lines} measures={measures} useDiffMetric diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-it.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-it.tsx index 44478340b69..4ff9d9a9378 100644 --- a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-it.tsx +++ b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-it.tsx @@ -51,6 +51,9 @@ jest.mock('../../../../api/measures', () => { mockMeasure({ metric: MetricKey.new_coverage, }), + mockMeasure({ + metric: MetricKey.coverage, + }), mockMeasure({ metric: MetricKey.duplicated_lines, }), @@ -70,6 +73,7 @@ jest.mock('../../../../api/measures', () => { }, metrics: [ mockMetric({ key: MetricKey.new_coverage }), + mockMetric({ key: MetricKey.coverage }), mockMetric({ key: MetricKey.duplicated_lines }), mockMetric({ key: MetricKey.new_lines, type: MetricType.ShortInteger }), mockMetric({ key: MetricKey.new_bugs, type: MetricType.Integer }), @@ -181,6 +185,9 @@ it('should render correctly for a passed QG', async () => { expect(screen.getByLabelText('overview.quality_gate_x.overview.gate.OK')).toBeInTheDocument(); expect(screen.getByText('metric.new_lines.name')).toBeInTheDocument(); + expect( + screen.getByText('component_measures.facet_category.overall_category.estimated'), + ).toBeInTheDocument(); expect(screen.getByText(/overview.last_analysis_x/)).toBeInTheDocument(); }); diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 46eb48c9a60..824f1bf2c0b 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -3912,8 +3912,7 @@ overview.quality_gate.duplications=Duplications overview.new_coverage.on_x_new_lines=On {link} New Lines to cover. overview.coverage.on_x_new_lines=On {link} lines to cover. overview.new_duplicated_lines_density.on_x_new_lines=On {link} New Lines. -overview.duplicated_lines_density.on_x_new_lines=On {link} lines. -overview.quality_gate.x_estimated_after_merge={value} Estimated after merge +overview.duplicated_lines_density.on_x_new_lines=On {link} lines. overview.quality_gate.require_fixing={count, plural, one {requires} other {require}} fixing overview.quality_gate.require_reviewing={count, plural, one {requires} other {require}} reviewing overview.quality_gate.required_x=Required {operator} {requirement} -- 2.39.5