From: Julien HENRY Date: Tue, 12 Jun 2018 09:39:04 +0000 (+0200) Subject: SONAR-10867 Add security hotspot new issue type X-Git-Tag: 7.5~891 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=d42307dd484ab82daecddb4e98b2085ba711b34f;p=sonarqube.git SONAR-10867 Add security hotspot new issue type --- diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/EffortAggregator.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/EffortAggregator.java index 51e4c20d02a..78cb17a8208 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/EffortAggregator.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/EffortAggregator.java @@ -119,6 +119,9 @@ public class EffortAggregator extends IssueVisitor { case VULNERABILITY: securityEffort += issueEffort; break; + case SECURITY_HOTSPOT: + // Not counted + break; default: throw new IllegalStateException(String.format("Unknown type '%s'", issue.type())); } diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/NewEffortAggregator.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/NewEffortAggregator.java index a9e3c2e3c93..7c7f9e0473f 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/NewEffortAggregator.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/NewEffortAggregator.java @@ -121,6 +121,9 @@ public class NewEffortAggregator extends IssueVisitor { case VULNERABILITY: securitySum.add(newEffort); break; + case SECURITY_HOTSPOT: + // Not counted + break; default: throw new IllegalStateException(String.format("Unknown type '%s'", issue.type())); } diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java index 97243a5ab87..58801ef4de6 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java @@ -238,6 +238,8 @@ public class TrackerRawInputFactory { return RuleType.CODE_SMELL; case VULNERABILITY: return RuleType.VULNERABILITY; + case SECURITY_HOTSPOT: + return RuleType.SECURITY_HOTSPOT; case UNRECOGNIZED: default: throw new IllegalStateException("Invalid issue type: " + type); diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesStatisticsTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesStatisticsTest.java index 0bbe22f5558..b318fab55f5 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesStatisticsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesStatisticsTest.java @@ -49,7 +49,7 @@ public class NewIssuesStatisticsTest { public ExpectedException expectedException = ExpectedException.none(); private final Random random = new Random(); - private RuleType randomRuleType = RuleType.values()[random.nextInt(RuleType.values().length)]; + private RuleType randomRuleTypeExceptHotspot = RuleType.values()[random.nextInt(RuleType.values().length - 1)]; private NewIssuesStatistics underTest = new NewIssuesStatistics(Issue::isNew); @Test @@ -126,7 +126,7 @@ public class NewIssuesStatisticsTest { List componentUuids = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList()); String assignee = randomAlphanumeric(10); componentUuids.stream() - .map(componentUuid -> new DefaultIssue().setType(randomRuleType).setComponentUuid(componentUuid).setAssigneeUuid(assignee).setNew(true)) + .map(componentUuid -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setComponentUuid(componentUuid).setAssigneeUuid(assignee).setNew(true)) .forEach(underTest::add); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT); @@ -140,7 +140,7 @@ public class NewIssuesStatisticsTest { List componentUuids = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList()); String assignee = randomAlphanumeric(10); componentUuids.stream() - .map(componentUuid -> new DefaultIssue().setType(randomRuleType).setComponentUuid(componentUuid).setAssigneeUuid(assignee).setNew(false)) + .map(componentUuid -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setComponentUuid(componentUuid).setAssigneeUuid(assignee).setNew(false)) .forEach(underTest::add); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT); @@ -153,7 +153,7 @@ public class NewIssuesStatisticsTest { @Test public void add_does_not_count_component_if_null_neither_globally_nor_per_assignee() { String assignee = randomAlphanumeric(10); - underTest.add(new DefaultIssue().setType(randomRuleType).setComponentUuid(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean())); + underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setComponentUuid(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean())); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT); DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.COMPONENT); @@ -170,7 +170,7 @@ public class NewIssuesStatisticsTest { List ruleKeys = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList()); String assignee = randomAlphanumeric(10); ruleKeys.stream() - .map(ruleKey -> new DefaultIssue().setType(randomRuleType).setRuleKey(RuleKey.of(repository, ruleKey)).setAssigneeUuid(assignee).setNew(true)) + .map(ruleKey -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setRuleKey(RuleKey.of(repository, ruleKey)).setAssigneeUuid(assignee).setNew(true)) .forEach(underTest::add); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE); @@ -186,7 +186,7 @@ public class NewIssuesStatisticsTest { List ruleKeys = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList()); String assignee = randomAlphanumeric(10); ruleKeys.stream() - .map(ruleKey -> new DefaultIssue().setType(randomRuleType).setRuleKey(RuleKey.of(repository, ruleKey)).setAssigneeUuid(assignee).setNew(false)) + .map(ruleKey -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setRuleKey(RuleKey.of(repository, ruleKey)).setAssigneeUuid(assignee).setNew(false)) .forEach(underTest::add); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE); @@ -198,7 +198,7 @@ public class NewIssuesStatisticsTest { @Test public void add_does_not_count_ruleKey_if_null_neither_globally_nor_per_assignee() { String assignee = randomAlphanumeric(10); - underTest.add(new DefaultIssue().setType(randomRuleType).setRuleKey(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean())); + underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setRuleKey(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean())); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE); DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.RULE); @@ -213,7 +213,7 @@ public class NewIssuesStatisticsTest { public void add_counts_issue_per_assignee_on_leak_globally_and_per_assignee() { List assignees = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList()); assignees.stream() - .map(assignee -> new DefaultIssue().setType(randomRuleType).setAssigneeUuid(assignee).setNew(true)) + .map(assignee -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setAssigneeUuid(assignee).setNew(true)) .forEach(underTest::add); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE); @@ -243,7 +243,7 @@ public class NewIssuesStatisticsTest { public void add_counts_issue_per_assignee_off_leak_globally_and_per_assignee() { List assignees = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList()); assignees.stream() - .map(assignee -> new DefaultIssue().setType(randomRuleType).setAssigneeUuid(assignee).setNew(false)) + .map(assignee -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setAssigneeUuid(assignee).setNew(false)) .forEach(underTest::add); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE); @@ -271,7 +271,7 @@ public class NewIssuesStatisticsTest { @Test public void add_does_not_assignee_if_empty_neither_globally_nor_per_assignee() { - underTest.add(new DefaultIssue().setType(randomRuleType).setAssigneeUuid(null).setNew(new Random().nextBoolean())); + underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setAssigneeUuid(null).setNew(new Random().nextBoolean())); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE); assertThat(globalDistribution.getTotal()).isEqualTo(0); @@ -283,7 +283,7 @@ public class NewIssuesStatisticsTest { public void add_counts_issue_per_tags_on_leak_globally_and_per_assignee() { List tags = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList()); String assignee = randomAlphanumeric(10); - underTest.add(new DefaultIssue().setType(randomRuleType).setTags(tags).setAssigneeUuid(assignee).setNew(true)); + underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setTags(tags).setAssigneeUuid(assignee).setNew(true)); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG); DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG); @@ -295,7 +295,7 @@ public class NewIssuesStatisticsTest { public void add_counts_issue_per_tags_off_leak_globally_and_per_assignee() { List tags = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList()); String assignee = randomAlphanumeric(10); - underTest.add(new DefaultIssue().setType(randomRuleType).setTags(tags).setAssigneeUuid(assignee).setNew(false)); + underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setTags(tags).setAssigneeUuid(assignee).setNew(false)); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG); DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG); @@ -306,7 +306,7 @@ public class NewIssuesStatisticsTest { @Test public void add_does_not_count_tags_if_empty_neither_globally_nor_per_assignee() { String assignee = randomAlphanumeric(10); - underTest.add(new DefaultIssue().setType(randomRuleType).setTags(Collections.emptyList()).setAssigneeUuid(assignee).setNew(new Random().nextBoolean())); + underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setTags(Collections.emptyList()).setAssigneeUuid(assignee).setNew(new Random().nextBoolean())); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG); DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG); @@ -324,7 +324,7 @@ public class NewIssuesStatisticsTest { int expected = efforts.stream().mapToInt(s -> s).sum(); String assignee = randomAlphanumeric(10); efforts.stream() - .map(effort -> new DefaultIssue().setType(randomRuleType).setEffort(Duration.create(effort)).setAssigneeUuid(assignee).setNew(true)) + .map(effort -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setEffort(Duration.create(effort)).setAssigneeUuid(assignee).setNew(true)) .forEach(underTest::add); MetricStatsLong globalDistribution = underTest.globalStatistics().effort(); @@ -344,7 +344,7 @@ public class NewIssuesStatisticsTest { int expected = efforts.stream().mapToInt(s -> s).sum(); String assignee = randomAlphanumeric(10); efforts.stream() - .map(effort -> new DefaultIssue().setType(randomRuleType).setEffort(Duration.create(effort)).setAssigneeUuid(assignee).setNew(false)) + .map(effort -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setEffort(Duration.create(effort)).setAssigneeUuid(assignee).setNew(false)) .forEach(underTest::add); MetricStatsLong globalDistribution = underTest.globalStatistics().effort(); @@ -360,7 +360,7 @@ public class NewIssuesStatisticsTest { @Test public void add_does_not_sum_effort_if_null_neither_globally_nor_per_assignee() { String assignee = randomAlphanumeric(10); - underTest.add(new DefaultIssue().setType(randomRuleType).setEffort(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean())); + underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setEffort(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean())); MetricStatsLong globalDistribution = underTest.globalStatistics().effort(); MetricStatsLong assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).effort(); @@ -381,7 +381,7 @@ public class NewIssuesStatisticsTest { int effort = 10 + new Random().nextInt(5); RuleKey ruleKey = RuleKey.of(randomAlphanumeric(5), randomAlphanumeric(6)); underTest.add(new DefaultIssue() - .setType(randomRuleType) + .setType(randomRuleTypeExceptHotspot) .setComponentUuid(componentUuid) .setTags(ImmutableSet.of(tag)) .setAssigneeUuid(assignee) @@ -393,7 +393,7 @@ public class NewIssuesStatisticsTest { "assigneesStatistics={" + assignee + "=" + "Stats{distributions={" + "RULE_TYPE=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + - "statsPerLabel={" + randomRuleType.name() + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " + + "statsPerLabel={" + randomRuleTypeExceptHotspot.name() + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " + "TAG=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + "statsPerLabel={" + tag + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " + "COMPONENT=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + @@ -405,7 +405,7 @@ public class NewIssuesStatisticsTest { "effortStats=MetricStatsLong{onLeak=" + effort + ", offLeak=0}}}, " + "globalStatistics=Stats{distributions={" + "RULE_TYPE=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + - "statsPerLabel={" + randomRuleType.name() + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " + + "statsPerLabel={" + randomRuleTypeExceptHotspot.name() + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " + "TAG=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + "statsPerLabel={" + tag + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " + "COMPONENT=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTypeActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTypeActionTest.java index b3b11aeb5c4..d6fe59d9f61 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTypeActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTypeActionTest.java @@ -138,7 +138,7 @@ public class SetTypeActionTest { setUserWithBrowseAndAdministerIssuePermission(issueDto); expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Value of parameter 'type' (unknown) must be one of: [CODE_SMELL, BUG, VULNERABILITY]"); + expectedException.expectMessage("Value of parameter 'type' (unknown) must be one of: [CODE_SMELL, BUG, VULNERABILITY, SECURITY_HOTSPOT]"); call(issueDto.getKey(), "unknown"); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java index 93c88fffd81..61cade0fb54 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java @@ -861,7 +861,8 @@ public class SearchActionTest { .containsExactlyInAnyOrder( tuple("BUG" /* rule2 */, 0L), tuple("CODE_SMELL"/* rule1 */, 1L), - tuple("VULNERABILITY", 0L)); + tuple("VULNERABILITY", 0L), + tuple("SECURITY_HOTSPOT", 0L)); } @Test diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/display_facets.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/display_facets.json index 5778db4cb02..38fd2f2b973 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/display_facets.json +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/display_facets.json @@ -145,6 +145,10 @@ { "val": "VULNERABILITY", "count": 0 + }, + { + "val": "SECURITY_HOTSPOT", + "count": 0 } ] } diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/TypeFacet.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/TypeFacet.tsx index 8094cf54b33..ff2accac97f 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/components/TypeFacet.tsx +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/TypeFacet.tsx @@ -33,7 +33,7 @@ export default class TypeFacet extends React.PureComponent { renderTextName = (type: string) => translate('issue.type', type); render() { - const options = ['BUG', 'VULNERABILITY', 'CODE_SMELL']; + const options = ['BUG', 'VULNERABILITY', 'CODE_SMELL', 'SECURITY_HOTSPOT']; return ( { }; render() { - const types = ['BUG', 'VULNERABILITY', 'CODE_SMELL']; + const types = ['BUG', 'VULNERABILITY', 'CODE_SMELL', 'SECURITY_HOTSPOT']; const values = this.props.types.map(type => translate('issue.type', type)); return ( diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx index a3a73a80a9f..261f5998c75 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx @@ -30,7 +30,7 @@ import { getRulesUrl } from '../../../helpers/urls'; import { translate } from '../../../helpers/l10n'; import { Profile } from '../types'; -const TYPES = ['BUG', 'VULNERABILITY', 'CODE_SMELL']; +const TYPES = ['BUG', 'VULNERABILITY', 'CODE_SMELL', 'SECURITY_HOTSPOT']; interface Props { organization: string | null; diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRules-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRules-test.tsx index fcabce9784a..2a313ccb6d8 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRules-test.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRules-test.tsx @@ -43,14 +43,15 @@ const PROFILE = { const EDITABLE_PROFILE = { ...PROFILE, actions: { edit: true } }; const apiResponseAll = { - total: 243, + total: 253, facets: [ { property: 'types', values: [ { val: 'CODE_SMELL', count: 168 }, { val: 'BUG', count: 68 }, - { val: 'VULNERABILITY', count: 7 } + { val: 'VULNERABILITY', count: 7 }, + { val: 'SECURITY_HOTSPOT', count: 10 } ] } ] @@ -64,7 +65,8 @@ const apiResponseActive = { values: [ { val: 'BUG', count: 68 }, { val: 'CODE_SMELL', count: 0 }, - { val: 'VULNERABILITY', count: 0 } + { val: 'VULNERABILITY', count: 0 }, + { val: 'SECURITY_HOTSPOT', count: 0 } ] } ] diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRules-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRules-test.tsx.snap index 2fd0450b1bd..ea82cabc5dc 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRules-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRules-test.tsx.snap @@ -30,7 +30,7 @@ exports[`should render the quality profiles rules with sonarway comparison 1`] = count={68} organization="foo" qprofile="foo" - total={243} + total={253} /> + diff --git a/server/sonar-web/src/main/js/components/icons-components/SecurityHotspotIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/SecurityHotspotIcon.tsx new file mode 100644 index 00000000000..334d10852db --- /dev/null +++ b/server/sonar-web/src/main/js/components/icons-components/SecurityHotspotIcon.tsx @@ -0,0 +1,43 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 * as React from 'react'; +import Icon, { IconProps } from './Icon'; + +export default function SecurityHotspotIcon({ className, fill = 'currentColor', size }: IconProps) { + return ( + + + + + + + + + ); +} diff --git a/server/sonar-web/src/main/js/components/ui/IssueTypeIcon.tsx b/server/sonar-web/src/main/js/components/ui/IssueTypeIcon.tsx index 5cf34fe37e3..05252164305 100644 --- a/server/sonar-web/src/main/js/components/ui/IssueTypeIcon.tsx +++ b/server/sonar-web/src/main/js/components/ui/IssueTypeIcon.tsx @@ -21,6 +21,7 @@ import * as React from 'react'; import BugIcon from '../icons-components/BugIcon'; import VulnerabilityIcon from '../icons-components/VulnerabilityIcon'; import CodeSmellIcon from '../icons-components/CodeSmellIcon'; +import SecurityHotspotIcon from '../icons-components/SecurityHotspotIcon'; interface Props { className?: string; @@ -47,6 +48,10 @@ export default function IssueTypeIcon({ className, query, size }: Props) { case 'new_code_smells': icon = ; break; + case 'security_hotspot': + case 'security_hotspots': + icon = ; + break; } if (!icon) { diff --git a/server/sonar-web/src/main/js/helpers/constants.ts b/server/sonar-web/src/main/js/helpers/constants.ts index 7c6a893ca7f..0857573b85f 100644 --- a/server/sonar-web/src/main/js/helpers/constants.ts +++ b/server/sonar-web/src/main/js/helpers/constants.ts @@ -21,7 +21,7 @@ import * as theme from '../app/theme'; export const SEVERITIES = ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO']; export const STATUSES = ['OPEN', 'REOPENED', 'CONFIRMED', 'RESOLVED', 'CLOSED']; -export const TYPES = ['BUG', 'VULNERABILITY', 'CODE_SMELL']; +export const TYPES = ['BUG', 'VULNERABILITY', 'CODE_SMELL', 'SECURITY_HOTSPOT']; export const RULE_STATUSES = ['READY', 'BETA', 'DEPRECATED']; export const CHART_COLORS_RANGE_PERCENT = [ diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 79d87fab775..fb53c1bfbde 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -589,9 +589,11 @@ issue.set_type=Change Type issue.type.CODE_SMELL=Code Smell issue.type.BUG=Bug issue.type.VULNERABILITY=Vulnerability +issue.type.SECURITY_HOTSPOT=Security Hotspot issue.type.CODE_SMELL.plural=Code Smells issue.type.BUG.plural=Bugs issue.type.VULNERABILITY.plural=Vulnerabilities +issue.type.SECURITY_HOTSPOT.plural=Security Hotspots issue.status.REOPENED=Reopened @@ -1277,6 +1279,7 @@ coding_rules.to_select_rules=to select rules coding_rules.type.tooltip.CODE_SMELL=Code Smell Detection Rule coding_rules.type.tooltip.BUG=Bug Detection Rule coding_rules.type.tooltip.VULNERABILITY=Vulnerability Detection Rule +coding_rules.type.tooltip.SECURITY_HOTSPOT=Security Hotspot Detection Rule coding_rules.update_custom_rule=Update Custom Rule coding_rules.filter_similar_rules=Filter Similar Rules diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/rules/RuleType.java b/sonar-plugin-api/src/main/java/org/sonar/api/rules/RuleType.java index fc1bb923540..79cb255acc6 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/rules/RuleType.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/rules/RuleType.java @@ -29,7 +29,7 @@ import static java.util.Collections.unmodifiableSet; import static java.util.stream.Collectors.toList; public enum RuleType { - CODE_SMELL(1), BUG(2), VULNERABILITY(3); + CODE_SMELL(1), BUG(2), VULNERABILITY(3), SECURITY_HOTSPOT(4); private static final Set ALL_NAMES = unmodifiableSet(new LinkedHashSet<>(stream(values()) .map(Enum::name) diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/rules/RuleTypeTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/rules/RuleTypeTest.java index aec770fbc42..7c9c51e33f0 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/rules/RuleTypeTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/rules/RuleTypeTest.java @@ -39,13 +39,13 @@ public class RuleTypeTest { @Test public void valueOf_throws_ISE_if_unsupported_db_constant() { expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Unsupported type value : 4"); - RuleType.valueOf(4); + expectedException.expectMessage("Unsupported type value : 5"); + RuleType.valueOf(5); } @Test public void test_ALL_NAMES() { - assertThat(RuleType.names()).containsOnly("BUG", "VULNERABILITY", "CODE_SMELL"); + assertThat(RuleType.names()).containsOnly("BUG", "VULNERABILITY", "CODE_SMELL", "SECURITY_HOTSPOT"); } @Test diff --git a/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto b/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto index 66930fb3a69..821b35e4d9a 100644 --- a/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto +++ b/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto @@ -204,6 +204,7 @@ enum IssueType { CODE_SMELL = 0; BUG = 1; VULNERABILITY = 2; + SECURITY_HOTSPOT = 3; } message IssueLocation { diff --git a/sonar-ws/src/main/protobuf/ws-commons.proto b/sonar-ws/src/main/protobuf/ws-commons.proto index 106a3ab1f6f..442630a7fce 100644 --- a/sonar-ws/src/main/protobuf/ws-commons.proto +++ b/sonar-ws/src/main/protobuf/ws-commons.proto @@ -118,6 +118,7 @@ enum RuleType { CODE_SMELL = 1; BUG = 2; VULNERABILITY = 3; + SECURITY_HOTSPOT = 4; } enum BranchType {