From: stanislavh Date: Fri, 17 Feb 2023 13:32:39 +0000 (+0100) Subject: SONAR-18217 Correct order of conditions in quality gate page X-Git-Tag: 10.0.0.68432~220 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=e16a504c67e6ee38757e8fc4899e336b4f3c0cda;p=sonarqube.git SONAR-18217 Correct order of conditions in quality gate page --- diff --git a/server/sonar-web/src/main/js/apps/quality-gates/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/quality-gates/__tests__/utils-test.ts index 3fd313aadcd..93c76b35343 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/__tests__/utils-test.ts +++ b/server/sonar-web/src/main/js/apps/quality-gates/__tests__/utils-test.ts @@ -17,14 +17,24 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { mockMetric } from '../../../helpers/testMocks'; -import { getLocalizedMetricNameNoDiffMetric } from '../utils'; +import { mockCondition, mockMetric } from '../../../helpers/testMocks'; +import { MetricKey } from '../../../types/metrics'; +import { Condition } from '../../../types/types'; +import { getLocalizedMetricNameNoDiffMetric, groupAndSortByPriorityConditions } from '../utils'; const METRICS = { - bugs: mockMetric({ key: 'bugs', name: 'Bugs' }), existing_metric: mockMetric(), - new_maintainability_rating: mockMetric(), - sqale_rating: mockMetric({ key: 'sqale_rating', name: 'Maintainability Rating' }), + [MetricKey.new_maintainability_rating]: mockMetric({ name: 'New Maintainability Rating' }), + [MetricKey.sqale_rating]: mockMetric({ + name: 'Maintainability Rating', + }), + [MetricKey.coverage]: mockMetric({ name: 'Coverage' }), + [MetricKey.bugs]: mockMetric({ name: 'Bugs' }), + [MetricKey.new_coverage]: mockMetric({ name: 'New Code Coverage' }), + [MetricKey.new_reliability_rating]: mockMetric({ name: 'New Reliability Rating' }), + [MetricKey.new_bugs]: mockMetric({ name: 'New Bugs' }), + [MetricKey.code_smells]: mockMetric({ name: 'Code Smells' }), + [MetricKey.duplicated_lines_density]: mockMetric({ name: 'Duplicated lines (%)' }), }; describe('getLocalizedMetricNameNoDiffMetric', () => { @@ -44,3 +54,36 @@ describe('getLocalizedMetricNameNoDiffMetric', () => { ).toBe('Maintainability Rating'); }); }); + +describe('groupAndSortByPriorityConditions', () => { + const conditions = [ + mockCondition(), + mockCondition({ metric: MetricKey.bugs }), + mockCondition({ metric: MetricKey.new_coverage }), + mockCondition({ metric: MetricKey.new_reliability_rating }), + mockCondition({ metric: MetricKey.code_smells }), + mockCondition({ metric: MetricKey.duplicated_lines_density }), + mockCondition({ metric: MetricKey.new_bugs }), + ]; + const expectedConditionsOrderNewCode = [ + MetricKey.new_reliability_rating, + MetricKey.new_coverage, + MetricKey.new_bugs, + ]; + const expectConditionsOrderOverallCode = [ + MetricKey.bugs, + MetricKey.code_smells, + MetricKey.coverage, + MetricKey.duplicated_lines_density, + ]; + + it('should return grouped conditions by overall/new code and sort them by CAYC order', () => { + const result = groupAndSortByPriorityConditions(conditions, METRICS); + const conditionsMap = ({ metric }: Condition) => metric; + + expect(result.newCodeConditions.map(conditionsMap)).toEqual(expectedConditionsOrderNewCode); + expect(result.overallCodeConditions.map(conditionsMap)).toEqual( + expectConditionsOrderOverallCode + ); + }); +}); 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 7da4afdb0fb..10885d4f923 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 @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { differenceWith, map, sortBy, uniqBy } from 'lodash'; +import { differenceWith, map, uniqBy } from 'lodash'; import * as React from 'react'; import { FormattedMessage } from 'react-intl'; import withAvailableFeatures, { @@ -30,7 +30,6 @@ import { Button } from '../../../components/controls/buttons'; import ModalButton, { ModalProps } from '../../../components/controls/ModalButton'; import { Alert } from '../../../components/ui/Alert'; import { getLocalizedMetricName, translate } from '../../../helpers/l10n'; -import { isDiffMetric } from '../../../helpers/measures'; import { Feature } from '../../../types/features'; import { MetricKey } from '../../../types/metrics'; import { @@ -40,6 +39,7 @@ import { Metric, QualityGate, } from '../../../types/types'; +import { groupAndSortByPriorityConditions } from '../utils'; import ConditionModal from './ConditionModal'; import CaycReviewUpdateConditionsModal from './ConditionReviewAndUpdateModal'; import ConditionsTable from './ConditionsTable'; @@ -140,16 +140,9 @@ export class Conditions extends React.PureComponent { const { unlockEditing } = this.state; const { conditions = [] } = qualityGate; const existingConditions = conditions.filter((condition) => metrics[condition.metric]); - const sortedConditions = sortBy( + const { overallCodeConditions, newCodeConditions } = groupAndSortByPriorityConditions( existingConditions, - (condition) => metrics[condition.metric] && metrics[condition.metric].name - ); - - const sortedConditionsOnOverallMetrics = sortedConditions.filter( - (condition) => !isDiffMetric(condition.metric) - ); - const sortedConditionsOnNewMetrics = sortedConditions.filter((condition) => - isDiffMetric(condition.metric) + metrics ); const duplicates: ConditionType[] = []; @@ -289,7 +282,7 @@ export class Conditions extends React.PureComponent { )} - {sortedConditionsOnNewMetrics.length > 0 && ( + {newCodeConditions.length > 0 && (

{translate('quality_gates.conditions.new_code', 'long')} @@ -306,14 +299,14 @@ export class Conditions extends React.PureComponent { onRemoveCondition={onRemoveCondition} onSaveCondition={onSaveCondition} updatedConditionId={updatedConditionId} - conditions={sortedConditionsOnNewMetrics} + conditions={newCodeConditions} showEdit={this.state.unlockEditing} scope="new" />

)} - {sortedConditionsOnOverallMetrics.length > 0 && ( + {overallCodeConditions.length > 0 && (

{translate('quality_gates.conditions.overall_code', 'long')} @@ -332,7 +325,7 @@ export class Conditions extends React.PureComponent { onRemoveCondition={onRemoveCondition} onSaveCondition={onSaveCondition} updatedConditionId={updatedConditionId} - conditions={sortedConditionsOnOverallMetrics} + conditions={overallCodeConditions} scope="overall" />

diff --git a/server/sonar-web/src/main/js/apps/quality-gates/utils.ts b/server/sonar-web/src/main/js/apps/quality-gates/utils.ts index 80b99e87220..502f32cb511 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/utils.ts +++ b/server/sonar-web/src/main/js/apps/quality-gates/utils.ts @@ -19,8 +19,14 @@ */ import { getLocalizedMetricName } from '../../helpers/l10n'; import { isDiffMetric } from '../../helpers/measures'; +import { MetricKey } from '../../types/metrics'; import { CaycStatus, Condition, Dict, Metric, QualityGate } from '../../types/types'; +interface GroupedByMetricConditions { + overallCodeConditions: Condition[]; + newCodeConditions: Condition[]; +} + const CAYC_CONDITIONS: { [key: string]: Condition } = { new_reliability_rating: { error: '1', @@ -60,6 +66,17 @@ const CAYC_CONDITIONS: { [key: string]: Condition } = { }, }; +const CAYC_CONDITION_ORDER_PRIORITIES: Dict = [ + MetricKey.new_reliability_rating, + MetricKey.new_security_rating, + MetricKey.new_security_hotspots_reviewed, + MetricKey.new_maintainability_rating, + MetricKey.new_coverage, + MetricKey.new_duplicated_lines_density, +] + .reverse() + .reduce((acc, key, i) => ({ ...acc, [key.toString()]: i + 1 }), {} as Dict); + export const CAYC_CONDITIONS_WITHOUT_FIXED_VALUE = ['new_duplicated_lines_density', 'new_coverage']; export const CAYC_CONDITIONS_WITH_FIXED_VALUE = [ 'new_security_hotspots_reviewed', @@ -104,6 +121,45 @@ export function getCaycConditionsWithCorrectValue(conditions: Condition[]) { }); } +export function groupConditionsByMetric(conditions: Condition[]): GroupedByMetricConditions { + return conditions.reduce( + (result, condition) => { + const isNewCode = isDiffMetric(condition.metric); + result[isNewCode ? 'newCodeConditions' : 'overallCodeConditions'].push(condition); + + return result; + }, + { + overallCodeConditions: [] as Condition[], + newCodeConditions: [] as Condition[], + } + ); +} + +export function groupAndSortByPriorityConditions( + conditions: Condition[], + metrics: Dict +): GroupedByMetricConditions { + const groupedConditions = groupConditionsByMetric(conditions); + + function sortFn(a: Condition, b: Condition) { + const priorityA = CAYC_CONDITION_ORDER_PRIORITIES[a.metric] ?? 0; + const priorityB = CAYC_CONDITION_ORDER_PRIORITIES[b.metric] ?? 0; + const diff = priorityB - priorityA; + if (diff !== 0) { + return diff; + } + return metrics[a.metric].name.localeCompare(metrics[b.metric].name, undefined, { + sensitivity: 'base', + }); + } + + groupedConditions.newCodeConditions.sort(sortFn); + groupedConditions.overallCodeConditions.sort(sortFn); + + return groupedConditions; +} + export function getCorrectCaycCondition(condition: Condition) { if (CAYC_CONDITIONS_WITHOUT_FIXED_VALUE.includes(condition.metric)) { return condition;