Skip to content

Commit

Permalink
SONAR-20993 Add option to optimize quality gates CaYC compliant witho…
Browse files Browse the repository at this point in the history
…ut 0 issues conditions (#9929)
  • Loading branch information
Andrey Luiz authored and sonartech committed Nov 15, 2023
1 parent 85f3049 commit 917bbd0
Show file tree
Hide file tree
Showing 10 changed files with 385 additions and 199 deletions.
18 changes: 18 additions & 0 deletions server/sonar-web/src/main/js/api/mocks/QualityGatesServiceMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ export class QualityGatesServiceMock {
mockQualityGate({
name: 'SonarSource way - CFamily',
conditions: [
{
id: 'AXJMbIUHPAOIsUIE3eOi',
metric: 'new_security_hotspots_reviewed',
op: 'LT',
error: '85',
isCaycCondition: true,
},
{
id: 'AXJMbIUHPAOIsUIE3eOu',
metric: 'new_coverage',
Expand Down Expand Up @@ -187,6 +194,17 @@ export class QualityGatesServiceMock {
isBuiltIn: false,
caycStatus: CaycStatus.NonCompliant,
}),
mockQualityGate({
name: 'Non Cayc Compliant QG',
conditions: [
{ id: 'AXJMbIUHPAOIsUIE3eNs', metric: 'new_security_rating', op: 'GT', error: '1' },
{ id: 'AXJMbIUHPAOIsUIE3eOD', metric: 'new_reliability_rating', op: 'GT', error: '1' },
{ id: 'AXJMbIUHPAOIsUIE3eOF', metric: 'new_coverage', op: 'LT', error: '80' },
],
isDefault: false,
isBuiltIn: false,
caycStatus: CaycStatus.Compliant,
}),
mockQualityGate({
name: 'Over Compliant CAYC QG',
conditions: [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* SonarQube
* Copyright (C) 2009-2023 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 {
CardWithPrimaryBackground,
CheckIcon,
LightLabel,
SubHeadingHighlight,
} from 'design-system';
import React from 'react';
import { FormattedMessage } from 'react-intl';
import DocumentationLink from '../../../components/common/DocumentationLink';
import { translate } from '../../../helpers/l10n';
import { OPTIMIZED_CAYC_CONDITIONS } from '../utils';

export default function CaycCompliantBanner() {
return (
<CardWithPrimaryBackground className="sw-mb-9 sw-p-8">
<SubHeadingHighlight className="sw-mb-2">
{translate('quality_gates.cayc.banner.title')}
</SubHeadingHighlight>

<div>
<FormattedMessage
id="quality_gates.cayc.banner.description1"
values={{
cayc_link: (
<DocumentationLink to="/user-guide/clean-as-you-code/">
{translate('quality_gates.cayc')}
</DocumentationLink>
),
}}
/>
</div>
<div className="sw-my-2">{translate('quality_gates.cayc.banner.description2')}</div>
<ul className="sw-body-sm sw-flex sw-flex-col sw-gap-2">
{Object.values(OPTIMIZED_CAYC_CONDITIONS).map((condition) => (
<li key={condition.metric}>
<CheckIcon className="sw-mr-1 sw-pt-1/2" />
<LightLabel>{translate(`metric.${condition.metric}.description.positive`)}</LightLabel>
</li>
))}
</ul>
</CardWithPrimaryBackground>
);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* SonarQube
* Copyright (C) 2009-2023 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 { ButtonPrimary, CardWithPrimaryBackground, SubHeadingHighlight } from 'design-system';
import React from 'react';
import { FormattedMessage } from 'react-intl';
import DocumentationLink from '../../../components/common/DocumentationLink';
import ModalButton from '../../../components/controls/ModalButton';
import { translate } from '../../../helpers/l10n';

interface Props {
renderCaycModal: ({ onClose }: { onClose: () => void }) => React.ReactNode;
isOptimizing?: boolean;
}

export default function CaycNonCompliantBanner({ renderCaycModal, isOptimizing }: Readonly<Props>) {
return (
<CardWithPrimaryBackground className="sw-mb-9 sw-p-8">
<SubHeadingHighlight className="sw-mb-2">
{translate(
isOptimizing
? 'quality_gates.cayc_optimize.banner.title'
: 'quality_gates.cayc_missing.banner.title',
)}
</SubHeadingHighlight>
<div>
<FormattedMessage
id={
isOptimizing
? 'quality_gates.cayc_optimize.banner.description'
: 'quality_gates.cayc_missing.banner.description'
}
values={{
cayc_link: (
<DocumentationLink to="/user-guide/clean-as-you-code/">
{translate('quality_gates.cayc')}
</DocumentationLink>
),
}}
/>
</div>
<ModalButton modal={renderCaycModal}>
{({ onClick }) => (
<ButtonPrimary className="sw-mt-4" onClick={onClick}>
{translate(
isOptimizing
? 'quality_gates.cayc_condition.review_optimize'
: 'quality_gates.cayc_condition.review_update',
)}
</ButtonPrimary>
)}
</ModalButton>
</CardWithPrimaryBackground>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ interface Props {
onSaveCondition: (newCondition: Condition, oldCondition: Condition) => void;
lockEditing: () => void;
qualityGate: QualityGate;
isOptimizing?: boolean;
}

export default function CaycReviewUpdateConditionsModal(props: Readonly<Props>) {
Expand All @@ -51,6 +52,7 @@ export default function CaycReviewUpdateConditionsModal(props: Readonly<Props>)
onAddCondition,
lockEditing,
onClose,
isOptimizing,
} = props;

const { weakConditions, missingConditions } = getWeakMissingAndNonCaycConditions(conditions);
Expand Down Expand Up @@ -108,8 +110,11 @@ export default function CaycReviewUpdateConditionsModal(props: Readonly<Props>)
<div className="sw-mb-10">
<SubHeading as="p" className="sw-body-sm">
<FormattedMessage
id="quality_gates.cayc.review_update_modal.description1"
defaultMessage={translate('quality_gates.cayc.review_update_modal.description1')}
id={
isOptimizing
? 'quality_gates.cayc.review_optimize_modal.description1'
: 'quality_gates.cayc.review_update_modal.description1'
}
values={{
cayc_link: (
<Link to={getDocUrl('/user-guide/clean-as-you-code/')}>
Expand Down Expand Up @@ -164,7 +169,9 @@ export default function CaycReviewUpdateConditionsModal(props: Readonly<Props>)
<Modal
isLarge
headerTitle={translateWithParameters(
'quality_gates.cayc.review_update_modal.header',
isOptimizing
? 'quality_gates.cayc.review_optimize_modal.header'
: 'quality_gates.cayc.review_update_modal.header',
qualityGate.name,
)}
onClose={onClose}
Expand All @@ -176,7 +183,11 @@ export default function CaycReviewUpdateConditionsModal(props: Readonly<Props>)
type="submit"
onClick={updateCaycQualityGate}
>
{translate('quality_gates.cayc.review_update_modal.confirm_text')}
{translate(
isOptimizing
? 'quality_gates.cayc.review_optimize_modal.confirm_text'
: 'quality_gates.cayc.review_update_modal.confirm_text',
)}
</ButtonPrimary>
}
secondaryButtonLabel={translate('close')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,9 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
import withAppStateContext from '../../../app/components/app-state/withAppStateContext';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { translate } from '../../../helpers/l10n';
import { formatMeasure } from '../../../helpers/measures';
import {
GRID_INDEX_OFFSET,
PERCENT_MULTIPLIER,
getMaintainabilityGrid,
} from '../../../helpers/ratings';
import { AppState } from '../../../types/appstate';
import { MetricKey, MetricType } from '../../../types/metrics';
import { GlobalSettingKeys } from '../../../types/settings';
import { MetricKey } from '../../../types/metrics';
import { Condition, Metric } from '../../../types/types';
import { GreenColorText } from './ConditionValue';

Expand All @@ -37,50 +29,22 @@ const NO_DESCRIPTION_CONDITION = [
MetricKey.new_security_hotspots_reviewed,
MetricKey.new_coverage,
MetricKey.new_duplicated_lines_density,
MetricKey.new_reliability_rating,
MetricKey.new_security_rating,
MetricKey.new_maintainability_rating,
];

interface Props {
appState: AppState;
condition: Condition;
metric: Metric;
isToBeModified?: boolean;
}

function ConditionValueDescription({
export default function ConditionValueDescription({
condition,
appState: { settings },
metric,
isToBeModified = false,
}: Readonly<Props>) {
if (condition.metric === MetricKey.new_maintainability_rating) {
const maintainabilityGrid = getMaintainabilityGrid(
settings[GlobalSettingKeys.RatingGrid] ?? '',
);
const maintainabilityRatingThreshold =
maintainabilityGrid[Math.floor(Number(condition.error)) - GRID_INDEX_OFFSET];
const ratingLetter = formatMeasure(condition.error, MetricType.Rating);

return (
<GreenColorText isToBeModified={isToBeModified}>
(
{condition.error === '1'
? translateWithParameters(
'quality_gates.cayc.new_maintainability_rating.A',
formatMeasure(maintainabilityGrid[0] * PERCENT_MULTIPLIER, MetricType.Percent),
)
: translateWithParameters(
'quality_gates.cayc.new_maintainability_rating',
ratingLetter,
formatMeasure(
maintainabilityRatingThreshold * PERCENT_MULTIPLIER,
MetricType.Percent,
),
)}
)
</GreenColorText>
);
}

return (
<GreenColorText isToBeModified={isToBeModified}>
{condition.isCaycCondition &&
Expand All @@ -99,5 +63,3 @@ function ConditionValueDescription({
</GreenColorText>
);
}

export default withAppStateContext(ConditionValueDescription);
Loading

0 comments on commit 917bbd0

Please sign in to comment.