Browse Source

SONAR-10867 Add security hotspot new issue type

tags/7.5
Julien HENRY 6 years ago
parent
commit
d42307dd48
20 changed files with 109 additions and 33 deletions
  1. 3
    0
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/EffortAggregator.java
  2. 3
    0
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/NewEffortAggregator.java
  3. 2
    0
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java
  4. 19
    19
      server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesStatisticsTest.java
  5. 1
    1
      server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTypeActionTest.java
  6. 2
    1
      server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java
  7. 4
    0
      server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/display_facets.json
  8. 1
    1
      server/sonar-web/src/main/js/apps/coding-rules/components/TypeFacet.tsx
  9. 1
    1
      server/sonar-web/src/main/js/apps/issues/sidebar/TypeFacet.tsx
  10. 1
    1
      server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx
  11. 5
    3
      server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRules-test.tsx
  12. 9
    1
      server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRules-test.tsx.snap
  13. 43
    0
      server/sonar-web/src/main/js/components/icons-components/SecurityHotspotIcon.tsx
  14. 5
    0
      server/sonar-web/src/main/js/components/ui/IssueTypeIcon.tsx
  15. 1
    1
      server/sonar-web/src/main/js/helpers/constants.ts
  16. 3
    0
      sonar-core/src/main/resources/org/sonar/l10n/core.properties
  17. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/rules/RuleType.java
  18. 3
    3
      sonar-plugin-api/src/test/java/org/sonar/api/rules/RuleTypeTest.java
  19. 1
    0
      sonar-scanner-protocol/src/main/protobuf/scanner_report.proto
  20. 1
    0
      sonar-ws/src/main/protobuf/ws-commons.proto

+ 3
- 0
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/EffortAggregator.java View File

@@ -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()));
}

+ 3
- 0
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/NewEffortAggregator.java View File

@@ -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()));
}

+ 2
- 0
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java View File

@@ -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);

+ 19
- 19
server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesStatisticsTest.java View File

@@ -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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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}, " +

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTypeActionTest.java View File

@@ -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");
}


+ 2
- 1
server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java View File

@@ -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

+ 4
- 0
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/display_facets.json View File

@@ -145,6 +145,10 @@
{
"val": "VULNERABILITY",
"count": 0
},
{
"val": "SECURITY_HOTSPOT",
"count": 0
}
]
}

+ 1
- 1
server/sonar-web/src/main/js/apps/coding-rules/components/TypeFacet.tsx View File

@@ -33,7 +33,7 @@ export default class TypeFacet extends React.PureComponent<BasicProps> {
renderTextName = (type: string) => translate('issue.type', type);

render() {
const options = ['BUG', 'VULNERABILITY', 'CODE_SMELL'];
const options = ['BUG', 'VULNERABILITY', 'CODE_SMELL', 'SECURITY_HOTSPOT'];

return (
<Facet

+ 1
- 1
server/sonar-web/src/main/js/apps/issues/sidebar/TypeFacet.tsx View File

@@ -95,7 +95,7 @@ export default class TypeFacet extends React.PureComponent<Props> {
};

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 (

+ 1
- 1
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx View File

@@ -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;

+ 5
- 3
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRules-test.tsx View File

@@ -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 }
]
}
]

+ 9
- 1
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRules-test.tsx.snap View File

@@ -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}
/>
<ProfileRulesRowOfType
count={68}
@@ -56,6 +56,14 @@ exports[`should render the quality profiles rules with sonarway comparison 1`] =
total={168}
type="CODE_SMELL"
/>
<ProfileRulesRowOfType
count={0}
key="SECURITY_HOTSPOT"
organization="foo"
qprofile="foo"
total={10}
type="SECURITY_HOTSPOT"
/>
</tbody>
</table>
</div>

+ 43
- 0
server/sonar-web/src/main/js/components/icons-components/SecurityHotspotIcon.tsx View File

@@ -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 (
<Icon className={className} size={size}>
<g style={{ fill }}>
<path
d="M10.238 2.416c-0.432-0.895-1.259-1.504-2.202-1.504-1.386 0-2.521 1.318-2.521 2.927v5.481"
fill="none"
stroke={fill}
strokeLinecap="round"
strokeWidth="1.1429"
/>
<path d="M8.537 10.372v1.199h-1.099v-1.199c-0.638-0.228-1.099-0.832-1.099-1.546 0-0.909 0.739-1.649 1.648-1.649s1.649 0.74 1.649 1.649c0 0.715-0.461 1.32-1.099 1.546zM10.734 4.979h-5.494c-1.21 0-2.199 0.989-2.199 2.197v4.395c0 1.21 0.989 2.199 2.199 2.199h5.494c1.209 0 2.197-0.989 2.197-2.199v-4.395c0-1.209-0.989-2.197-2.197-2.197z" />
<path d="M4.030 6.352h6.923v6.923h-6.923z" />
<path
d="M7.504 10.283c0-0.423 0.048-0.757 0.144-1.002s0.251-0.457 0.465-0.637c0.215-0.18 0.377-0.344 0.489-0.493s0.167-0.313 0.167-0.493c0-0.438-0.189-0.656-0.565-0.656-0.174 0-0.314 0.064-0.421 0.191s-0.164 0.3-0.17 0.518h-1.469c0.006-0.58 0.189-1.031 0.548-1.354s0.864-0.485 1.513-0.485c0.646 0 1.147 0.149 1.501 0.447s0.532 0.723 0.532 1.274c0 0.241-0.048 0.459-0.144 0.656s-0.249 0.398-0.46 0.604l-0.5 0.465c-0.142 0.136-0.241 0.276-0.296 0.42s-0.086 0.325-0.091 0.545h-1.243zM7.326 11.604c0-0.215 0.078-0.39 0.233-0.528s0.349-0.207 0.58-0.207c0.232 0 0.425 0.068 0.58 0.207s0.233 0.313 0.233 0.528-0.078 0.39-0.233 0.528c-0.155 0.138-0.349 0.207-0.58 0.207s-0.425-0.068-0.58-0.207c-0.155-0.138-0.233-0.313-0.233-0.528z"
fill="#fff"
/>
</g>
</Icon>
);
}

+ 5
- 0
server/sonar-web/src/main/js/components/ui/IssueTypeIcon.tsx View File

@@ -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 = <CodeSmellIcon size={size} />;
break;
case 'security_hotspot':
case 'security_hotspots':
icon = <SecurityHotspotIcon size={size} />;
break;
}

if (!icon) {

+ 1
- 1
server/sonar-web/src/main/js/helpers/constants.ts View File

@@ -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 = [

+ 3
- 0
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

@@ -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


+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/rules/RuleType.java View File

@@ -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<String> ALL_NAMES = unmodifiableSet(new LinkedHashSet<>(stream(values())
.map(Enum::name)

+ 3
- 3
sonar-plugin-api/src/test/java/org/sonar/api/rules/RuleTypeTest.java View File

@@ -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

+ 1
- 0
sonar-scanner-protocol/src/main/protobuf/scanner_report.proto View File

@@ -204,6 +204,7 @@ enum IssueType {
CODE_SMELL = 0;
BUG = 1;
VULNERABILITY = 2;
SECURITY_HOTSPOT = 3;
}

message IssueLocation {

+ 1
- 0
sonar-ws/src/main/protobuf/ws-commons.proto View File

@@ -118,6 +118,7 @@ enum RuleType {
CODE_SMELL = 1;
BUG = 2;
VULNERABILITY = 3;
SECURITY_HOTSPOT = 4;
}

enum BranchType {

Loading…
Cancel
Save