]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10070 Show badge on issues raised by deprecated/removed rules
authorWouter Admiraal <wouter.admiraal@sonarsource.com>
Mon, 7 Dec 2020 11:00:02 +0000 (12:00 +0100)
committersonartech <sonartech@sonarsource.com>
Thu, 17 Dec 2020 20:08:00 +0000 (20:08 +0000)
Co-authored-by: Siegfried Ehret <siegfried.ehret@sonarsource.com>
Co-authored-by: Wouter Admiraal <wouter.admiraal@sonarsource.com>
server/sonar-web/src/main/js/app/theme.js
server/sonar-web/src/main/js/components/issue/Issue.css
server/sonar-web/src/main/js/components/issue/components/IssueMessage.tsx
server/sonar-web/src/main/js/components/issue/components/IssueTitleBar.tsx
server/sonar-web/src/main/js/components/issue/components/__tests__/IssueMessage-test.tsx
server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueMessage-test.tsx.snap
server/sonar-web/src/main/js/types/rules.ts [new file with mode: 0644]
server/sonar-web/src/main/js/types/types.d.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index f888c8c5709ec18727c097538c52ac924881cab3..12fdd4422bc506ca56e643ba31648aa6bc93671e 100644 (file)
@@ -107,6 +107,7 @@ module.exports = {
     // badge
     badgeBlueBackground: '#2E7CB5',
     badgeBlueColor: '#FFFFFF',
+    badgeRedBackgroundOnIssue: '#EEC8C8',
 
     // alm
     azure: '#0078d7',
index 899ee3a0e42511106a4dfc5b6dca1250bfb9b25d..c659effd5d6bb7faa6d51ca0aae020167008c0f1 100644 (file)
   max-height: 120px;
   overflow: auto;
 }
+
+.issue .badge-error {
+  background-color: var(--badgeRedBackgroundOnIssue);
+}
index 970748031e9193b08780a5d966231e78ea1e51cf..e0ccc98b4f8da87936ff8f2d96594879a399aad8 100644 (file)
@@ -21,6 +21,8 @@ import * as React from 'react';
 import { ButtonLink } from 'sonar-ui-common/components/controls/buttons';
 import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
 import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
+import { RuleStatus } from '../../../types/rules';
+import DocumentationTooltip from '../../common/DocumentationTooltip';
 import { WorkspaceContextShape } from '../../workspace/context';
 
 export interface IssueMessageProps {
@@ -31,10 +33,19 @@ export interface IssueMessageProps {
   onOpenRule: WorkspaceContextShape['openRule'];
   organization: string;
   ruleKey: string;
+  ruleStatus?: RuleStatus;
 }
 
 export default function IssueMessage(props: IssueMessageProps) {
-  const { engine, engineName, manualVulnerability, message, organization, ruleKey } = props;
+  const {
+    engine,
+    engineName,
+    manualVulnerability,
+    message,
+    organization,
+    ruleKey,
+    ruleStatus
+  } = props;
   const ruleEngine = engineName ? engineName : engine;
 
   return (
@@ -47,6 +58,22 @@ export default function IssueMessage(props: IssueMessageProps) {
         {translate('issue.why_this_issue')}
       </ButtonLink>
 
+      {ruleStatus && (ruleStatus === RuleStatus.Deprecated || ruleStatus === RuleStatus.Removed) && (
+        <DocumentationTooltip
+          className="spacer-left"
+          content={translate('rules.status', ruleStatus, 'help')}
+          links={[
+            {
+              href: '/documentation/user-guide/rules/',
+              label: translateWithParameters('see_x', translate('rules'))
+            }
+          ]}>
+          <span className="spacer-right badge badge-error">
+            {translate('rules.status', ruleStatus)}
+          </span>
+        </DocumentationTooltip>
+      )}
+
       {ruleEngine && (
         <Tooltip overlay={translateWithParameters('issue.from_external_rule_engine', ruleEngine)}>
           <div className="badge spacer-right text-baseline">{ruleEngine}</div>
index 1b9ec10f0a9df016de8486085fea19f1af0fca64..c19554396a6adc49b57b72ffa0119d38e6ff285a 100644 (file)
@@ -26,6 +26,7 @@ import { formatMeasure } from 'sonar-ui-common/helpers/measures';
 import { getBranchLikeQuery } from '../../../helpers/branch-like';
 import { getComponentIssuesUrl } from '../../../helpers/urls';
 import { BranchLike } from '../../../types/branch-like';
+import { RuleStatus } from '../../../types/rules';
 import LocationIndex from '../../common/LocationIndex';
 import { WorkspaceContext } from '../../workspace/context';
 import IssueChangelog from './IssueChangelog';
@@ -85,6 +86,7 @@ export default function IssueTitleBar(props: IssueTitleBarProps) {
             onOpenRule={openRule}
             organization={issue.organization}
             ruleKey={issue.rule}
+            ruleStatus={issue.ruleStatus as RuleStatus | undefined}
           />
         )}
       </WorkspaceContext.Consumer>
index 61793579040cccbff47d0d0daa1a7209211ba3b3..a53ad25f7c05b288ac5469bb1c602d3c3e97cce1 100644 (file)
@@ -22,6 +22,7 @@ import { shallow } from 'enzyme';
 import * as React from 'react';
 import { ButtonLink } from 'sonar-ui-common/components/controls/buttons';
 import { click } from 'sonar-ui-common/helpers/testUtils';
+import { RuleStatus } from '../../../../types/rules';
 import IssueMessage, { IssueMessageProps } from '../IssueMessage';
 
 it('should render correctly', () => {
@@ -29,6 +30,10 @@ it('should render correctly', () => {
   expect(shallowRender({ engine: 'js' })).toMatchSnapshot('with engine info');
   expect(shallowRender({ engineName: 'JS' })).toMatchSnapshot('with engine name');
   expect(shallowRender({ manualVulnerability: true })).toMatchSnapshot('is manual vulnerability');
+  expect(shallowRender({ ruleStatus: RuleStatus.Deprecated })).toMatchSnapshot(
+    'is deprecated rule'
+  );
+  expect(shallowRender({ ruleStatus: RuleStatus.Removed })).toMatchSnapshot('is removed rule');
 });
 
 it('should handle click correctly', () => {
index 1142d0b5bb8e88debee2f1db0f49fb73b1f3f24d..05ac47ff7ea7d88e342c358bc8a5b63b8f41b80e 100644 (file)
@@ -19,6 +19,43 @@ exports[`should render correctly: default 1`] = `
 </div>
 `;
 
+exports[`should render correctly: is deprecated rule 1`] = `
+<div
+  className="issue-message break-word"
+>
+  <span
+    className="spacer-right"
+  >
+    Reduce the number of conditional operators (4) used in the expression
+  </span>
+  <ButtonLink
+    aria-label="issue.why_this_issue.long"
+    className="issue-see-rule spacer-right text-baseline"
+    onClick={[Function]}
+  >
+    issue.why_this_issue
+  </ButtonLink>
+  <DocumentationTooltip
+    className="spacer-left"
+    content="rules.status.DEPRECATED.help"
+    links={
+      Array [
+        Object {
+          "href": "/documentation/user-guide/rules/",
+          "label": "see_x.rules",
+        },
+      ]
+    }
+  >
+    <span
+      className="spacer-right badge badge-error"
+    >
+      rules.status.DEPRECATED
+    </span>
+  </DocumentationTooltip>
+</div>
+`;
+
 exports[`should render correctly: is manual vulnerability 1`] = `
 <div
   className="issue-message break-word"
@@ -47,6 +84,43 @@ exports[`should render correctly: is manual vulnerability 1`] = `
 </div>
 `;
 
+exports[`should render correctly: is removed rule 1`] = `
+<div
+  className="issue-message break-word"
+>
+  <span
+    className="spacer-right"
+  >
+    Reduce the number of conditional operators (4) used in the expression
+  </span>
+  <ButtonLink
+    aria-label="issue.why_this_issue.long"
+    className="issue-see-rule spacer-right text-baseline"
+    onClick={[Function]}
+  >
+    issue.why_this_issue
+  </ButtonLink>
+  <DocumentationTooltip
+    className="spacer-left"
+    content="rules.status.REMOVED.help"
+    links={
+      Array [
+        Object {
+          "href": "/documentation/user-guide/rules/",
+          "label": "see_x.rules",
+        },
+      ]
+    }
+  >
+    <span
+      className="spacer-right badge badge-error"
+    >
+      rules.status.REMOVED
+    </span>
+  </DocumentationTooltip>
+</div>
+`;
+
 exports[`should render correctly: with engine info 1`] = `
 <div
   className="issue-message break-word"
diff --git a/server/sonar-web/src/main/js/types/rules.ts b/server/sonar-web/src/main/js/types/rules.ts
new file mode 100644 (file)
index 0000000..7c06db1
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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.
+ */
+
+export enum RuleStatus {
+  Ready = 'READY',
+  Beta = 'BETA',
+  Deprecated = 'DEPRECATED',
+  Removed = 'REMOVED'
+}
index 56219d6f11c75d1ffc1b671191ce35dd61e6fc42..d946f35bb63ea931b8da439307b11195d38b51d7 100644 (file)
@@ -352,6 +352,7 @@ declare namespace T {
     resolution?: string;
     rule: string;
     ruleName: string;
+    ruleStatus?: string;
     secondaryLocations: FlowLocation[];
     severity: string;
     status: string;
index 738b934e13dd6f91f0437a94cd96ca4284d048c8..3ea97aac1d01e8b67f3051591f35ed9b560be1c3 100644 (file)
@@ -176,6 +176,7 @@ save=Save
 search_results=Search results
 search_verb=Search
 see_all=See all
+see_x=See {0}
 select_verb=Select
 selected=Selected
 set=Set
@@ -1598,9 +1599,11 @@ rules.status.beta=Beta
 rules.status.BETA=Beta
 rules.status.deprecated=Deprecated
 rules.status.DEPRECATED=Deprecated
+rules.status.DEPRECATED.help=The rule that generated this issue has been deprecated and will be removed. Once the rule is removed, this issue will no longer appear.
 rules.status.ready=Ready
 rules.status.READY=Ready
 rules.status.REMOVED=Removed
+rules.status.REMOVED.help=The rule that generated this issue has been removed. Starting on the next analysis, this issue will no longer appear.
 
 
 #------------------------------------------------------------------------------