diff options
Diffstat (limited to 'server/sonar-web')
5 files changed, 438 insertions, 13 deletions
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 c815e3a8daa..be3d0fb8f82 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 @@ -18,6 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { Button, Spinner } from '@sonarsource/echoes-react'; import { uniqBy } from 'lodash'; import * as React from 'react'; import { FormattedMessage } from 'react-intl'; @@ -31,7 +32,6 @@ import { LightPrimary, Link, Note, - Spinner, SubHeading, } from '~design-system'; import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip'; @@ -42,9 +42,16 @@ import { ModalProps } from '../../../components/controls/ModalButton'; import { DocLink } from '../../../helpers/doc-links'; import { useDocUrl } from '../../../helpers/docs'; import { getLocalizedMetricName, translate } from '../../../helpers/l10n'; +import { useStandardExperienceMode } from '../../../queries/settings'; +import { MetricKey } from '../../../sonar-aligned/types/metrics'; import { Feature } from '../../../types/features'; import { CaycStatus, Condition as ConditionType, QualityGate } from '../../../types/types'; -import { groupAndSortByPriorityConditions, isQualityGateOptimized } from '../utils'; +import { + groupAndSortByPriorityConditions, + isQualityGateOptimized, + MQR_CONDITIONS_MAP, + STANDARD_CONDITIONS_MAP, +} from '../utils'; import AddConditionModal from './AddConditionModal'; import AIGeneratedIcon from './AIGeneratedIcon'; import CaycCompliantBanner from './CaycCompliantBanner'; @@ -54,6 +61,7 @@ import CaycFixOptimizeBanner from './CaycFixOptimizeBanner'; import CaycReviewUpdateConditionsModal from './ConditionReviewAndUpdateModal'; import ConditionsTable from './ConditionsTable'; import QGRecommendedIcon from './QGRecommendedIcon'; +import UpdateConditionsFromOtherModeModal from './UpdateConditionsFromOtherModeModal'; interface Props { isFetching?: boolean; @@ -66,6 +74,7 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>) const [editing, setEditing] = React.useState<boolean>(caycStatus === CaycStatus.NonCompliant); const metrics = useMetrics(); const { hasFeature } = useAvailableFeatures(); + const { data: isStandardMode, isLoading } = useStandardExperienceMode(); const canEdit = Boolean(actions?.manageConditions); const existingConditions = conditions.filter((condition) => metrics[condition.metric]); @@ -116,10 +125,11 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>) [qualityGate, conditions, metrics, isOptimizing, canEdit], ); + const conditionsToOtherModeMap = isStandardMode ? MQR_CONDITIONS_MAP : STANDARD_CONDITIONS_MAP; + return ( - <div> + <Spinner isLoading={isLoading}> <CaYCConditionsSimplificationGuide qualityGate={qualityGate} /> - {isBuiltIn && ( <div className="sw-flex sw-items-center"> <QGRecommendedIcon className="sw-mr-1" /> @@ -138,7 +148,6 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>) </LightLabel> </div> )} - {isAICodeAssuranceQualityGate && ( <div className="sw-flex sw-items-center sw-mt-2"> <AIGeneratedIcon className="sw-mr-1" /> @@ -157,7 +166,6 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>) </LightLabel> </div> )} - {isCompliantCustomQualityGate && !isOptimizing && <CaycCompliantBanner />} {isCompliantCustomQualityGate && isOptimizing && canEdit && ( <CaycFixOptimizeBanner renderCaycModal={renderCaycModal} isOptimizing /> @@ -165,7 +173,26 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>) {caycStatus === CaycStatus.NonCompliant && canEdit && ( <CaycFixOptimizeBanner renderCaycModal={renderCaycModal} /> )} - + <UpdateConditionsFromOtherModeModal + qualityGateName={qualityGate.name} + newCodeConditions={newCodeConditions.filter( + (c) => conditionsToOtherModeMap[c.metric as MetricKey] !== undefined, + )} + overallCodeConditions={overallCodeConditions.filter( + (c) => conditionsToOtherModeMap[c.metric as MetricKey] !== undefined, + )} + > + {/* TODO test example */} + <Button>Review and update metrics</Button> + </UpdateConditionsFromOtherModeModal> + <UpdateConditionsFromOtherModeModal + qualityGateName={qualityGate.name} + isSingleMetric + condition={newCodeConditions.find((c) => c.metric.includes('rating'))!} + > + {/* TODO test example */} + <Button>Test single</Button> + </UpdateConditionsFromOtherModeModal> <header className="sw-flex sw-items-center sw-mt-9 sw-mb-4 sw-justify-between"> <div className="sw-flex"> <HeadingDark className="sw-typo-lg-semibold sw-m-0"> @@ -185,7 +212,7 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>) <HelperHintIcon /> </DocHelpTooltip> )} - <Spinner loading={isFetching} className="sw-ml-4 sw-mt-1" /> + <Spinner isLoading={isFetching} className="sw-ml-4 sw-mt-1" /> </div> <div> {(caycStatus === CaycStatus.NonCompliant || editing) && canEdit && ( @@ -193,7 +220,6 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>) )} </div> </header> - {uniqDuplicates.length > 0 && ( <FlagMessage variant="warning" className="sw-flex sw-mb-4"> <div> @@ -206,7 +232,6 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>) </div> </FlagMessage> )} - <div className="sw-flex sw-flex-col sw-gap-8"> {caycConditions.length > 0 && ( <div> @@ -288,7 +313,6 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>) </div> )} </div> - {caycStatus !== CaycStatus.NonCompliant && !editing && canEdit && ( <div className="sw-mt-4 it__qg-unfollow-cayc"> <SubHeading as="p" className="sw-mb-2 sw-typo-default"> @@ -305,12 +329,11 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>) </ButtonSecondary> </div> )} - {existingConditions.length === 0 && ( <div className="sw-mt-4 sw-typo-default"> <LightPrimary as="p">{translate('quality_gates.no_conditions')}</LightPrimary> </div> )} - </div> + </Spinner> ); } diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/UpdateConditionsFromOtherModeModal.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/UpdateConditionsFromOtherModeModal.tsx new file mode 100644 index 00000000000..50775c76dda --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/UpdateConditionsFromOtherModeModal.tsx @@ -0,0 +1,321 @@ +/* + * 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 { + Button, + ButtonVariety, + Heading, + IconArrowRight, + Modal, + ModalSize, + Text, + TextSize, +} from '@sonarsource/echoes-react'; +import * as React from 'react'; +import { FormattedMessage, useIntl } from 'react-intl'; +import { useMetrics } from '../../../app/components/metrics/withMetricsContext'; +import DocumentationLink from '../../../components/common/DocumentationLink'; +import { ContentCell, FlagMessageV2, Table, TableRow } from '../../../design-system'; +import { DocLink } from '../../../helpers/doc-links'; +import { translate } from '../../../helpers/l10n'; +import { getOperatorLabel } from '../../../helpers/qualityGates'; +import { useUpdateOrDeleteConditionsMutation } from '../../../queries/quality-gates'; +import { useStandardExperienceMode } from '../../../queries/settings'; +import { MetricKey } from '../../../sonar-aligned/types/metrics'; +import { Condition } from '../../../types/types'; +import { + getLocalizedMetricNameNoDiffMetric, + MQR_CONDITIONS_MAP, + STANDARD_CONDITIONS_MAP, +} from '../utils'; +import ConditionValue from './ConditionValue'; + +type Props = React.PropsWithChildren & { qualityGateName: string } & ( + | { + condition?: never; + isSingleMetric?: false; + newCodeConditions: Condition[]; + overallCodeConditions: Condition[]; + } + | { + condition: Condition; + isSingleMetric: true; + newCodeConditions?: never; + overallCodeConditions?: never; + } + ); + +export default function UpdateConditionsFromOtherModeModal({ + newCodeConditions, + overallCodeConditions, + qualityGateName, + isSingleMetric, + condition, + children, +}: Readonly<Props>) { + const { data: isStandard } = useStandardExperienceMode(); + const [isOpen, setOpen] = React.useState(false); + const [error, setError] = React.useState(false); + const intl = useIntl(); + const mapper = isStandard ? MQR_CONDITIONS_MAP : STANDARD_CONDITIONS_MAP; + const { mutate: updateConditions, isPending } = useUpdateOrDeleteConditionsMutation( + qualityGateName, + isSingleMetric, + ); + + const onSubmit = () => { + const conditions = isSingleMetric + ? [condition] + : [...newCodeConditions, ...overallCodeConditions]; + + updateConditions( + conditions.map((c) => ({ ...c, metric: mapper[c.metric as MetricKey] })), + { + onSuccess: () => setOpen(false), + onError: () => setError(true), + }, + ); + }; + + return ( + <Modal + isOpen={isOpen} + onOpenChange={setOpen} + title={intl.formatMessage( + { + id: `quality_gates.update_conditions.header${isSingleMetric ? '.single_metric' : ''}`, + }, + { qualityGate: qualityGateName }, + )} + size={isSingleMetric ? ModalSize.Default : ModalSize.Wide} + primaryButton={ + <Button + isDisabled={isPending} + isLoading={isPending} + onClick={onSubmit} + id="update-metrics-button" + variety={ButtonVariety.Primary} + > + {intl.formatMessage({ + id: isSingleMetric ? 'update_verb' : 'quality_gates.update_conditions.update_metrics', + })} + </Button> + } + secondaryButton={<Button onClick={() => setOpen(false)}>{translate('cancel')}</Button>} + content={ + <> + {error && ( + <div> + <FlagMessageV2 variant="error"> + {intl.formatMessage({ id: 'quality_gates.update_conditions.error' })} + </FlagMessageV2> + </div> + )} + <Text> + <FormattedMessage + id="quality_gates.update_conditions.description.line1" + values={{ + b: (chunks) => <Text isHighlighted>{chunks}</Text>, + mode: intl.formatMessage({ + id: `settings.mode.${isStandard ? 'standard' : 'mqr'}.name`, + }), + }} + /> + </Text> + + {isSingleMetric && <SingleMetric condition={condition} />} + <Text> + <FormattedMessage + id="quality_gates.update_conditions.description.line2" + values={{ + b: (chunks) => <Text isHighlighted>{chunks}</Text>, + }} + /> + <br /> + <br /> + <FormattedMessage + id="quality_gates.update_conditions.description.line3" + values={{ + mode: intl.formatMessage({ + id: `settings.mode.${isStandard ? 'standard' : 'mqr'}.name`, + }), + link: ( + <DocumentationLink to={isStandard ? DocLink.ModeStandard : DocLink.ModeMQR}> + {intl.formatMessage({ + id: 'quality_gates.update_conditions.description.link', + })} + </DocumentationLink> + ), + }} + /> + </Text> + {!isSingleMetric && ( + <> + {newCodeConditions.length > 0 && ( + <> + <Heading as="h3" className="sw-mt-8"> + {intl.formatMessage({ id: 'overview.new_code' })} + </Heading> + <Table + columnCount={3} + columnWidths={['35%', '35%', 'auto']} + className="sw-my-2" + header={<Header />} + > + {newCodeConditions.map((condition) => ( + <ConditionRow condition={condition} key={condition.id} /> + ))} + </Table> + </> + )} + {overallCodeConditions.length > 0 && ( + <> + <Heading as="h3" className="sw-mt-8"> + {intl.formatMessage({ id: 'overview.overall_code' })} + </Heading> + <Table + columnCount={3} + columnWidths={['35%', '35%', 'auto']} + className="sw-my-2" + header={<Header />} + > + {overallCodeConditions.map((condition) => ( + <ConditionRow condition={condition} key={condition.id} /> + ))} + </Table> + </> + )} + </> + )} + </> + } + > + {React.cloneElement(children as React.ReactElement, { onClick: () => setOpen(true) })} + </Modal> + ); +} + +function SingleMetric({ condition }: Readonly<{ condition: Condition }>) { + const { data: isStandard } = useStandardExperienceMode(); + const intl = useIntl(); + const metrics = useMetrics(); + const metric = metrics[condition.metric]; + const mapper = isStandard ? MQR_CONDITIONS_MAP : STANDARD_CONDITIONS_MAP; + const metricFromOtherMode = mapper[metric.key as MetricKey]; + + return ( + <div className="sw-flex sw-justify-between sw-my-8 sw-items-center sw-w-[80%]"> + <div> + <Text as="div" size={TextSize.Small}> + {intl.formatMessage({ + id: `quality_gates.update_conditions.${isStandard ? 'mqr' : 'standard'}_mode_header`, + })} + </Text> + <Text as="div" size={TextSize.Small} isHighlighted> + {getLocalizedMetricNameNoDiffMetric(metrics[condition.metric], metrics)} + </Text> + </div> + <IconArrowRight /> + <div> + {metricFromOtherMode ? ( + <> + <Text as="div" size={TextSize.Small}> + {intl.formatMessage({ + id: `quality_gates.update_conditions.${isStandard ? 'standard' : 'mqr'}_mode_header`, + })} + </Text> + <Text as="div" size={TextSize.Small} isHighlighted> + {getLocalizedMetricNameNoDiffMetric(metrics[metricFromOtherMode], metrics)} + </Text> + </> + ) : ( + <Text size={TextSize.Small}> + {intl.formatMessage({ id: 'quality_gates.update_conditions.removed' })} + </Text> + )} + </div> + </div> + ); +} + +function Header() { + const intl = useIntl(); + const { data: isStandard } = useStandardExperienceMode(); + + return ( + <TableRow> + <ContentCell className="sw-justify-between sw-pr-4"> + <Heading as="h4" className="sw-typo-semibold sw-m-0 sw-whitespace-nowrap"> + {intl.formatMessage({ + id: `quality_gates.update_conditions.${isStandard ? 'mqr' : 'standard'}_mode_header`, + })} + </Heading> + <IconArrowRight /> + </ContentCell> + <ContentCell> + <Heading as="h4" className="sw-typo-semibold sw-m-0 sw-whitespace-nowrap"> + {intl.formatMessage({ + id: `quality_gates.update_conditions.${isStandard ? 'standard' : 'mqr'}_mode_header`, + })} + </Heading> + </ContentCell> + <ContentCell> + <Heading as="h4" className="sw-typo-semibold sw-m-0 sw-whitespace-nowrap"> + {intl.formatMessage({ id: 'quality_gates.update_conditions.operator_and_value_header' })} + </Heading> + </ContentCell> + <ContentCell /> + </TableRow> + ); +} + +function ConditionRow({ condition }: Readonly<{ condition: Condition }>) { + const { data: isStandard } = useStandardExperienceMode(); + const intl = useIntl(); + const metrics = useMetrics(); + const { op = 'GT' } = condition; + const metric = metrics[condition.metric]; + const mapper = isStandard ? MQR_CONDITIONS_MAP : STANDARD_CONDITIONS_MAP; + const metricFromOtherMode = mapper[metric?.key as MetricKey]; + + return ( + <TableRow> + <ContentCell>{getLocalizedMetricNameNoDiffMetric(metric, metrics)}</ContentCell> + <ContentCell> + {metricFromOtherMode ? ( + getLocalizedMetricNameNoDiffMetric(metrics[metricFromOtherMode], metrics) + ) : ( + <Text colorOverride="echoes-color-text-danger"> + {intl.formatMessage({ id: 'quality_gates.update_conditions.removed' })} + </Text> + )} + </ContentCell> + + <ContentCell className="sw-whitespace-nowrap"> + {metricFromOtherMode && ( + <Text isSubdued> + {getOperatorLabel(op, metric)} + <ConditionValue condition={condition} metric={metric} /> + </Text> + )} + </ContentCell> + </TableRow> + ); +} 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 8cfc4f50e87..99e3aad55b3 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 @@ -20,6 +20,7 @@ import { sortBy } from 'lodash'; import { MetricKey } from '~sonar-aligned/types/metrics'; +import { SOFTWARE_QUALITY_RATING_METRICS_MAP } from '../../helpers/constants'; import { getLocalizedMetricName } from '../../helpers/l10n'; import { isDiffMetric } from '../../helpers/measures'; import { CaycStatus, Condition, Dict, Group, Metric, QualityGate } from '../../types/types'; @@ -148,6 +149,33 @@ const CAYC_CONDITIONS_WITH_FIXED_VALUE: AllCaycMetricKeys[] = [ ]; const NON_EDITABLE_CONDITIONS: MetricKey[] = [MetricKey.prioritized_rule_issues]; +export const STANDARD_CONDITIONS_MAP: Partial<Record<MetricKey, MetricKey>> = { + [MetricKey.new_blocker_violations]: MetricKey.new_software_quality_blocker_issues, + [MetricKey.new_critical_violations]: MetricKey.new_software_quality_high_issues, + [MetricKey.new_major_violations]: MetricKey.new_software_quality_medium_issues, + [MetricKey.new_minor_violations]: MetricKey.new_software_quality_low_issues, + [MetricKey.new_info_violations]: MetricKey.new_software_quality_info_issues, + [MetricKey.blocker_violations]: MetricKey.software_quality_blocker_issues, + [MetricKey.critical_violations]: MetricKey.software_quality_high_issues, + [MetricKey.major_violations]: MetricKey.software_quality_medium_issues, + [MetricKey.minor_violations]: MetricKey.software_quality_low_issues, + [MetricKey.info_violations]: MetricKey.software_quality_info_issues, + [MetricKey.new_vulnerabilities]: MetricKey.new_software_quality_security_issues, + [MetricKey.new_bugs]: MetricKey.new_software_quality_reliability_issues, + [MetricKey.new_code_smells]: MetricKey.new_software_quality_maintainability_issues, + [MetricKey.vulnerabilities]: MetricKey.software_quality_security_issues, + [MetricKey.bugs]: MetricKey.software_quality_reliability_issues, + [MetricKey.code_smells]: MetricKey.software_quality_maintainability_issues, + ...SOFTWARE_QUALITY_RATING_METRICS_MAP, +}; + +export const MQR_CONDITIONS_MAP: Partial<Record<MetricKey, MetricKey | null>> = { + ...Object.fromEntries( + Object.entries(STANDARD_CONDITIONS_MAP).map(([key, value]) => [value, key]), + ), + [MetricKey.high_impact_accepted_issues]: null, +}; + export function isConditionWithFixedValue(condition: Condition) { return CAYC_CONDITIONS_WITH_FIXED_VALUE.includes(condition.metric as OptimizedCaycMetricKeys); } diff --git a/server/sonar-web/src/main/js/queries/quality-gates.ts b/server/sonar-web/src/main/js/queries/quality-gates.ts index 5b2524e4be2..acc880b1e73 100644 --- a/server/sonar-web/src/main/js/queries/quality-gates.ts +++ b/server/sonar-web/src/main/js/queries/quality-gates.ts @@ -19,6 +19,7 @@ */ import { queryOptions, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { useIntl } from 'react-intl'; import { addGlobalSuccessMessage } from '~design-system'; import { BranchParameters } from '~sonar-aligned/types/branch-like'; import { @@ -238,6 +239,42 @@ export function useUpdateConditionMutation(gateName: string) { }); } +export function useUpdateOrDeleteConditionsMutation(gateName: string, isSingleMetric?: boolean) { + const queryClient = useQueryClient(); + const intl = useIntl(); + + return useMutation({ + mutationFn: ( + conditions: (Omit<Condition, 'metric'> & { metric: string | null | undefined })[], + ) => { + const promiseArr = conditions.map((condition) => + condition.metric + ? updateCondition(condition as Condition) + : deleteCondition({ id: condition.id }), + ); + + return Promise.all(promiseArr); + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: qualityQuery.list() }); + queryClient.invalidateQueries({ queryKey: qualityQuery.detail(gateName) }); + addGlobalSuccessMessage( + intl.formatMessage( + { + id: isSingleMetric + ? 'quality_gates.condition_updated' + : 'quality_gates.conditions_updated_to_the_mode', + }, + { qualityGateName: gateName }, + ), + ); + }, + onError: () => { + queryClient.invalidateQueries({ queryKey: qualityQuery.detail(gateName) }); + }, + }); +} + export function useDeleteConditionMutation(gateName: string) { const queryClient = useQueryClient(); diff --git a/server/sonar-web/src/main/js/sonar-aligned/types/metrics.ts b/server/sonar-web/src/main/js/sonar-aligned/types/metrics.ts index d711330cfa7..db99c08030b 100644 --- a/server/sonar-web/src/main/js/sonar-aligned/types/metrics.ts +++ b/server/sonar-web/src/main/js/sonar-aligned/types/metrics.ts @@ -22,13 +22,16 @@ export enum MetricKey { accepted_issues = 'accepted_issues', alert_status = 'alert_status', blocker_violations = 'blocker_violations', + software_quality_blocker_issues = 'software_quality_blocker_issues', branch_coverage = 'branch_coverage', bugs = 'bugs', + software_quality_reliability_issues = 'software_quality_reliability_issues', burned_budget = 'burned_budget', business_value = 'business_value', class_complexity = 'class_complexity', classes = 'classes', code_smells = 'code_smells', + software_quality_maintainability_issues = 'software_quality_maintainability_issues', cognitive_complexity = 'cognitive_complexity', comment_lines = 'comment_lines', comment_lines_data = 'comment_lines_data', @@ -40,6 +43,7 @@ export enum MetricKey { confirmed_issues = 'confirmed_issues', coverage = 'coverage', critical_violations = 'critical_violations', + software_quality_high_issues = 'software_quality_high_issues', development_cost = 'development_cost', directories = 'directories', duplicated_blocks = 'duplicated_blocks', @@ -63,6 +67,7 @@ export enum MetricKey { generated_ncloc = 'generated_ncloc', high_impact_accepted_issues = 'high_impact_accepted_issues', info_violations = 'info_violations', + software_quality_info_issues = 'software_quality_info_issues', issues = 'issues', last_change_on_maintainability_rating = 'last_change_on_maintainability_rating', last_change_on_releasability_rating = 'last_change_on_releasability_rating', @@ -83,23 +88,30 @@ export enum MetricKey { maintainability_rating_effort = 'maintainability_rating_effort', software_quality_maintainability_rating_effort = 'software_quality_maintainability_rating_effort', major_violations = 'major_violations', + software_quality_medium_issues = 'software_quality_medium_issues', minor_violations = 'minor_violations', + software_quality_low_issues = 'software_quality_low_issues', ncloc = 'ncloc', ncloc_data = 'ncloc_data', ncloc_language_distribution = 'ncloc_language_distribution', new_accepted_issues = 'new_accepted_issues', new_blocker_violations = 'new_blocker_violations', + new_software_quality_blocker_issues = 'new_software_quality_blocker_issues', new_branch_coverage = 'new_branch_coverage', new_bugs = 'new_bugs', + new_software_quality_reliability_issues = 'new_software_quality_reliability_issues', new_code_smells = 'new_code_smells', + new_software_quality_maintainability_issues = 'new_software_quality_maintainability_issues', new_conditions_to_cover = 'new_conditions_to_cover', new_coverage = 'new_coverage', new_critical_violations = 'new_critical_violations', + new_software_quality_high_issues = 'new_software_quality_high_issues', new_development_cost = 'new_development_cost', new_duplicated_blocks = 'new_duplicated_blocks', new_duplicated_lines = 'new_duplicated_lines', new_duplicated_lines_density = 'new_duplicated_lines_density', new_info_violations = 'new_info_violations', + new_software_quality_info_issues = 'new_software_quality_info_issues', new_issues = 'new_issues', new_line_coverage = 'new_line_coverage', new_lines = 'new_lines', @@ -110,7 +122,9 @@ export enum MetricKey { new_maintainability_rating_distribution = 'new_maintainability_rating_distribution', new_software_quality_maintainability_rating_distribution = 'new_software_quality_maintainability_rating_distribution', new_major_violations = 'new_major_violations', + new_software_quality_medium_issues = 'new_software_quality_medium_issues', new_minor_violations = 'new_minor_violations', + new_software_quality_low_issues = 'new_software_quality_low_issues', new_reliability_issues = 'new_reliability_issues', new_reliability_rating = 'new_reliability_rating', new_software_quality_reliability_rating = 'new_software_quality_reliability_rating', @@ -138,6 +152,7 @@ export enum MetricKey { new_violations = 'new_violations', new_violations_rating = 'new_violations_rating', new_vulnerabilities = 'new_vulnerabilities', + new_software_quality_security_issues = 'new_software_quality_security_issues', open_issues = 'open_issues', prioritized_rule_issues = 'prioritized_rule_issues', projects = 'projects', @@ -195,6 +210,7 @@ export enum MetricKey { violations = 'violations', violations_rating = 'violations_rating', vulnerabilities = 'vulnerabilities', + software_quality_security_issues = 'software_quality_security_issues', wont_fix_issues = 'wont_fix_issues', } |