aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js
diff options
context:
space:
mode:
authorJeremy Davis <jeremy.davis@sonarsource.com>2023-01-10 14:35:17 +0100
committersonartech <sonartech@sonarsource.com>2023-01-12 20:02:51 +0000
commit10e6b8ee65ecc77738bfab13fd3be135e8e4ab85 (patch)
tree1fddd0a11d4a19010296a1562f9de6c0b88156d5 /server/sonar-web/src/main/js
parent118a3ed166799831e097748f2ce8e113298ad14e (diff)
downloadsonarqube-10e6b8ee65ecc77738bfab13fd3be135e8e4ab85.tar.gz
sonarqube-10e6b8ee65ecc77738bfab13fd3be135e8e4ab85.zip
SONAR-17816 Warn user about non-cayc-compliant QG on the project overview
Diffstat (limited to 'server/sonar-web/src/main/js')
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx122
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-test.tsx27
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanelSection-test.tsx1
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanelSection-test.tsx.snap100
-rw-r--r--server/sonar-web/src/main/js/apps/overview/styles.css7
-rw-r--r--server/sonar-web/src/main/js/apps/overview/utils.ts10
6 files changed, 66 insertions, 201 deletions
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx
index d67432add26..ac9bc243030 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx
@@ -21,18 +21,16 @@ import * as React from 'react';
import { ButtonPlain } from '../../../components/controls/buttons';
import ChevronDownIcon from '../../../components/icons/ChevronDownIcon';
import ChevronRightIcon from '../../../components/icons/ChevronRightIcon';
-import { Alert } from '../../../components/ui/Alert';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { isDiffMetric } from '../../../helpers/measures';
import { BranchLike } from '../../../types/branch-like';
-import { ComponentQualifier } from '../../../types/component';
+import { isApplication } from '../../../types/component';
import {
QualityGateStatus,
QualityGateStatusConditionEnhanced,
} from '../../../types/quality-gates';
import { Component } from '../../../types/types';
import QualityGateConditions from '../components/QualityGateConditions';
-import { CAYC_METRICS } from '../utils';
import CleanAsYouCodeWarning from './CleanAsYouCodeWarning';
export interface QualityGatePanelSectionProps {
@@ -41,22 +39,21 @@ export interface QualityGatePanelSectionProps {
qgStatus: QualityGateStatus;
}
-function splitConditions(conditions: QualityGateStatusConditionEnhanced[]) {
- const caycConditions = [];
+function splitConditions(
+ conditions: QualityGateStatusConditionEnhanced[]
+): [QualityGateStatusConditionEnhanced[], QualityGateStatusConditionEnhanced[]] {
const newCodeFailedConditions = [];
const overallFailedConditions = [];
for (const condition of conditions) {
- if (CAYC_METRICS.includes(condition.metric)) {
- caycConditions.push(condition);
- } else if (isDiffMetric(condition.metric)) {
+ if (isDiffMetric(condition.metric)) {
newCodeFailedConditions.push(condition);
} else {
overallFailedConditions.push(condition);
}
}
- return [caycConditions, newCodeFailedConditions, overallFailedConditions];
+ return [newCodeFailedConditions, overallFailedConditions];
}
function displayConditions(conditions: number) {
@@ -84,24 +81,15 @@ export function QualityGatePanelSection(props: QualityGatePanelSectionProps) {
return null;
}
- const [caycConditions, newCodeFailedConditions, overallFailedConditions] = splitConditions(
+ const [newCodeFailedConditions, overallFailedConditions] = splitConditions(
qgStatus.failedConditions
);
- /*
- * Show Clean as You Code if:
- * - The QG is not CAYC-compliant
- * - There are *any* failing conditions, we either show:
- * - the cayc-specific failures
- * - that cayc is passing and only other conditions are failing
- */
- const showCayc = !qgStatus.isCaycCompliant || qgStatus.failedConditions.length > 0;
+ const showName = isApplication(component.qualifier);
- const showSuccessfulCayc = caycConditions.length === 0 && qgStatus.isCaycCompliant;
-
- const hasOtherConditions = newCodeFailedConditions.length + overallFailedConditions.length > 0;
-
- const showName = component.qualifier === ComponentQualifier.Application;
+ const showSectionTitles =
+ !qgStatus.isCaycCompliant ||
+ (overallFailedConditions.length > 0 && newCodeFailedConditions.length > 0);
const toggleLabel = collapsed
? translateWithParameters('overview.quality_gate.show_project_conditions_x', qgStatus.name)
@@ -131,69 +119,45 @@ export function QualityGatePanelSection(props: QualityGatePanelSectionProps) {
{!collapsed && (
<>
- {showCayc && (
- <>
- <div className="display-flex-center overview-quality-gate-conditions-section-title">
- <h4 className="padded">{translate('quality_gates.conditions.cayc')}</h4>
- {displayConditions(caycConditions.length)}
- </div>
-
- {!qgStatus.isCaycCompliant && (
- <div className="big-padded bordered-bottom overview-quality-gate-conditions-list">
- <CleanAsYouCodeWarning />
- </div>
- )}
-
- {showSuccessfulCayc && (
- <div className="big-padded bordered-bottom overview-quality-gate-conditions-list">
- <Alert variant="success" className="no-margin-bottom">
- {translate('overview.quality_gate.conditions.cayc.passed')}
- </Alert>
- </div>
- )}
+ {!qgStatus.isCaycCompliant && (
+ <div className="big-padded bordered-bottom overview-quality-gate-conditions-list">
+ <CleanAsYouCodeWarning />
+ </div>
+ )}
- {caycConditions.length > 0 && (
- <QualityGateConditions
- component={qgStatus}
- branchLike={qgStatus.branchLike}
- failedConditions={caycConditions}
- />
+ {newCodeFailedConditions.length > 0 && (
+ <>
+ {showSectionTitles && (
+ <h4 className="big-padded overview-quality-gate-conditions-section-title">
+ {translateWithParameters(
+ 'quality_gates.conditions.new_code_x',
+ newCodeFailedConditions.length.toString()
+ )}
+ </h4>
)}
+ <QualityGateConditions
+ component={qgStatus}
+ branchLike={qgStatus.branchLike}
+ failedConditions={newCodeFailedConditions}
+ />
</>
)}
- {hasOtherConditions && (
+ {overallFailedConditions.length > 0 && (
<>
- <div className="display-flex-center overview-quality-gate-conditions-section-title">
- <h4 className="padded">{translate('quality_gates.conditions.other_conditions')}</h4>
- {displayConditions(newCodeFailedConditions.length + overallFailedConditions.length)}
- </div>
-
- {newCodeFailedConditions.length > 0 && (
- <>
- <h5 className="big-padded overview-quality-gate-conditions-subsection-title">
- {translate('quality_gates.conditions.new_code')}
- </h5>
- <QualityGateConditions
- component={qgStatus}
- branchLike={qgStatus.branchLike}
- failedConditions={newCodeFailedConditions}
- />
- </>
- )}
-
- {overallFailedConditions.length > 0 && (
- <>
- <h5 className="big-padded overview-quality-gate-conditions-subsection-title">
- {translate('quality_gates.conditions.overall_code')}
- </h5>
- <QualityGateConditions
- component={qgStatus}
- branchLike={qgStatus.branchLike}
- failedConditions={overallFailedConditions}
- />
- </>
+ {showSectionTitles && (
+ <h4 className="big-padded overview-quality-gate-conditions-section-title">
+ {translateWithParameters(
+ 'quality_gates.conditions.overall_code_x',
+ overallFailedConditions.length.toString()
+ )}
+ </h4>
)}
+ <QualityGateConditions
+ component={qgStatus}
+ branchLike={qgStatus.branchLike}
+ failedConditions={overallFailedConditions}
+ />
</>
)}
</>
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-test.tsx
index be4171f53e2..7b0e14a91f4 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-test.tsx
@@ -34,7 +34,6 @@ import { mockQualityGateProjectStatus } from '../../../../helpers/mocks/quality-
import { mockLoggedInUser, mockPeriod } from '../../../../helpers/testMocks';
import { renderComponent } from '../../../../helpers/testReactTestingUtils';
import { ComponentQualifier } from '../../../../types/component';
-import { MetricKey } from '../../../../types/metrics';
import { GraphType } from '../../../../types/project-activity';
import { Measure, Metric } from '../../../../types/types';
import BranchOverview, { BRANCH_OVERVIEW_ACTIVITY_GRAPH, NO_CI_DETECTED } from '../BranchOverview';
@@ -231,32 +230,6 @@ describe('project overview', () => {
expect(await screen.findByText('metric.level.ERROR')).toBeInTheDocument();
expect(screen.getByText('overview.X_conditions_failed.2')).toBeInTheDocument();
-
- expect(
- screen.queryByText('overview.quality_gate.conditions.cayc.passed')
- ).not.toBeInTheDocument();
- });
-
- it('should show a failed QG with passing CAYC conditions', async () => {
- jest.mocked(getQualityGateProjectStatus).mockResolvedValueOnce(
- mockQualityGateProjectStatus({
- status: 'ERROR',
- conditions: [
- {
- actualValue: '12',
- comparator: 'GT',
- errorThreshold: '10',
- metricKey: MetricKey.new_bugs,
- periodIndex: 1,
- status: 'ERROR',
- },
- ],
- })
- );
- renderBranchOverview();
-
- expect(await screen.findByText('metric.level.ERROR')).toBeInTheDocument();
- expect(screen.getByText('overview.quality_gate.conditions.cayc.passed')).toBeInTheDocument();
});
it('should correctly show a project as empty', async () => {
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanelSection-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanelSection-test.tsx
index 251e2730e72..6d151b5bff1 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanelSection-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanelSection-test.tsx
@@ -55,6 +55,7 @@ function shallowRender(props: Partial<QualityGatePanelSectionProps> = {}) {
mockQualityGateStatusConditionEnhanced({ metric: MetricKey.new_bugs }),
],
status: 'ERROR',
+ isCaycCompliant: false,
})}
{...props}
/>
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanelSection-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanelSection-test.tsx.snap
index c49d5435550..dd37526a134 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanelSection-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanelSection-test.tsx.snap
@@ -5,43 +5,15 @@ exports[`should render correctly 1`] = `
className="overview-quality-gate-conditions"
>
<div
- className="display-flex-center overview-quality-gate-conditions-section-title"
- >
- <h4
- className="padded"
- >
- quality_gates.conditions.cayc
- </h4>
- </div>
- <div
className="big-padded bordered-bottom overview-quality-gate-conditions-list"
>
- <Alert
- className="no-margin-bottom"
- variant="success"
- >
- overview.quality_gate.conditions.cayc.passed
- </Alert>
- </div>
- <div
- className="display-flex-center overview-quality-gate-conditions-section-title"
- >
- <h4
- className="padded"
- >
- quality_gates.conditions.other_conditions
- </h4>
- <span
- className="text-muted big-spacer-left"
- >
- overview.X_conditions_failed.2
- </span>
+ <CleanAsYouCodeWarning />
</div>
- <h5
- className="big-padded overview-quality-gate-conditions-subsection-title"
+ <h4
+ className="big-padded overview-quality-gate-conditions-section-title"
>
- quality_gates.conditions.new_code
- </h5>
+ quality_gates.conditions.new_code_x.1
+ </h4>
<Memo(QualityGateConditions)
component={
{
@@ -94,7 +66,7 @@ exports[`should render correctly 1`] = `
},
],
"ignoredConditions": false,
- "isCaycCompliant": true,
+ "isCaycCompliant": false,
"key": "foo",
"name": "Foo",
"status": "ERROR",
@@ -128,11 +100,11 @@ exports[`should render correctly 1`] = `
]
}
/>
- <h5
- className="big-padded overview-quality-gate-conditions-subsection-title"
+ <h4
+ className="big-padded overview-quality-gate-conditions-section-title"
>
- quality_gates.conditions.overall_code
- </h5>
+ quality_gates.conditions.overall_code_x.1
+ </h4>
<Memo(QualityGateConditions)
component={
{
@@ -185,7 +157,7 @@ exports[`should render correctly 1`] = `
},
],
"ignoredConditions": false,
- "isCaycCompliant": true,
+ "isCaycCompliant": false,
"key": "foo",
"name": "Foo",
"status": "ERROR",
@@ -249,43 +221,15 @@ exports[`should render correctly 2`] = `
</div>
</ButtonPlain>
<div
- className="display-flex-center overview-quality-gate-conditions-section-title"
- >
- <h4
- className="padded"
- >
- quality_gates.conditions.cayc
- </h4>
- </div>
- <div
className="big-padded bordered-bottom overview-quality-gate-conditions-list"
>
- <Alert
- className="no-margin-bottom"
- variant="success"
- >
- overview.quality_gate.conditions.cayc.passed
- </Alert>
- </div>
- <div
- className="display-flex-center overview-quality-gate-conditions-section-title"
- >
- <h4
- className="padded"
- >
- quality_gates.conditions.other_conditions
- </h4>
- <span
- className="text-muted big-spacer-left"
- >
- overview.X_conditions_failed.2
- </span>
+ <CleanAsYouCodeWarning />
</div>
- <h5
- className="big-padded overview-quality-gate-conditions-subsection-title"
+ <h4
+ className="big-padded overview-quality-gate-conditions-section-title"
>
- quality_gates.conditions.new_code
- </h5>
+ quality_gates.conditions.new_code_x.1
+ </h4>
<Memo(QualityGateConditions)
component={
{
@@ -338,7 +282,7 @@ exports[`should render correctly 2`] = `
},
],
"ignoredConditions": false,
- "isCaycCompliant": true,
+ "isCaycCompliant": false,
"key": "foo",
"name": "Foo",
"status": "ERROR",
@@ -372,11 +316,11 @@ exports[`should render correctly 2`] = `
]
}
/>
- <h5
- className="big-padded overview-quality-gate-conditions-subsection-title"
+ <h4
+ className="big-padded overview-quality-gate-conditions-section-title"
>
- quality_gates.conditions.overall_code
- </h5>
+ quality_gates.conditions.overall_code_x.1
+ </h4>
<Memo(QualityGateConditions)
component={
{
@@ -429,7 +373,7 @@ exports[`should render correctly 2`] = `
},
],
"ignoredConditions": false,
- "isCaycCompliant": true,
+ "isCaycCompliant": false,
"key": "foo",
"name": "Foo",
"status": "ERROR",
diff --git a/server/sonar-web/src/main/js/apps/overview/styles.css b/server/sonar-web/src/main/js/apps/overview/styles.css
index 17327125a32..d06f711df32 100644
--- a/server/sonar-web/src/main/js/apps/overview/styles.css
+++ b/server/sonar-web/src/main/js/apps/overview/styles.css
@@ -131,13 +131,6 @@
background: var(--barBorderColor);
}
-.overview-quality-gate-conditions-subsection-title {
- background-color: white;
- border-bottom: 1px solid var(--barBorderColor);
- margin: 0;
- font-size: var(--baseFontSize);
-}
-
.overview-quality-gate-conditions-list-collapse {
margin: calc(2 * var(--gridSize)) 0;
}
diff --git a/server/sonar-web/src/main/js/apps/overview/utils.ts b/server/sonar-web/src/main/js/apps/overview/utils.ts
index 332a91fefc6..e42daa22931 100644
--- a/server/sonar-web/src/main/js/apps/overview/utils.ts
+++ b/server/sonar-web/src/main/js/apps/overview/utils.ts
@@ -112,16 +112,6 @@ export enum MeasurementType {
Duplication = 'DUPLICATION',
}
-/*
- * Metrics part of Clean As You Code
- */
-export const CAYC_METRICS: string[] = [
- MetricKey.new_maintainability_rating,
- MetricKey.new_reliability_rating,
- MetricKey.new_security_hotspots_reviewed,
- MetricKey.new_security_rating,
-];
-
const MEASUREMENTS_MAP = {
[MeasurementType.Coverage]: {
metric: MetricKey.coverage,