aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorViktor Vorona <viktor.vorona@sonarsource.com>2024-10-15 17:15:02 +0200
committersonartech <sonartech@sonarsource.com>2024-10-16 20:03:02 +0000
commit3bb32d2694602a7a8c63f307509b85ebb6a5bdcf (patch)
tree75d0c03e86e3f4a2266173fcf6fa262acf7c7d34
parentaff39a4a01010cd4e6425ecd6f17146dd3274f89 (diff)
downloadsonarqube-3bb32d2694602a7a8c63f307509b85ebb6a5bdcf.tar.gz
sonarqube-3bb32d2694602a7a8c63f307509b85ebb6a5bdcf.zip
SONAR-23250 Show only changed impacts in quality profile comparison
-rw-r--r--server/sonar-web/src/main/js/api/quality-profiles.ts13
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx48
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.tsx36
-rw-r--r--server/sonar-web/src/main/js/helpers/testMocks.ts22
4 files changed, 96 insertions, 23 deletions
diff --git a/server/sonar-web/src/main/js/api/quality-profiles.ts b/server/sonar-web/src/main/js/api/quality-profiles.ts
index f8ed8782c79..21a61af4e4f 100644
--- a/server/sonar-web/src/main/js/api/quality-profiles.ts
+++ b/server/sonar-web/src/main/js/api/quality-profiles.ts
@@ -199,23 +199,18 @@ export function getProfileChangelog(
export interface RuleCompare {
cleanCodeAttributeCategory?: CleanCodeAttributeCategory;
- impacts: SoftwareImpact[];
+ impacts?: SoftwareImpact[];
key: string;
- left?: { params: Dict<string>; severity: string };
+ left?: { impacts?: SoftwareImpact[]; params?: Dict<string>; severity?: string };
name: string;
- right?: { params: Dict<string>; severity: string };
+ right?: { impacts?: SoftwareImpact[]; params?: Dict<string>; severity?: string };
}
export interface CompareResponse {
inLeft: Array<RuleCompare>;
inRight: Array<RuleCompare>;
left: { name: string };
- modified: Array<
- RuleCompare & {
- left: { params: Dict<string>; severity: string };
- right: { params: Dict<string>; severity: string };
- }
- >;
+ modified: Array<RuleCompare & Required<Pick<RuleCompare, 'left' | 'right'>>>;
right: { name: string };
}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx
index bf0737f757b..9d0dd72c7a8 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx
@@ -22,7 +22,7 @@ import userEvent from '@testing-library/user-event';
import { byLabelText, byRole, byText } from '~sonar-aligned/helpers/testSelector';
import QualityProfilesServiceMock from '../../../api/mocks/QualityProfilesServiceMock';
import SettingsServiceMock from '../../../api/mocks/SettingsServiceMock';
-import { mockPaging, mockRule } from '../../../helpers/testMocks';
+import { mockCompareResult, mockPaging, mockRule } from '../../../helpers/testMocks';
import { renderAppRoutes } from '../../../helpers/testReactTestingUtils';
import routes from '../routes';
@@ -329,11 +329,57 @@ it('should be able to compare profiles', async () => {
expect(ui.comparisonDiffTableHeading(1, 'java quality profile #2').get()).toBeInTheDocument();
expect(ui.comparisonModifiedTableHeading(1).get()).toBeInTheDocument();
+ expect(
+ ui.comparisonModifiedTableHeading(1).byLabelText('severity_impact.BLOCKER').get(),
+ ).toBeInTheDocument();
+ expect(
+ ui.comparisonModifiedTableHeading(1).byLabelText('severity_impact.LOW').get(),
+ ).toBeInTheDocument();
+
// java quality profile is not editable
expect(ui.activeRuleButton('java quality profile').query()).not.toBeInTheDocument();
expect(ui.deactivateRuleButton('java quality profile').query()).not.toBeInTheDocument();
});
+it('should be able to compare profiles without impacts', async () => {
+ // From the list page
+ const user = userEvent.setup();
+ serviceMock.comparisonResult = mockCompareResult({
+ modified: [
+ {
+ impacts: [],
+ key: 'java:S1698',
+ name: '== and != should not be used when equals is overridden',
+ left: {
+ params: {},
+ severity: 'MINOR',
+ },
+ right: {
+ params: {},
+ severity: 'CRITICAL',
+ },
+ },
+ ],
+ });
+ serviceMock.setAdmin();
+ renderQualityProfiles();
+
+ await user.click(await ui.listProfileActions('java quality profile', 'Java').find());
+ expect(ui.compareButton.get()).toBeInTheDocument();
+ await user.click(ui.compareButton.get());
+ await user.click(ui.compareDropdown.get());
+ await user.click(byRole('option', { name: 'java quality profile #2' }).get());
+
+ expect(await ui.comparisonModifiedTableHeading(1).find()).toBeInTheDocument();
+
+ expect(
+ ui
+ .comparisonModifiedTableHeading(1)
+ .byLabelText(/severity_impact/)
+ .query(),
+ ).not.toBeInTheDocument();
+});
+
it('should be able to activate or deactivate rules in comparison page', async () => {
// From the list page
const user = userEvent.setup();
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.tsx
index 9af91ac5e32..1f66dbd9dfb 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.tsx
@@ -28,6 +28,7 @@ import { CleanCodeAttributePill } from '../../../components/shared/CleanCodeAttr
import SoftwareImpactPillList from '../../../components/shared/SoftwareImpactPillList';
import { getRulesUrl } from '../../../helpers/urls';
import { useStandardExperienceMode } from '../../../queries/settings';
+import { SoftwareImpact } from '../../../types/clean-code-taxonomy';
import { IssueSeverity } from '../../../types/issues';
import { Dict } from '../../../types/types';
import ComparisonResultActivation from './ComparisonResultActivation';
@@ -186,13 +187,13 @@ export default function ComparisonResults(props: Readonly<Props>) {
<TableRowInteractive key={`modified-${rule.key}`}>
<ContentCell>
<div>
- <RuleCell rule={rule} severity={rule.left.severity} />
+ <RuleCell rule={rule} severity={rule.left.severity} impacts={rule.left.impacts} />
<Parameters params={rule.left.params} />
</div>
</ContentCell>
<ContentCell className="sw-pl-4">
<div>
- <RuleCell rule={rule} severity={rule.right.severity} />
+ <RuleCell rule={rule} severity={rule.right.severity} impacts={rule.right.impacts} />
<Parameters params={rule.right.params} />
</div>
</ContentCell>
@@ -223,14 +224,24 @@ export default function ComparisonResults(props: Readonly<Props>) {
);
}
-function RuleCell({ rule, severity }: Readonly<{ rule: RuleCompare; severity?: string }>) {
+type RuleCellProps = {
+ impacts?: SoftwareImpact[];
+ rule: RuleCompare;
+ severity?: string;
+};
+
+function RuleCell({ rule, severity, impacts }: Readonly<RuleCellProps>) {
const { data: isStandardMode } = useStandardExperienceMode();
const shouldRenderSeverity =
- isStandardMode &&
- Boolean(severity) &&
- rule.left &&
- rule.right &&
- isEqual(rule.left.params, rule.right.params);
+ isStandardMode &&Boolean(severity) &&
+ rule.left?.severity &&
+ rule.right?.severity &&
+ !isEqual(rule.left.severity,
+ rule.right.severity);
+ const shouldRenderImpacts =
+ rule.impacts ||
+ (rule.left?.impacts && rule.right?.impacts &&
+ !isEqual(rule.left.impacts, rule.right.impacts));
return (
<div>
@@ -238,7 +249,7 @@ function RuleCell({ rule, severity }: Readonly<{ rule: RuleCompare; severity?: s
<LinkStandalone className="sw-ml-1" to={getRulesUrl({ rule_key: rule.key, open: rule.key })}>
{rule.name}
</LinkStandalone>
- {!isStandardMode && (rule.cleanCodeAttributeCategory || rule.impacts.length > 0) && (
+ {!isStandardMode && (rule.cleanCodeAttributeCategory || shouldRenderImpacts) && (
<ul className="sw-mt-3 sw-flex sw-items-center">
{rule.cleanCodeAttributeCategory && (
<li>
@@ -247,9 +258,12 @@ function RuleCell({ rule, severity }: Readonly<{ rule: RuleCompare; severity?: s
/>
</li>
)}
- {rule.impacts.length > 0 && (
+ {((impacts && impacts.length > 0) || rule.impacts) && (
<li>
- <SoftwareImpactPillList className="sw-ml-2" softwareImpacts={rule.impacts} />
+ <SoftwareImpactPillList
+ className="sw-ml-2"
+ softwareImpacts={impacts ?? rule.impacts ?? []}
+ />
</li>
)}
</ul>
diff --git a/server/sonar-web/src/main/js/helpers/testMocks.ts b/server/sonar-web/src/main/js/helpers/testMocks.ts
index 2408be0427c..3abec815549 100644
--- a/server/sonar-web/src/main/js/helpers/testMocks.ts
+++ b/server/sonar-web/src/main/js/helpers/testMocks.ts
@@ -551,8 +551,26 @@ export function mockCompareResult(overrides: Partial<CompareResponse> = {}): Com
impacts: [],
key: 'java:S1698',
name: '== and != should not be used when equals is overridden',
- left: { params: {}, severity: 'MINOR' },
- right: { params: {}, severity: 'CRITICAL' },
+ left: {
+ params: {},
+ severity: 'MINOR',
+ impacts: [
+ {
+ softwareQuality: SoftwareQuality.Security,
+ severity: SoftwareImpactSeverity.Blocker,
+ },
+ ],
+ },
+ right: {
+ params: {},
+ severity: 'CRITICAL',
+ impacts: [
+ {
+ softwareQuality: SoftwareQuality.Security,
+ severity: SoftwareImpactSeverity.Low,
+ },
+ ],
+ },
},
],
...overrides,