* 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', () => {
).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
+ );
+ });
+});
* 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, {
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 {
Metric,
QualityGate,
} from '../../../types/types';
+import { groupAndSortByPriorityConditions } from '../utils';
import ConditionModal from './ConditionModal';
import CaycReviewUpdateConditionsModal from './ConditionReviewAndUpdateModal';
import ConditionsTable from './ConditionsTable';
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[] = [];
</Alert>
)}
- {sortedConditionsOnNewMetrics.length > 0 && (
+ {newCodeConditions.length > 0 && (
<div className="big-spacer-top">
<h3 className="medium text-normal">
{translate('quality_gates.conditions.new_code', 'long')}
onRemoveCondition={onRemoveCondition}
onSaveCondition={onSaveCondition}
updatedConditionId={updatedConditionId}
- conditions={sortedConditionsOnNewMetrics}
+ conditions={newCodeConditions}
showEdit={this.state.unlockEditing}
scope="new"
/>
</div>
)}
- {sortedConditionsOnOverallMetrics.length > 0 && (
+ {overallCodeConditions.length > 0 && (
<div className="big-spacer-top">
<h3 className="medium text-normal">
{translate('quality_gates.conditions.overall_code', 'long')}
onRemoveCondition={onRemoveCondition}
onSaveCondition={onSaveCondition}
updatedConditionId={updatedConditionId}
- conditions={sortedConditionsOnOverallMetrics}
+ conditions={overallCodeConditions}
scope="overall"
/>
</div>
*/
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',
},
};
+const CAYC_CONDITION_ORDER_PRIORITIES: Dict<number> = [
+ 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<number>);
+
export const CAYC_CONDITIONS_WITHOUT_FIXED_VALUE = ['new_duplicated_lines_density', 'new_coverage'];
export const CAYC_CONDITIONS_WITH_FIXED_VALUE = [
'new_security_hotspots_reviewed',
});
}
+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<Metric>
+): 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;