From bc6df3ab12c13a5da5fbd5105d11e16c08a43639 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Wed, 24 Feb 2016 11:44:01 +0100 Subject: [PATCH] SONAR-7333 add field "type" to issues (db and elasticsearch) --- ...ReportComputeEngineContainerPopulator.java | 2 + .../computation/issue/IssueLifecycle.java | 1 + .../sonar/server/computation/issue/Rule.java | 3 + .../server/computation/issue/RuleImpl.java | 9 +++ .../computation/issue/RuleTypeCopier.java | 42 ++++++++++ .../org/sonar/server/issue/IssueQuery.java | 12 +++ .../sonar/server/issue/IssueQueryService.java | 2 + .../org/sonar/server/issue/IssueService.java | 32 +++----- .../sonar/server/issue/index/IssueDoc.java | 15 ++++ .../sonar/server/issue/index/IssueIndex.java | 6 +- .../issue/index/IssueIndexDefinition.java | 2 + .../issue/index/IssueResultSetIterator.java | 5 +- .../sonar/server/issue/ws/CreateAction.java | 4 +- .../sonar/server/issue/ws/SearchAction.java | 13 ++- .../server/issue/ws/SearchResponseFormat.java | 4 + .../sonar/server/issue/ws/example-search.json | 1 + .../server/computation/issue/DumbRule.java | 11 +++ .../computation/issue/IssueAssignerTest.java | 9 +-- .../computation/issue/RuleTagsCopierTest.java | 6 +- .../computation/issue/RuleTypeCopierTest.java | 59 ++++++++++++++ .../issue/UpdateConflictResolverTest.java | 3 + .../step/PersistIssuesStepTest.java | 5 ++ .../sonar/server/issue/IssueQueryTest.java | 4 + .../sonar/server/issue/IssueStorageTest.java | 6 ++ .../org/sonar/server/issue/IssueTesting.java | 3 + .../server/issue/ServerIssueStorageTest.java | 3 + .../actionplan/ActionPlanServiceTest.java | 4 +- .../index/IssueResultSetIteratorTest.java | 6 ++ .../issue/ws/SearchActionMediumTest.java | 2 +- .../close_issue-result.xml | 1 + .../insert_new_issue-result.xml | 1 + .../step/PersistIssuesStepTest/shared.xml | 1 + .../should_insert_new_issues-result.xml | 1 + ...ld_resolve_conflicts_on_updates-result.xml | 1 + .../should_resolve_conflicts_on_updates.xml | 1 + .../should_update_issues-result.xml | 1 + .../IssueStorageTest/should_update_issues.xml | 1 + .../should_insert_new_issues-result.xml | 1 + .../should_update_issues-result.xml | 1 + .../should_update_issues.xml | 1 + .../issue/index/IssueIndexerTest/index.xml | 1 + .../index/IssueIndexerTest/index_project.xml | 2 + .../extract_directory_path.xml | 12 ++- .../extract_file_path.xml | 12 ++- .../many_projects.xml | 3 + .../IssueResultSetIteratorTest/one_issue.xml | 4 +- .../IssueResultSetIteratorTest/shared.xml | 7 +- .../db/migrate/1106_add_issues_type.rb | 31 +++++++ .../org/sonar/core/issue/DefaultIssue.java | 11 ++- .../sonar/core/issue/DefaultIssueBuilder.java | 8 ++ .../java/org/sonar/core/issue/IssueType.java | 49 ++++++++++++ .../java/org/sonar/db/issue/IssueDto.java | 19 +++++ .../org/sonar/db/version/DatabaseVersion.java | 2 +- .../sonar/db/version/MigrationStepModule.java | 6 +- .../sonar/db/version/TinyIntColumnDef.java | 79 ++++++++++++++++++ .../sonar/db/version/v55/AddIssuesType.java | 48 +++++++++++ .../org/sonar/db/issue/IssueMapper.xml | 14 ++-- .../org/sonar/db/version/rows-h2.sql | 1 + .../org/sonar/db/version/schema-h2.ddl | 1 + .../java/org/sonar/db/issue/IssueDaoTest.java | 2 + .../java/org/sonar/db/issue/IssueDtoTest.java | 3 + .../org/sonar/db/issue/IssueMapperTest.java | 3 + .../db/version/MigrationStepModuleTest.java | 2 +- .../db/version/TinyIntColumnDefTest.java | 80 +++++++++++++++++++ .../db/issue/IssueDaoTest/insert-result.xml | 1 + .../IssueMapperTest/testInsert-result.xml | 1 + .../IssueMapperTest/testUpdate-result.xml | 1 + .../db/issue/IssueMapperTest/testUpdate.xml | 1 + ...eforeSelectedDate_with_conflict-result.xml | 1 + ...updateBeforeSelectedDate_with_conflict.xml | 1 + ...resources_without_last_snapshot-result.xml | 10 ++- ...isable_resources_without_last_snapshot.xml | 12 ++- .../PurgeDaoTest/shouldDeleteProject.xml | 2 + ...should_delete_all_closed_issues-result.xml | 6 +- .../should_delete_all_closed_issues.xml | 15 ++-- ...should_delete_old_closed_issues-result.xml | 9 ++- .../should_delete_old_closed_issues.xml | 12 ++- .../client/issue/IssueFilterParameters.java | 3 +- .../ws/client/issue/SearchWsRequest.java | 11 +++ sonar-ws/src/main/protobuf/ws-issues.proto | 13 +++ 80 files changed, 707 insertions(+), 77 deletions(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleTypeCopier.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/computation/issue/RuleTypeCopierTest.java create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1106_add_issues_type.rb create mode 100644 sonar-core/src/main/java/org/sonar/core/issue/IssueType.java create mode 100644 sonar-db/src/main/java/org/sonar/db/version/TinyIntColumnDef.java create mode 100644 sonar-db/src/main/java/org/sonar/db/version/v55/AddIssuesType.java create mode 100644 sonar-db/src/test/java/org/sonar/db/version/TinyIntColumnDefTest.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java index c35f5b8a634..0ca26aef802 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java @@ -53,6 +53,7 @@ import org.sonar.server.computation.issue.NewDebtAggregator; import org.sonar.server.computation.issue.NewDebtCalculator; import org.sonar.server.computation.issue.RuleRepositoryImpl; import org.sonar.server.computation.issue.RuleTagsCopier; +import org.sonar.server.computation.issue.RuleTypeCopier; import org.sonar.server.computation.issue.ScmAccountToUser; import org.sonar.server.computation.issue.ScmAccountToUserLoader; import org.sonar.server.computation.issue.TrackerBaseInputFactory; @@ -178,6 +179,7 @@ public final class ReportComputeEngineContainerPopulator implements ContainerPop NewDebtAggregator.class, IssueAssigner.class, RuleTagsCopier.class, + RuleTypeCopier.class, IssueCounter.class, // visitors : order is important, measure computers must be executed at the end in order to access to every measures / issues diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueLifecycle.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueLifecycle.java index 33ab0b5f1d2..fb7d388ba29 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueLifecycle.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueLifecycle.java @@ -68,6 +68,7 @@ public class IssueLifecycle { public void mergeExistingOpenIssue(DefaultIssue raw, DefaultIssue base) { raw.setNew(false); raw.setKey(base.key()); + raw.setType(base.type()); raw.setCreationDate(base.creationDate()); raw.setUpdateDate(base.updateDate()); raw.setCloseDate(base.closeDate()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/Rule.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/Rule.java index b8573cb1442..aae0d4073dc 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/Rule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/Rule.java @@ -24,6 +24,7 @@ import javax.annotation.CheckForNull; import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.RuleStatus; import org.sonar.api.server.debt.DebtRemediationFunction; +import org.sonar.core.issue.IssueType; public interface Rule { @@ -35,6 +36,8 @@ public interface Rule { RuleStatus getStatus(); + IssueType getType(); + /** * Get all tags, whatever system or user tags. */ diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleImpl.java index 14cc9118a5d..1cb90d033d9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleImpl.java @@ -28,6 +28,7 @@ import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.RuleStatus; import org.sonar.api.server.debt.DebtRemediationFunction; import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction; +import org.sonar.core.issue.IssueType; import org.sonar.db.rule.RuleDto; import static com.google.common.collect.Sets.union; @@ -41,6 +42,7 @@ public class RuleImpl implements Rule { private final RuleStatus status; private final Set tags; private final DebtRemediationFunction remediationFunction; + private final IssueType type; public RuleImpl(RuleDto dto) { this.id = dto.getId(); @@ -49,6 +51,8 @@ public class RuleImpl implements Rule { this.status = dto.getStatus(); this.tags = union(dto.getSystemTags(), dto.getTags()); this.remediationFunction = effectiveRemediationFunction(dto); + // TODO get rule type + this.type = IssueType.CODE_SMELL; } @Override @@ -81,6 +85,11 @@ public class RuleImpl implements Rule { return remediationFunction; } + @Override + public IssueType getType() { + return type; + } + @Override public boolean equals(@Nullable Object o) { if (this == o) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleTypeCopier.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleTypeCopier.java new file mode 100644 index 00000000000..3c902c856d9 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleTypeCopier.java @@ -0,0 +1,42 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +package org.sonar.server.computation.issue; + +import org.sonar.core.issue.DefaultIssue; +import org.sonar.server.computation.component.Component; + +import static com.google.common.collect.Sets.union; + +public class RuleTypeCopier extends IssueVisitor { + + private final RuleRepository ruleRepository; + + public RuleTypeCopier(RuleRepository ruleRepository) { + this.ruleRepository = ruleRepository; + } + + @Override + public void onIssue(Component component, DefaultIssue issue) { + if (issue.type()==null) { + Rule rule = ruleRepository.getByKey(issue.ruleKey()); + issue.setType(rule.getType()); + } + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQuery.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQuery.java index d3e45a7bbae..9c75dbf5640 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQuery.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQuery.java @@ -72,6 +72,7 @@ public class IssueQuery { private final Collection authors; private final Collection languages; private final Collection tags; + private final Collection types; private final Boolean onComponentOnly; private final Boolean assigned; private final Boolean planned; @@ -108,6 +109,7 @@ public class IssueQuery { this.authors = defaultCollection(builder.authors); this.languages = defaultCollection(builder.languages); this.tags = defaultCollection(builder.tags); + this.types = defaultCollection(builder.types); this.onComponentOnly = builder.onComponentOnly; this.assigned = builder.assigned; this.planned = builder.planned; @@ -197,6 +199,10 @@ public class IssueQuery { return tags; } + public Collection types() { + return types; + } + @CheckForNull public Boolean onComponentOnly() { return onComponentOnly; @@ -303,6 +309,7 @@ public class IssueQuery { private Collection authors; private Collection languages; private Collection tags; + private Collection types; private Boolean onComponentOnly = false; private Boolean assigned = null; private Boolean planned = null; @@ -414,6 +421,11 @@ public class IssueQuery { return this; } + public Builder types(@Nullable Collection t) { + this.types = t; + return this; + } + /** * If true, it will return only issues on the passed component(s) * If false, it will return all issues on the passed component(s) and their descendants diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java index 443b139303a..2cc8d64f234 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java @@ -98,6 +98,7 @@ public class IssueQueryService { .assignees(buildAssignees(RubyUtils.toStrings(params.get(IssueFilterParameters.ASSIGNEES)))) .languages(RubyUtils.toStrings(params.get(IssueFilterParameters.LANGUAGES))) .tags(RubyUtils.toStrings(params.get(IssueFilterParameters.TAGS))) + .types(RubyUtils.toStrings(params.get(IssueFilterParameters.TYPES))) .assigned(RubyUtils.toBoolean(params.get(IssueFilterParameters.ASSIGNED))) .planned(RubyUtils.toBoolean(params.get(IssueFilterParameters.PLANNED))) .hideRules(RubyUtils.toBoolean(params.get(IssueFilterParameters.HIDE_RULES))) @@ -171,6 +172,7 @@ public class IssueQueryService { .assignees(buildAssignees(request.getAssignees())) .languages(request.getLanguages()) .tags(request.getTags()) + .types(request.getTypes()) .assigned(request.getAssigned()) .planned(request.getPlanned()) .createdAt(parseAsDateTime(request.getCreatedAt())) diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java index 09c2c041d2c..46109f83936 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java @@ -44,6 +44,7 @@ import org.sonar.api.web.UserRole; import org.sonar.core.issue.DefaultIssue; import org.sonar.core.issue.DefaultIssueBuilder; import org.sonar.core.issue.IssueChangeContext; +import org.sonar.core.issue.IssueType; import org.sonar.server.issue.workflow.IssueWorkflow; import org.sonar.server.issue.workflow.Transition; import org.sonar.db.DbClient; @@ -142,8 +143,8 @@ public class IssueService { return allowedTransitions; } - public Issue doTransition(String issueKey, String transitionKey) { - verifyLoggedIn(); + public void doTransition(String issueKey, String transitionKey) { + userSession.checkLoggedIn(); DbSession session = dbClient.openSession(false); try { @@ -153,7 +154,6 @@ public class IssueService { if (workflow.doTransition(defaultIssue, transitionKey, context)) { saveIssue(session, defaultIssue, context, null); } - return defaultIssue; } finally { session.close(); @@ -170,8 +170,8 @@ public class IssueService { } } - public Issue assign(String issueKey, @Nullable String assignee) { - verifyLoggedIn(); + public void assign(String issueKey, @Nullable String assignee) { + userSession.checkLoggedIn(); DbSession session = dbClient.openSession(false); try { @@ -187,15 +187,14 @@ public class IssueService { if (issueUpdater.assign(issue, user, context)) { saveIssue(session, issue, context, null); } - return issue; } finally { session.close(); } } - public Issue plan(String issueKey, @Nullable String actionPlanKey) { - verifyLoggedIn(); + public void plan(String issueKey, @Nullable String actionPlanKey) { + userSession.checkLoggedIn(); DbSession session = dbClient.openSession(false); try { @@ -212,15 +211,14 @@ public class IssueService { if (issueUpdater.plan(issue, actionPlan, context)) { saveIssue(session, issue, context, null); } - return issue; } finally { session.close(); } } - public Issue setSeverity(String issueKey, String severity) { - verifyLoggedIn(); + public void setSeverity(String issueKey, String severity) { + userSession.checkLoggedIn(); DbSession session = dbClient.openSession(false); try { @@ -231,14 +229,13 @@ public class IssueService { if (issueUpdater.setManualSeverity(issue, severity, context)) { saveIssue(session, issue, context, null); } - return issue; } finally { session.close(); } } - public DefaultIssue createManualIssue(String componentKey, RuleKey ruleKey, @Nullable Integer line, @Nullable String message, @Nullable String severity) { - verifyLoggedIn(); + public Issue createManualIssue(String componentKey, RuleKey ruleKey, @Nullable Integer line, @Nullable String message, @Nullable String severity) { + userSession.checkLoggedIn(); DbSession dbSession = dbClient.openSession(false); try { @@ -260,6 +257,7 @@ public class IssueService { DefaultIssue issue = new DefaultIssueBuilder() .componentKey(component.getKey()) + // TODO use rule type: type(rule.type()) .projectKey(project.getKey()) .line(line) .message(!Strings.isNullOrEmpty(message) ? message : rule.getName()) @@ -318,10 +316,6 @@ public class IssueService { return issueIndex.search(query, options); } - private void verifyLoggedIn() { - userSession.checkLoggedIn(); - } - /** * Search for all tags, whatever issue resolution or user access rights */ @@ -340,7 +334,7 @@ public class IssueService { } public Collection setTags(String issueKey, Collection tags) { - verifyLoggedIn(); + userSession.checkLoggedIn(); DbSession session = dbClient.openSession(false); try { diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueDoc.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueDoc.java index 3e6d4829242..bc98b0cfd80 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueDoc.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueDoc.java @@ -34,6 +34,7 @@ import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.Severity; import org.sonar.api.utils.Duration; import org.sonar.api.utils.KeyValueFormat; +import org.sonar.core.issue.IssueType; import org.sonar.server.search.BaseDoc; public class IssueDoc extends BaseDoc implements Issue { @@ -195,6 +196,15 @@ public class IssueDoc extends BaseDoc implements Issue { return getNullableField(IssueIndexDefinition.FIELD_ISSUE_ACTION_PLAN); } + @CheckForNull + public IssueType type() { + String type = getNullableField(IssueIndexDefinition.FIELD_ISSUE_TYPE); + if (type != null) { + return IssueType.valueOf(type); + } + return null; + } + @Override public List comments() { throw new IllegalStateException("Comments are not availables in index"); @@ -372,4 +382,9 @@ public class IssueDoc extends BaseDoc implements Issue { setField(IssueIndexDefinition.FIELD_ISSUE_TAGS, tags); return this; } + + public IssueDoc setType(IssueType type) { + setField(IssueIndexDefinition.FIELD_ISSUE_TYPE, type.toString()); + return this; + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java index 477cec3239c..ef3be38d935 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java @@ -109,6 +109,7 @@ public class IssueIndex extends BaseIndex { IssueFilterParameters.DIRECTORIES, IssueFilterParameters.LANGUAGES, IssueFilterParameters.TAGS, + IssueFilterParameters.TYPES, IssueFilterParameters.CREATED_AT); // TODO to be documented @@ -265,6 +266,7 @@ public class IssueIndex extends BaseIndex { filters.put(IssueIndexDefinition.FIELD_ISSUE_LANGUAGE, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_LANGUAGE, query.languages())); filters.put(IssueIndexDefinition.FIELD_ISSUE_TAGS, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_TAGS, query.tags())); + filters.put(IssueIndexDefinition.FIELD_ISSUE_TYPE, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_TYPE, query.types())); filters.put(IssueIndexDefinition.FIELD_ISSUE_RESOLUTION, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_RESOLUTION, query.resolutions())); filters.put(IssueIndexDefinition.FIELD_ISSUE_REPORTER, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_REPORTER, query.reporters())); filters.put(IssueIndexDefinition.FIELD_ISSUE_AUTHOR_LOGIN, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_AUTHOR_LOGIN, query.authors())); @@ -404,7 +406,9 @@ public class IssueIndex extends BaseIndex { if (options.getFacets().contains(IssueFilterParameters.TAGS)) { esSearch.addAggregation(stickyFacetBuilder.buildStickyFacet(IssueIndexDefinition.FIELD_ISSUE_TAGS, IssueFilterParameters.TAGS, query.tags().toArray())); } - + if (options.getFacets().contains(IssueFilterParameters.TYPES)) { + esSearch.addAggregation(stickyFacetBuilder.buildStickyFacet(IssueIndexDefinition.FIELD_ISSUE_TYPE, IssueFilterParameters.TYPES, query.types().toArray())); + } if (options.getFacets().contains(IssueFilterParameters.RESOLUTIONS)) { esSearch.addAggregation(createResolutionFacet(query, filters, esQuery)); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java index 271ad04e7f3..1e019ce9a92 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java @@ -76,6 +76,7 @@ public class IssueIndexDefinition implements IndexDefinition { public static final String FIELD_ISSUE_STATUS = "status"; public static final String FIELD_ISSUE_CHECKSUM = "checksum"; public static final String FIELD_ISSUE_TAGS = "tags"; + public static final String FIELD_ISSUE_TYPE = "type"; /** * Technical date */ @@ -134,5 +135,6 @@ public class IssueIndexDefinition implements IndexDefinition { issueMapping.stringFieldBuilder(FIELD_ISSUE_STATUS).enableSorting().build(); issueMapping.stringFieldBuilder(FIELD_ISSUE_TAGS).build(); issueMapping.createDateTimeField(FIELD_ISSUE_TECHNICAL_UPDATED_AT); + issueMapping.stringFieldBuilder(FIELD_ISSUE_TYPE).build(); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueResultSetIterator.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueResultSetIterator.java index 6283b66dea2..37857d1264f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueResultSetIterator.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueResultSetIterator.java @@ -33,6 +33,7 @@ import javax.annotation.Nullable; import org.apache.commons.lang.StringUtils; import org.sonar.api.resources.Scopes; import org.sonar.api.rule.RuleKey; +import org.sonar.core.issue.IssueType; import org.sonar.db.DatabaseUtils; import org.sonar.db.DbClient; import org.sonar.db.DbSession; @@ -80,7 +81,8 @@ class IssueResultSetIterator extends ResultSetIterator { "p.module_uuid_path", "p.path", "p.scope", - "i.tags" + "i.tags", + "i.issue_type" }; private static final String SQL_ALL = "select " + StringUtils.join(FIELDS, ",") + " from issues i " + @@ -191,6 +193,7 @@ class IssueResultSetIterator extends ResultSetIterator { doc.setDirectoryPath(extractDirPath(doc.filePath(), scope)); String tags = rs.getString(28); doc.setTags(ImmutableList.copyOf(TAGS_SPLITTER.split(tags == null ? "" : tags))); + doc.setType(IssueType.valueOf(rs.getInt(29))); return doc; } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/CreateAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/CreateAction.java index 1ef04aa330d..fb3bf745ddc 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/CreateAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/CreateAction.java @@ -19,12 +19,12 @@ */ package org.sonar.server.issue.ws; +import org.sonar.api.issue.Issue; import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.Severity; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; -import org.sonar.core.issue.DefaultIssue; import org.sonar.server.issue.IssueService; import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; @@ -76,7 +76,7 @@ public class CreateAction implements IssuesWsAction { String componentKey = request.mandatoryParam("component"); RuleKey ruleKey = RuleKey.parse(request.mandatoryParam("rule")); - DefaultIssue issue = issueService.createManualIssue(componentKey, ruleKey, + Issue issue = issueService.createManualIssue(componentKey, ruleKey, request.paramAsInt("line"), request.param("message"), request.param("severity")); diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java index b3fb5a407a7..f4fa7f5b4b0 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java @@ -20,6 +20,7 @@ package org.sonar.server.issue.ws; import com.google.common.base.Function; +import com.google.common.collect.FluentIterable; import com.google.common.collect.Lists; import com.google.common.io.Resources; import java.util.Collection; @@ -36,6 +37,7 @@ import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService.Param; import org.sonar.api.utils.Paging; +import org.sonar.core.issue.IssueType; import org.sonar.server.rule.RuleKeyFunctions; import org.sonar.server.es.Facets; import org.sonar.server.es.SearchOptions; @@ -52,6 +54,7 @@ import org.sonarqube.ws.client.issue.SearchWsRequest; import static com.google.common.collect.FluentIterable.from; import static com.google.common.collect.Iterables.concat; +import static java.lang.String.format; import static java.util.Collections.singletonList; import static org.sonar.api.utils.Paging.forPageIndex; import static org.sonar.server.es.SearchOptions.MAX_LIMIT; @@ -90,6 +93,7 @@ import static org.sonarqube.ws.client.issue.IssueFilterParameters.RULES; import static org.sonarqube.ws.client.issue.IssueFilterParameters.SEVERITIES; import static org.sonarqube.ws.client.issue.IssueFilterParameters.STATUSES; import static org.sonarqube.ws.client.issue.IssueFilterParameters.TAGS; +import static org.sonarqube.ws.client.issue.IssueFilterParameters.TYPES; public class SearchAction implements IssuesWsAction { @@ -159,6 +163,11 @@ public class SearchAction implements IssuesWsAction { action.createParam(IssueFilterParameters.TAGS) .setDescription("Comma-separated list of tags.") .setExampleValue("security,convention"); + action.createParam(IssueFilterParameters.TYPES) + .setDescription("Comma-separated list of types.") + .setSince("5.5") + .setPossibleValues(IssueType.values()) + .setExampleValue(format("%s,%s", IssueType.CODE_SMELL, IssueType.BUG)); action.createParam(ACTION_PLANS) .setDescription("Comma-separated list of action plan keys (not names)") .setExampleValue("3f19de90-1521-4482-a737-a311758ff513"); @@ -338,6 +347,7 @@ public class SearchAction implements IssuesWsAction { addMandatoryValuesToFacet(facets, IssueFilterParameters.RULES, request.getRules()); addMandatoryValuesToFacet(facets, IssueFilterParameters.LANGUAGES, request.getLanguages()); addMandatoryValuesToFacet(facets, IssueFilterParameters.TAGS, request.getTags()); + addMandatoryValuesToFacet(facets, IssueFilterParameters.TYPES, request.getTypes()); List actionPlans = Lists.newArrayList(""); List actionPlansFromRequest = request.getActionPlans(); if (actionPlansFromRequest != null) { @@ -443,7 +453,8 @@ public class SearchAction implements IssuesWsAction { .setSort(request.param(Param.SORT)) .setSeverities(request.paramAsStrings(SEVERITIES)) .setStatuses(request.paramAsStrings(STATUSES)) - .setTags(request.paramAsStrings(TAGS)); + .setTags(request.paramAsStrings(TAGS)) + .setTypes(request.paramAsStrings(TYPES)); } private enum IssueDocToKey implements Function { diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java index 246fe4eb118..e828f36db1b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java @@ -145,6 +145,10 @@ public class SearchResponseFormat { private void formatIssue(Issues.Issue.Builder issueBuilder, IssueDto dto, SearchResponseData data) { issueBuilder.setKey(dto.getKey()); + Issues.IssueType type = Issues.IssueType.valueOf(dto.getType()); + if (type != null) { + issueBuilder.setType(type); + } ComponentDto component = data.getComponentByUuid(dto.getComponentUuid()); issueBuilder.setComponent(dto.getComponentKey()); // Only used for the compatibility with the Java WS Client <= 4.4 used by Eclipse diff --git a/server/sonar-server/src/main/resources/org/sonar/server/issue/ws/example-search.json b/server/sonar-server/src/main/resources/org/sonar/server/issue/ws/example-search.json index b02142ae1e2..61908702dd9 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/issue/ws/example-search.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/issue/ws/example-search.json @@ -26,6 +26,7 @@ "creationDate": "2013-05-13T17:55:39+0200", "updateDate": "2013-05-13T17:55:39+0200", "tags": ["bug"], + "type": "RELIABILITY", "comments": [ { "key": "7d7c56f5-7b5a-41b9-87f8-36fa70caa5ba", diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/DumbRule.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/DumbRule.java index 55465a81e2e..e73f8486acc 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/DumbRule.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/DumbRule.java @@ -25,6 +25,7 @@ import javax.annotation.Nullable; import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.RuleStatus; import org.sonar.api.server.debt.DebtRemediationFunction; +import org.sonar.core.issue.IssueType; import static java.util.Objects.requireNonNull; @@ -33,6 +34,7 @@ public class DumbRule implements Rule { private RuleKey key; private String name; private RuleStatus status = RuleStatus.READY; + private IssueType type = IssueType.CODE_SMELL; private Set tags = new HashSet<>(); private DebtRemediationFunction function; @@ -66,6 +68,11 @@ public class DumbRule implements Rule { return requireNonNull(tags); } + @Override + public IssueType getType() { + return type; + } + @Override public DebtRemediationFunction getRemediationFunction() { return function; @@ -94,4 +101,8 @@ public class DumbRule implements Rule { public void setTags(Set tags) { this.tags = tags; } + + public void setType(IssueType type) { + this.type = type; + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/IssueAssignerTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/IssueAssignerTest.java index 5a929c0d149..a390f5e0c37 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/IssueAssignerTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/IssueAssignerTest.java @@ -23,6 +23,7 @@ import org.junit.Test; import org.sonar.api.utils.log.LogTester; import org.sonar.api.utils.log.LoggerLevel; import org.sonar.core.issue.DefaultIssue; +import org.sonar.core.issue.IssueType; import org.sonar.server.issue.IssueUpdater; import org.sonar.server.computation.analysis.AnalysisMetadataHolderRule; import org.sonar.server.computation.component.Component; @@ -175,16 +176,12 @@ public class IssueAssignerTest { @Test public void display_warning_when_line_is_above_max_size() throws Exception { setSingleChangeset("john", 123456789L, "rev-1"); - DefaultIssue issue = new DefaultIssue().setLine(2); + DefaultIssue issue = new DefaultIssue().setLine(2).setType(IssueType.VULNERABILITY); underTest.onIssue(FILE, issue); assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly( - "No SCM info has been found for issue DefaultIssue[key=,componentUuid=,componentKey=,moduleUuid=,moduleUuidPath=," + - "projectUuid=,projectKey=,ruleKey=,language=,severity=,manualSeverity=false,message=,line=2,effortToFix=,debt=," + - "status=,resolution=,reporter=,assignee=,checksum=,attributes=,authorLogin=,actionPlanKey=,comments=,tags=,l" + - "ocations=,creationDate=,updateDate=,closeDate=,currentChange=,changes=,isNew=true,beingClosed=false,onDisabledRule=false," + - "isChanged=false,sendNotifications=false,selectedAt=]"); + "No SCM info has been found for issue DefaultIssue[key=,type=VULNERABILITY,componentUuid=,componentKey=,moduleUuid=,moduleUuidPath=,projectUuid=,projectKey=,ruleKey=,language=,severity=,manualSeverity=false,message=,line=2,effortToFix=,debt=,status=,resolution=,reporter=,assignee=,checksum=,attributes=,authorLogin=,actionPlanKey=,comments=,tags=,locations=,creationDate=,updateDate=,closeDate=,currentChange=,changes=,isNew=true,beingClosed=false,onDisabledRule=false,isChanged=false,sendNotifications=false,selectedAt=]"); } private void setSingleChangeset(String author, Long date, String revision) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/RuleTagsCopierTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/RuleTagsCopierTest.java index 1446354cc13..1c75cc6f91c 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/RuleTagsCopierTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/RuleTagsCopierTest.java @@ -41,7 +41,7 @@ public class RuleTagsCopierTest { RuleTagsCopier underTest = new RuleTagsCopier(ruleRepository); @Test - public void copy_tags_if_new_rule() { + public void copy_tags_if_new_issue() { rule.setTags(Sets.newHashSet("bug", "performance")); issue.setNew(true); @@ -51,7 +51,7 @@ public class RuleTagsCopierTest { } @Test - public void do_not_copy_tags_if_existing_rule() { + public void do_not_copy_tags_if_existing_issue() { rule.setTags(Sets.newHashSet("bug", "performance")); issue.setNew(false).setTags(asList("misra")); @@ -61,7 +61,7 @@ public class RuleTagsCopierTest { } @Test - public void do_not_copy_tags_if_existing_rule_without_tags() { + public void do_not_copy_tags_if_existing_issue_without_tags() { rule.setTags(Sets.newHashSet("bug", "performance")); issue.setNew(false).setTags(Collections.emptyList()); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/RuleTypeCopierTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/RuleTypeCopierTest.java new file mode 100644 index 00000000000..e81f28bed30 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/RuleTypeCopierTest.java @@ -0,0 +1,59 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +package org.sonar.server.computation.issue; + +import org.junit.Test; +import org.sonar.core.issue.DefaultIssue; +import org.sonar.core.issue.IssueType; +import org.sonar.server.computation.component.Component; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.sonar.db.rule.RuleTesting.XOO_X1; + +public class RuleTypeCopierTest { + + DumbRule rule = new DumbRule(XOO_X1); + + @org.junit.Rule + public RuleRepositoryRule ruleRepository = new RuleRepositoryRule().add(rule); + + DefaultIssue issue = new DefaultIssue().setRuleKey(rule.getKey()); + RuleTypeCopier underTest = new RuleTypeCopier(ruleRepository); + + @Test + public void copy_rule_type_if_missing() { + rule.setType(IssueType.BUG); + + underTest.onIssue(mock(Component.class), issue); + + assertThat(issue.type()).isEqualTo(IssueType.BUG); + } + + @Test + public void do_not_copy_type_if_present() { + rule.setType(IssueType.BUG); + issue.setType(IssueType.VULNERABILITY); + + underTest.onIssue(mock(Component.class), issue); + + assertThat(issue.type()).isEqualTo(IssueType.VULNERABILITY); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/UpdateConflictResolverTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/UpdateConflictResolverTest.java index e0d40c64aa4..4af8c294a39 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/UpdateConflictResolverTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/UpdateConflictResolverTest.java @@ -26,6 +26,7 @@ import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.Severity; import org.sonar.api.utils.DateUtils; import org.sonar.core.issue.DefaultIssue; +import org.sonar.core.issue.IssueType; import org.sonar.db.issue.IssueDto; import org.sonar.db.issue.IssueMapper; @@ -40,6 +41,7 @@ public class UpdateConflictResolverTest { public void should_reload_issue_and_resolve_conflict() { DefaultIssue issue = new DefaultIssue() .setKey("ABCDE") + .setType(IssueType.CODE_SMELL) .setRuleKey(RuleKey.of("squid", "AvoidCycles")) .setComponentKey("struts:org.apache.struts.Action") .setNew(false) @@ -50,6 +52,7 @@ public class UpdateConflictResolverTest { when(mapper.selectByKey("ABCDE")).thenReturn( new IssueDto() .setKee("ABCDE") + .setType(IssueType.CODE_SMELL) .setRuleId(10) .setRuleKey("squid", "AvoidCycles") .setComponentKey("struts:org.apache.struts.Action") diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistIssuesStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistIssuesStepTest.java index 5ae798b9fd4..85adce10b33 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistIssuesStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistIssuesStepTest.java @@ -32,6 +32,7 @@ import org.sonar.batch.protocol.output.BatchReport; import org.sonar.core.issue.DefaultIssue; import org.sonar.core.issue.DefaultIssueComment; import org.sonar.core.issue.FieldDiffs; +import org.sonar.core.issue.IssueType; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; @@ -93,6 +94,7 @@ public class PersistIssuesStepTest extends BaseStepTest { issueCache.newAppender().append(new DefaultIssue() .setKey("ISSUE") + .setType(IssueType.CODE_SMELL) .setRuleKey(RuleKey.of("xoo", "S01")) .setComponentUuid("COMPONENT") .setProjectUuid("PROJECT") @@ -112,6 +114,7 @@ public class PersistIssuesStepTest extends BaseStepTest { issueCache.newAppender().append(new DefaultIssue() .setKey("ISSUE") + .setType(IssueType.CODE_SMELL) .setRuleKey(RuleKey.of("xoo", "S01")) .setComponentUuid("COMPONENT") .setProjectUuid("PROJECT") @@ -134,6 +137,7 @@ public class PersistIssuesStepTest extends BaseStepTest { issueCache.newAppender().append(new DefaultIssue() .setKey("ISSUE") + .setType(IssueType.CODE_SMELL) .setRuleKey(RuleKey.of("xoo", "S01")) .setComponentUuid("COMPONENT") .setProjectUuid("PROJECT") @@ -162,6 +166,7 @@ public class PersistIssuesStepTest extends BaseStepTest { issueCache.newAppender().append(new DefaultIssue() .setKey("ISSUE") + .setType(IssueType.CODE_SMELL) .setRuleKey(RuleKey.of("xoo", "S01")) .setComponentUuid("COMPONENT") .setProjectUuid("PROJECT") diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryTest.java index 7f802a5f4b6..f033679ff74 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryTest.java @@ -50,6 +50,7 @@ public class IssueQueryTest { .assignees(newArrayList("gargantua")) .languages(newArrayList("xoo")) .tags(newArrayList("tag1", "tag2")) + .types(newArrayList("RELIABILITY", "SECURITY")) .assigned(true) .hideRules(true) .createdAfter(new Date()) @@ -70,6 +71,7 @@ public class IssueQueryTest { assertThat(query.assignees()).containsOnly("gargantua"); assertThat(query.languages()).containsOnly("xoo"); assertThat(query.tags()).containsOnly("tag1", "tag2"); + assertThat(query.types()).containsOnly("RELIABILITY", "SECURITY"); assertThat(query.assigned()).isTrue(); assertThat(query.hideRules()).isTrue(); assertThat(query.rules()).containsOnly(RuleKey.of("squid", "AvoidCycle")); @@ -124,6 +126,7 @@ public class IssueQueryTest { .severities(null) .languages(null) .tags(null) + .types(null) .build(); assertThat(query.issueKeys()).isEmpty(); assertThat(query.componentUuids()).isEmpty(); @@ -137,6 +140,7 @@ public class IssueQueryTest { assertThat(query.severities()).isEmpty(); assertThat(query.languages()).isEmpty(); assertThat(query.tags()).isEmpty(); + assertThat(query.types()).isEmpty(); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueStorageTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueStorageTest.java index f7c62ea5e17..c3c088b4fc1 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueStorageTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueStorageTest.java @@ -33,6 +33,7 @@ import org.sonar.api.utils.System2; import org.sonar.core.issue.DefaultIssue; import org.sonar.core.issue.DefaultIssueComment; import org.sonar.core.issue.IssueChangeContext; +import org.sonar.core.issue.IssueType; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; @@ -62,6 +63,7 @@ public class IssueStorageTest { Date date = DateUtils.parseDateTime("2013-05-18T12:00:00+0000"); DefaultIssue issue = new DefaultIssue() .setKey("ABCDE") + .setType(IssueType.BUG) .setNew(true) .setRuleKey(RuleKey.of("squid", "AvoidCycle")) @@ -98,6 +100,7 @@ public class IssueStorageTest { Date date = DateUtils.parseDateTime("2013-05-18T12:00:00+0000"); DefaultIssue issue = new DefaultIssue() .setKey("ABCDE") + .setType(IssueType.BUG) .setNew(true) .setRuleKey(RuleKey.of("squid", "AvoidCycle")) @@ -137,6 +140,7 @@ public class IssueStorageTest { Date date = DateUtils.parseDateTime("2013-05-18T12:00:00+0000"); DefaultIssue issue = new DefaultIssue() .setKey("ABCDE") + .setType(IssueType.BUG) .setNew(true) .setRuleKey(RuleKey.of("squid", "AvoidCycle")) @@ -176,6 +180,7 @@ public class IssueStorageTest { Date date = DateUtils.parseDateTime("2013-05-18T12:00:00+0000"); DefaultIssue issue = new DefaultIssue() .setKey("ABCDE") + .setType(IssueType.BUG) .setNew(false) .setChanged(true) @@ -222,6 +227,7 @@ public class IssueStorageTest { Date date = DateUtils.parseDateTime("2013-05-18T12:00:00+0000"); DefaultIssue issue = new DefaultIssue() .setKey("ABCDE") + .setType(IssueType.BUG) .setNew(false) .setChanged(true) diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueTesting.java b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueTesting.java index d015d8b2e2f..8af8c688263 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueTesting.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueTesting.java @@ -24,6 +24,7 @@ import org.sonar.api.issue.Issue; import org.sonar.api.resources.Scopes; import org.sonar.api.rule.Severity; import org.sonar.api.utils.DateUtils; +import org.sonar.core.issue.IssueType; import org.sonar.core.util.Uuids; import org.sonar.db.component.ComponentDto; import org.sonar.db.issue.IssueDto; @@ -45,6 +46,7 @@ public class IssueTesting { return new IssueDto() .setKee(Uuids.create()) .setRule(rule) + .setType(IssueType.CODE_SMELL) .setComponent(file) .setProject(project) .setStatus(Issue.STATUS_OPEN) @@ -61,6 +63,7 @@ public class IssueTesting { IssueDoc doc = new IssueDoc(Maps.newHashMap()); doc.setKey("ABC"); doc.setRuleKey(RuleTesting.XOO_X1.toString()); + doc.setType(IssueType.CODE_SMELL); doc.setActionPlanKey(null); doc.setReporter(null); doc.setAssignee("steve"); diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ServerIssueStorageTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ServerIssueStorageTest.java index e1714bc3c3f..0e9d8841337 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ServerIssueStorageTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ServerIssueStorageTest.java @@ -34,6 +34,7 @@ import org.sonar.api.utils.System2; import org.sonar.core.issue.DefaultIssue; import org.sonar.core.issue.DefaultIssueComment; import org.sonar.core.issue.IssueChangeContext; +import org.sonar.core.issue.IssueType; import org.sonar.db.DbClient; import org.sonar.db.DbTester; import org.sonar.server.issue.index.IssueIndexer; @@ -89,6 +90,7 @@ public class ServerIssueStorageTest { Date date = DateUtils.parseDateTime("2013-05-18T12:00:00+0000"); DefaultIssue issue = new DefaultIssue() .setKey("ABCDE") + .setType(IssueType.BUG) .setNew(true) .setRuleKey(RuleKey.of("squid", "AvoidCycle")) @@ -126,6 +128,7 @@ public class ServerIssueStorageTest { Date date = DateUtils.parseDateTime("2013-05-18T12:00:00+0000"); DefaultIssue issue = new DefaultIssue() .setKey("ABCDE") + .setType(IssueType.BUG) .setNew(false) .setChanged(true) diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/actionplan/ActionPlanServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/actionplan/ActionPlanServiceTest.java index 3076cf36686..e4acd7aa6ac 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/actionplan/ActionPlanServiceTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/actionplan/ActionPlanServiceTest.java @@ -34,6 +34,8 @@ import org.sonar.core.issue.ActionPlanStats; import org.sonar.core.issue.DefaultActionPlan; import org.sonar.core.issue.DefaultIssue; import org.sonar.core.issue.IssueChangeContext; +import org.sonar.core.issue.IssueType; +import org.sonar.server.issue.IssueTesting; import org.sonar.server.issue.IssueUpdater; import org.sonar.db.DbClient; import org.sonar.db.DbSession; @@ -161,7 +163,7 @@ public class ActionPlanServiceTest { when(actionPlanDao.selectByKey("ABCD")).thenReturn(new ActionPlanDto().setKey("ABCD").setProjectKey_unit_test_only(PROJECT_KEY)); when(resourceDao.selectResource(any(ResourceQuery.class))).thenReturn(new ResourceDto().setKey(PROJECT_KEY).setId(1l)); - IssueDto issueDto = new IssueDto().setId(100L).setStatus(Issue.STATUS_OPEN).setRuleKey("squid", "s100").setIssueCreationDate(new Date()); + IssueDto issueDto = new IssueDto().setId(100L).setStatus(Issue.STATUS_OPEN).setRuleKey("squid", "s100").setIssueCreationDate(new Date()).setType(IssueType.BUG); when(issueDao.selectByActionPlan(session, "ABCD")).thenReturn(newArrayList(issueDto)); when(issueUpdater.plan(any(DefaultIssue.class), eq((ActionPlan) null), any(IssueChangeContext.class))).thenReturn(true); diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueResultSetIteratorTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueResultSetIteratorTest.java index 4ed283308bf..89799c9ff5d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueResultSetIteratorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueResultSetIteratorTest.java @@ -31,6 +31,7 @@ import org.sonar.api.rule.RuleKey; import org.sonar.api.utils.System2; import org.sonar.db.DbTester; import org.sonar.test.DbTests; +import org.sonarqube.ws.Issues; import static org.assertj.core.api.Assertions.assertThat; @@ -86,6 +87,7 @@ public class IssueResultSetIteratorTest { assertThat(issue.effortToFix()).isEqualTo(2d); assertThat(issue.actionPlanKey()).isEqualTo("PLAN1"); assertThat(issue.attribute("JIRA")).isEqualTo("http://jira.com"); + assertThat(issue.type().getDbConstant()).isEqualTo(2); } @Test @@ -108,6 +110,7 @@ public class IssueResultSetIteratorTest { assertThat(issue.filePath()).isEqualTo("src/main/java/Action.java"); assertThat(issue.tags()).containsOnly("tag1", "tag2", "tag3"); assertThat(issue.debt().toMinutes()).isGreaterThan(0L); + assertThat(issue.type().getDbConstant()).isEqualTo(1); issue = issuesByKey.get("BCD"); assertThat(issue.key()).isEqualTo("BCD"); @@ -120,6 +123,7 @@ public class IssueResultSetIteratorTest { assertThat(issue.filePath()).isNull(); assertThat(issue.tags()).containsOnly("tag1", "tag2", "tag3"); assertThat(issue.debt().toMinutes()).isGreaterThan(0L); + assertThat(issue.type().getDbConstant()).isEqualTo(2); issue = issuesByKey.get("DEF"); assertThat(issue.key()).isEqualTo("DEF"); @@ -132,6 +136,7 @@ public class IssueResultSetIteratorTest { assertThat(issue.filePath()).isEqualTo("src/main/java/Action.java"); assertThat(issue.tags()).isEmpty(); assertThat(issue.debt().toMinutes()).isGreaterThan(0L); + assertThat(issue.type().getDbConstant()).isEqualTo(1); issue = issuesByKey.get("EFG"); assertThat(issue.key()).isEqualTo("EFG"); @@ -144,6 +149,7 @@ public class IssueResultSetIteratorTest { assertThat(issue.filePath()).isEqualTo("src/main/java"); assertThat(issue.tags()).isEmpty(); assertThat(issue.debt().toMinutes()).isGreaterThan(0L); + assertThat(issue.type().getDbConstant()).isEqualTo(1); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java index caa55c7845e..69295b395da 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java @@ -95,7 +95,7 @@ public class SearchActionMediumTest { assertThat(show.isPost()).isFalse(); assertThat(show.isInternal()).isFalse(); assertThat(show.responseExampleAsString()).isNotEmpty(); - assertThat(show.params()).hasSize(37); + assertThat(show.params()).hasSize(38); } @Test diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/close_issue-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/close_issue-result.xml index b2765988177..f99404e0b84 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/close_issue-result.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/close_issue-result.xml @@ -27,6 +27,7 @@ created_at="1300000000000" updated_at="1400000000000" locations="[null]" + issue_type="1" /> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/insert_new_issue-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/insert_new_issue-result.xml index d114f261b49..991c8769011 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/insert_new_issue-result.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/insert_new_issue-result.xml @@ -27,6 +27,7 @@ created_at="1400000000000" updated_at="1400000000000" locations="[null]" + issue_type="1" /> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/shared.xml index 263f957b384..a06f7a729e0 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/shared.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/shared.xml @@ -39,6 +39,7 @@ created_at="1300000000000" updated_at="1300000000000" locations="[null]" + issue_type="[null]" /> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_insert_new_issues-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_insert_new_issues-result.xml index 3db758bb13b..47a64e727e1 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_insert_new_issues-result.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_insert_new_issues-result.xml @@ -20,6 +20,7 @@ issue_update_date="1368878400000" issue_close_date="1368878400000" locations="[null]" + issue_type="2" /> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_resolve_conflicts_on_updates.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_resolve_conflicts_on_updates.xml index 76ef67e4569..e1b2e8f4cf1 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_resolve_conflicts_on_updates.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_resolve_conflicts_on_updates.xml @@ -32,5 +32,6 @@ issue_update_date="1368878400000" issue_close_date="[null]" locations="[null]" + issue_type="2" /> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_update_issues-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_update_issues-result.xml index f5ffd879c45..f29278e59ae 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_update_issues-result.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_update_issues-result.xml @@ -25,6 +25,7 @@ issue_update_date="1368878400000" issue_close_date="1368878400000" locations="[null]" + issue_type="2" /> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ServerIssueStorageTest/should_insert_new_issues-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/ServerIssueStorageTest/should_insert_new_issues-result.xml index 29ff12edfe0..6e6bba1dc50 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/ServerIssueStorageTest/should_insert_new_issues-result.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/ServerIssueStorageTest/should_insert_new_issues-result.xml @@ -20,6 +20,7 @@ issue_update_date="1368878400000" issue_close_date="1368878400000" locations="[null]" + issue_type="2" /> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueIndexerTest/index.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueIndexerTest/index.xml index 1277674a21f..942bd4a30cc 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueIndexerTest/index.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueIndexerTest/index.xml @@ -33,5 +33,6 @@ issue_update_date="1368828000000" issue_close_date="[null]" locations="[null]" + issue_type="2" /> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueIndexerTest/index_project.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueIndexerTest/index_project.xml index 0f83fdf4945..098f110a70a 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueIndexerTest/index_project.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueIndexerTest/index_project.xml @@ -34,6 +34,7 @@ issue_update_date="1368828000000" issue_close_date="[null]" locations="[null]" + issue_type="2" /> @@ -68,5 +69,6 @@ issue_update_date="1368828000000" issue_close_date="[null]" locations="[null]" + issue_type="2" /> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/extract_directory_path.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/extract_directory_path.xml index 939428fa0d5..938137b4782 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/extract_directory_path.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/extract_directory_path.xml @@ -33,7 +33,8 @@ issue_creation_date="1115848800000" issue_update_date="1356994800000" issue_close_date="[null]" - locations="[null]"/> + locations="[null]" + issue_type="1"/> + locations="[null]" + issue_type="1"/> + locations="[null]" + issue_type="1"/> + locations="[null]" + issue_type="1"/> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/extract_file_path.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/extract_file_path.xml index 939428fa0d5..938137b4782 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/extract_file_path.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/extract_file_path.xml @@ -33,7 +33,8 @@ issue_creation_date="1115848800000" issue_update_date="1356994800000" issue_close_date="[null]" - locations="[null]"/> + locations="[null]" + issue_type="1"/> + locations="[null]" + issue_type="1"/> + locations="[null]" + issue_type="1"/> + locations="[null]" + issue_type="1"/> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/many_projects.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/many_projects.xml index 15c81202975..a5ec593268f 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/many_projects.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/many_projects.xml @@ -34,6 +34,7 @@ issue_update_date="1368828000000" issue_close_date="[null]" locations="[null]" + issue_type="1" /> @@ -95,5 +97,6 @@ issue_update_date="1368828000000" issue_close_date="[null]" locations="[null]" + issue_type="1" /> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/one_issue.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/one_issue.xml index f9cb45385b0..374d2b24f08 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/one_issue.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/one_issue.xml @@ -33,6 +33,8 @@ issue_creation_date="1115848800000" issue_update_date="1356994800000" issue_close_date="[null]" - locations="[null]"/> + locations="[null]" + issue_type="2" + /> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/shared.xml index 417b2fdce4c..6939692204f 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/shared.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/shared.xml @@ -34,6 +34,7 @@ issue_update_date="1356994800000" issue_close_date="[null]" locations="[null]" + issue_type="1" /> + locations="[null]" + issue_type="1" + /> diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1106_add_issues_type.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1106_add_issues_type.rb new file mode 100644 index 00000000000..bd1a3e3351e --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1106_add_issues_type.rb @@ -0,0 +1,31 @@ +# +# SonarQube, open source software quality management tool. +# Copyright (C) 2008-2014 SonarSource +# mailto:contact AT sonarsource DOT com +# +# SonarQube 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. +# +# SonarQube 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. +# + +# +# SonarQube 5.5 +# SONAR-7333 +# +class AddIssuesType < ActiveRecord::Migration + + def self.up + execute_java_migration('org.sonar.db.version.v55.AddIssuesType') + end + +end diff --git a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java index ecc151a8d08..1f623fa01b9 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java @@ -56,7 +56,7 @@ import static java.lang.String.format; public class DefaultIssue implements Issue, Trackable, org.sonar.api.ce.measure.Issue { private String key; - + private IssueType type; private String componentUuid; private String componentKey; @@ -127,6 +127,15 @@ public class DefaultIssue implements Issue, Trackable, org.sonar.api.ce.measure. return this; } + public IssueType type() { + return type; + } + + public DefaultIssue setType(IssueType type) { + this.type = type; + return this; + } + /** * Can be null on Views or Devs */ diff --git a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java index 356880b1859..2607d9384ff 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java @@ -19,6 +19,7 @@ */ package org.sonar.core.issue; +import com.google.common.base.Objects; import com.google.common.base.Preconditions; import com.google.common.collect.Maps; import java.util.Map; @@ -41,6 +42,7 @@ public class DefaultIssueBuilder implements Issuable.IssueBuilder { private Double effortToFix; private String reporter; private String assignee; + private IssueType type; private Map attributes; public DefaultIssueBuilder() { @@ -122,6 +124,11 @@ public class DefaultIssueBuilder implements Issuable.IssueBuilder { return this; } + public DefaultIssueBuilder type(@Nullable IssueType type) { + this.type = type; + return this; + } + @Override public DefaultIssueBuilder attribute(String key, @Nullable String value) { if (attributes == null) { @@ -140,6 +147,7 @@ public class DefaultIssueBuilder implements Issuable.IssueBuilder { DefaultIssue issue = new DefaultIssue(); String key = Uuids.create(); issue.setKey(key); + issue.setType(Objects.firstNonNull(type, IssueType.CODE_SMELL)); issue.setComponentKey(componentKey); issue.setProjectKey(projectKey); issue.setRuleKey(ruleKey); diff --git a/sonar-core/src/main/java/org/sonar/core/issue/IssueType.java b/sonar-core/src/main/java/org/sonar/core/issue/IssueType.java new file mode 100644 index 00000000000..2ce73537adb --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/issue/IssueType.java @@ -0,0 +1,49 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +package org.sonar.core.issue; + +import static java.lang.String.format; + +public enum IssueType { + CODE_SMELL(1), BUG(2), VULNERABILITY(3); + + private final int dbConstant; + + IssueType(int dbConstant) { + this.dbConstant = dbConstant; + } + + public int getDbConstant() { + return dbConstant; + } + + /** + * Returns the enum constant of the specified DB column value. + */ + public static IssueType valueOf(int dbConstant) { + // iterating the array is fast-enough as size is small. No need for a map. + for (IssueType type : values()) { + if (type.getDbConstant() == dbConstant) { + return type; + } + } + throw new IllegalArgumentException(format("Unsupported value for db column ISSUES.ISSUE_TYPE: %d", dbConstant)); + } +} diff --git a/sonar-db/src/main/java/org/sonar/db/issue/IssueDto.java b/sonar-db/src/main/java/org/sonar/db/issue/IssueDto.java index e4aa61e80fe..c4f8dedae2d 100644 --- a/sonar-db/src/main/java/org/sonar/db/issue/IssueDto.java +++ b/sonar-db/src/main/java/org/sonar/db/issue/IssueDto.java @@ -38,6 +38,7 @@ import org.sonar.api.rule.RuleKey; import org.sonar.api.utils.Duration; import org.sonar.api.utils.KeyValueFormat; import org.sonar.core.issue.DefaultIssue; +import org.sonar.core.issue.IssueType; import org.sonar.core.util.Uuids; import org.sonar.db.component.ComponentDto; import org.sonar.db.protobuf.DbIssues; @@ -54,6 +55,7 @@ public final class IssueDto implements Serializable { private static final Splitter TAGS_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings(); private Long id; + private int type; private String kee; private String componentUuid; private String projectUuid; @@ -103,6 +105,7 @@ public final class IssueDto implements Serializable { public static IssueDto toDtoForComputationInsert(DefaultIssue issue, int ruleId, long now) { return new IssueDto() .setKee(issue.key()) + .setType(issue.type()) .setLine(issue.line()) .setLocations((DbIssues.Locations) issue.getLocations()) .setMessage(issue.message()) @@ -151,6 +154,7 @@ public final class IssueDto implements Serializable { // Invariant fields, like key and rule, can't be updated return new IssueDto() .setKee(issue.key()) + .setType(issue.type()) .setLine(issue.line()) .setLocations((DbIssues.Locations) issue.getLocations()) .setMessage(issue.message()) @@ -696,6 +700,20 @@ public final class IssueDto implements Serializable { return this; } + public int getType() { + return type; + } + + public IssueDto setType(int type) { + this.type = type; + return this; + } + + public IssueDto setType(IssueType type) { + this.type = type.getDbConstant(); + return this; + } + @Override public String toString() { return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); @@ -704,6 +722,7 @@ public final class IssueDto implements Serializable { public DefaultIssue toDefaultIssue() { DefaultIssue issue = new DefaultIssue(); issue.setKey(kee); + issue.setType(IssueType.valueOf(type)); issue.setStatus(status); issue.setResolution(resolution); issue.setMessage(message); diff --git a/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java b/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java index 14aa4f3b3d7..113ee4f5fdd 100644 --- a/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java +++ b/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java @@ -29,7 +29,7 @@ import org.sonar.db.MyBatis; public class DatabaseVersion { - public static final int LAST_VERSION = 1103; + public static final int LAST_VERSION = 1106; /** * The minimum supported version which can be upgraded. Lower diff --git a/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java b/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java index 6e9c1d24bf6..7df3779ced9 100644 --- a/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java +++ b/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java @@ -69,6 +69,7 @@ import org.sonar.db.version.v54.MigrateQualityGatesConditions; import org.sonar.db.version.v54.MigrateUsersIdentity; import org.sonar.db.version.v54.RemoveComponentPageProperties; import org.sonar.db.version.v54.RemovePreviewPermission; +import org.sonar.db.version.v55.AddIssuesType; import org.sonar.db.version.v55.AddRulesLongDateColumns; import org.sonar.db.version.v55.DeleteMeasuresWithCharacteristicId; import org.sonar.db.version.v55.FeedRulesLongDateColumns; @@ -141,7 +142,8 @@ public class MigrationStepModule extends Module { // 5.5 AddRulesLongDateColumns.class, FeedRulesLongDateColumns.class, - DeleteMeasuresWithCharacteristicId.class - ); + DeleteMeasuresWithCharacteristicId.class, + AddIssuesType.class + ); } } diff --git a/sonar-db/src/main/java/org/sonar/db/version/TinyIntColumnDef.java b/sonar-db/src/main/java/org/sonar/db/version/TinyIntColumnDef.java new file mode 100644 index 00000000000..013e3c6fbfe --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/version/TinyIntColumnDef.java @@ -0,0 +1,79 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +package org.sonar.db.version; + +import javax.annotation.CheckForNull; +import org.sonar.db.dialect.Dialect; +import org.sonar.db.dialect.H2; +import org.sonar.db.dialect.MsSql; +import org.sonar.db.dialect.MySql; +import org.sonar.db.dialect.Oracle; +import org.sonar.db.dialect.PostgreSql; + +import static org.sonar.db.version.ColumnDefValidation.validateColumnName; + +/** + * Integer that supports at least range [0..128]. Full range depends on database vendor. + */ +public class TinyIntColumnDef extends AbstractColumnDef { + + private TinyIntColumnDef(Builder builder) { + super(builder.columnName, builder.isNullable); + } + + @Override + public String generateSqlType(Dialect dialect) { + switch (dialect.getId()) { + case PostgreSql.ID: + return "SMALLINT"; + case Oracle.ID: + return "NUMBER(3)"; + case MySql.ID: + return "TINYINT(1)"; + case MsSql.ID: + case H2.ID: + return "TINYINT"; + default: + throw new UnsupportedOperationException(String.format("Unknown dialect '%s'", dialect.getId())); + } + } + + public static class Builder { + @CheckForNull + private String columnName; + private boolean isNullable = true; + + public Builder setColumnName(String columnName) { + this.columnName = validateColumnName(columnName); + return this; + } + + public Builder setIsNullable(boolean isNullable) { + this.isNullable = isNullable; + return this; + } + + public TinyIntColumnDef build() { + validateColumnName(columnName); + return new TinyIntColumnDef(this); + } + } + +} diff --git a/sonar-db/src/main/java/org/sonar/db/version/v55/AddIssuesType.java b/sonar-db/src/main/java/org/sonar/db/version/v55/AddIssuesType.java new file mode 100644 index 00000000000..734dc8bb31b --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/version/v55/AddIssuesType.java @@ -0,0 +1,48 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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. + */ +package org.sonar.db.version.v55; + +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.db.version.AddColumnsBuilder; +import org.sonar.db.version.DdlChange; +import org.sonar.db.version.TinyIntColumnDef; + +public class AddIssuesType extends DdlChange { + + private final Database db; + + public AddIssuesType(Database db) { + super(db); + this.db = db; + } + + @Override + public void execute(Context context) throws SQLException { + context.execute(generateSql()); + } + + private String generateSql() { + return new AddColumnsBuilder(db.getDialect(), "issues") + .addColumn(new TinyIntColumnDef.Builder().setColumnName("issue_type").setIsNullable(true).build()) + .build(); + } + +} diff --git a/sonar-db/src/main/resources/org/sonar/db/issue/IssueMapper.xml b/sonar-db/src/main/resources/org/sonar/db/issue/IssueMapper.xml index de76d8cd205..ff137839e05 100644 --- a/sonar-db/src/main/resources/org/sonar/db/issue/IssueMapper.xml +++ b/sonar-db/src/main/resources/org/sonar/db/issue/IssueMapper.xml @@ -38,7 +38,8 @@ p.module_uuid_path as moduleUuidPath, p.path as filePath, root.kee as projectKey, - i.project_uuid as projectUuid + i.project_uuid as projectUuid, + i.issue_type as type @@ -70,7 +71,7 @@ INSERT INTO issues (kee, rule_id, action_plan_key, severity, manual_severity, message, line, locations, effort_to_fix, technical_debt, status, tags, resolution, checksum, reporter, assignee, author_login, issue_attributes, issue_creation_date, issue_update_date, - issue_close_date, created_at, updated_at, component_uuid, project_uuid) + issue_close_date, created_at, updated_at, component_uuid, project_uuid, issue_type) VALUES (#{kee,jdbcType=VARCHAR}, #{ruleId,jdbcType=INTEGER}, #{actionPlanKey,jdbcType=VARCHAR}, #{severity,jdbcType=VARCHAR}, #{manualSeverity,jdbcType=BOOLEAN}, #{message,jdbcType=VARCHAR}, #{line,jdbcType=INTEGER}, @@ -81,7 +82,7 @@ #{issueAttributes,jdbcType=VARCHAR}, #{issueCreationTime,jdbcType=BIGINT},#{issueUpdateTime,jdbcType=BIGINT}, #{issueCloseTime,jdbcType=BIGINT}, #{createdAt,jdbcType=BIGINT}, #{updatedAt,jdbcType=BIGINT}, - #{componentUuid,jdbcType=VARCHAR}, #{projectUuid,jdbcType=VARCHAR}) + #{componentUuid,jdbcType=VARCHAR}, #{projectUuid,jdbcType=VARCHAR}, #{type,jdbcType=INTEGER}) @@ -89,7 +90,8 @@ What has been changed : message="[null]" action_plan_key="[null]" effort_to_fix="[null]" technical_debt="[null]" issue_attributes="[null]" checksum="[null]" author_login="[null]" updated_at="1450000000000" issue_creation_date="1366063200000" issue_update_date="1396994400000" - created_at="1450000000000" tags="[null]" locations="[null]"/> + created_at="1450000000000" tags="[null]" locations="[null]" + issue_type="[null]"/> + created_at="1450000000000" tags="[null]" locations="[null]" + issue_type="[null]"/> + created_at="1450000000000" tags="[null]" locations="[null]" + issue_type="[null]"/> diff --git a/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/disable_resources_without_last_snapshot.xml b/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/disable_resources_without_last_snapshot.xml index 98781137978..d88f4f5d439 100644 --- a/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/disable_resources_without_last_snapshot.xml +++ b/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/disable_resources_without_last_snapshot.xml @@ -66,7 +66,8 @@ message="[null]" action_plan_key="[null]" effort_to_fix="[null]" technical_debt="[null]" issue_attributes="[null]" checksum="[null]" author_login="[null]" updated_at="[null]" issue_creation_date="1366063200000" issue_update_date="1366063200000" - created_at="1450000000000" locations="[null]"/> + created_at="1450000000000" locations="[null]" + issue_type="[null]"/> + created_at="1450000000000" locations="[null]" + issue_type="[null]"/> + created_at="1450000000000" locations="[null]" + issue_type="[null]"/> + created_at="1450000000000" locations="[null]" + issue_type="[null]"/> diff --git a/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/shouldDeleteProject.xml b/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/shouldDeleteProject.xml index dc6abb440dc..f1948def485 100644 --- a/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/shouldDeleteProject.xml +++ b/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/shouldDeleteProject.xml @@ -33,6 +33,7 @@ issue_update_date="1366063200000" issue_close_date="1366063200000" locations="[null]" + issue_type="[null]" /> + created_at="1400000000000" locations="[null]" + issue_type="[null]"/> @@ -72,7 +73,8 @@ message="[null]" action_plan_key="[null]" effort_to_fix="[null]" technical_debt="[null]" issue_attributes="[null]" checksum="[null]" author_login="[null]" updated_at="[null]" issue_creation_date="1366063200000" issue_update_date="1366063200000" - created_at="1400000000000" locations="[null]"/> + created_at="1400000000000" locations="[null]" + issue_type="[null]"/> diff --git a/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/should_delete_all_closed_issues.xml b/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/should_delete_all_closed_issues.xml index 90dfe2ed797..3daba8cc287 100644 --- a/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/should_delete_all_closed_issues.xml +++ b/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/should_delete_all_closed_issues.xml @@ -28,7 +28,8 @@ message="[null]" action_plan_key="[null]" effort_to_fix="[null]" technical_debt="[null]" issue_attributes="[null]" checksum="[null]" author_login="[null]" updated_at="[null]" issue_creation_date="1366063200000" issue_update_date="1366063200000" - created_at="1400000000000" locations="[null]"/> + created_at="1400000000000" locations="[null]" + issue_type="[null]"/> @@ -42,7 +43,8 @@ message="[null]" action_plan_key="[null]" effort_to_fix="[null]" technical_debt="[null]" issue_attributes="[null]" checksum="[null]" author_login="[null]" updated_at="[null]" issue_creation_date="1366063200000" issue_update_date="1366063200000" - created_at="1400000000000" locations="[null]"/> + created_at="1400000000000" locations="[null]" + issue_type="[null]"/> @@ -58,7 +60,8 @@ message="[null]" action_plan_key="[null]" effort_to_fix="[null]" technical_debt="[null]" issue_attributes="[null]" checksum="[null]" author_login="[null]" updated_at="[null]" issue_creation_date="1366063200000" issue_update_date="1366063200000" - created_at="1400000000000" locations="[null]"/> + created_at="1400000000000" locations="[null]" + issue_type="[null]"/> @@ -73,7 +76,8 @@ message="[null]" action_plan_key="[null]" effort_to_fix="[null]" technical_debt="[null]" issue_attributes="[null]" checksum="[null]" author_login="[null]" updated_at="[null]" issue_creation_date="1366063200000" issue_update_date="1366063200000" - created_at="1400000000000" locations="[null]"/> + created_at="1400000000000" locations="[null]" + issue_type="[null]"/> @@ -87,7 +91,8 @@ message="[null]" action_plan_key="[null]" effort_to_fix="[null]" technical_debt="[null]" issue_attributes="[null]" checksum="[null]" author_login="[null]" updated_at="[null]" issue_creation_date="1366063200000" issue_update_date="1366063200000" - created_at="1400000000000" locations="[null]"/> + created_at="1400000000000" locations="[null]" + issue_type="[null]"/> diff --git a/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/should_delete_old_closed_issues-result.xml b/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/should_delete_old_closed_issues-result.xml index fc37dd89259..bff1ed1ba8e 100644 --- a/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/should_delete_old_closed_issues-result.xml +++ b/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/should_delete_old_closed_issues-result.xml @@ -50,7 +50,8 @@ message="[null]" action_plan_key="[null]" effort_to_fix="[null]" technical_debt="[null]" issue_attributes="[null]" checksum="[null]" author_login="[null]" updated_at="[null]" issue_creation_date="1366063200000" issue_update_date="1366063200000" - created_at="1400000000000" locations="[null]"/> + created_at="1400000000000" locations="[null]" + issue_type="[null]"/> @@ -65,7 +66,8 @@ message="[null]" action_plan_key="[null]" effort_to_fix="[null]" technical_debt="[null]" issue_attributes="[null]" checksum="[null]" author_login="[null]" updated_at="[null]" issue_creation_date="1366063200000" issue_update_date="1366063200000" - created_at="1400000000000" locations="[null]"/> + created_at="1400000000000" locations="[null]" + issue_type="[null]"/> @@ -79,7 +81,8 @@ message="[null]" action_plan_key="[null]" effort_to_fix="[null]" technical_debt="[null]" issue_attributes="[null]" checksum="[null]" author_login="[null]" updated_at="[null]" issue_creation_date="1366063200000" issue_update_date="1366063200000" - created_at="1400000000000" locations="[null]"/> + created_at="1400000000000" locations="[null]" + issue_type="[null]"/> diff --git a/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/should_delete_old_closed_issues.xml b/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/should_delete_old_closed_issues.xml index 4688bc5f6f8..e44cbf283d1 100644 --- a/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/should_delete_old_closed_issues.xml +++ b/sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/should_delete_old_closed_issues.xml @@ -27,7 +27,8 @@ message="[null]" action_plan_key="[null]" effort_to_fix="[null]" technical_debt="[null]" issue_attributes="[null]" checksum="[null]" author_login="[null]" updated_at="[null]" issue_creation_date="1366063200000" issue_update_date="1366063200000" - created_at="1400000000000" locations="[null]"/> + created_at="1400000000000" locations="[null]" + issue_type="[null]"/> @@ -57,7 +58,8 @@ message="[null]" action_plan_key="[null]" effort_to_fix="[null]" technical_debt="[null]" issue_attributes="[null]" checksum="[null]" author_login="[null]" updated_at="[null]" issue_creation_date="1366063200000" issue_update_date="1366063200000" - created_at="1400000000000" locations="[null]"/> + created_at="1400000000000" locations="[null]" + issue_type="[null]"/> @@ -72,7 +74,8 @@ message="[null]" action_plan_key="[null]" effort_to_fix="[null]" technical_debt="[null]" issue_attributes="[null]" checksum="[null]" author_login="[null]" updated_at="[null]" issue_creation_date="1366063200000" issue_update_date="1366063200000" - created_at="1400000000000" locations="[null]"/> + created_at="1400000000000" locations="[null]" + issue_type="[null]"/> @@ -86,7 +89,8 @@ message="[null]" action_plan_key="[null]" effort_to_fix="[null]" technical_debt="[null]" issue_attributes="[null]" checksum="[null]" author_login="[null]" updated_at="[null]" issue_creation_date="1366063200000" issue_update_date="1366063200000" - created_at="1400000000000" locations="[null]"/> + created_at="1400000000000" locations="[null]" + issue_type="[null]"/> diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssueFilterParameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssueFilterParameters.java index b2ab430dd00..96e71ee495c 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssueFilterParameters.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssueFilterParameters.java @@ -53,6 +53,7 @@ public class IssueFilterParameters { public static final String AUTHORS = "authors"; public static final String LANGUAGES = "languages"; public static final String TAGS = "tags"; + public static final String TYPES = "types"; public static final String ASSIGNED = "assigned"; public static final String PLANNED = "planned"; public static final String HIDE_RULES = "hideRules"; @@ -74,7 +75,7 @@ public class IssueFilterParameters { public static final String FACET_ASSIGNED_TO_ME = "assigned_to_me"; - public static final List ALL = ImmutableList.of(ISSUES, SEVERITIES, STATUSES, RESOLUTIONS, RESOLVED, COMPONENTS, COMPONENT_ROOTS, RULES, ACTION_PLANS, REPORTERS, TAGS, + public static final List ALL = ImmutableList.of(ISSUES, SEVERITIES, STATUSES, RESOLUTIONS, RESOLVED, COMPONENTS, COMPONENT_ROOTS, RULES, ACTION_PLANS, REPORTERS, TAGS, TYPES, ASSIGNEES, LANGUAGES, ASSIGNED, PLANNED, HIDE_RULES, CREATED_AT, CREATED_AFTER, CREATED_BEFORE, CREATED_IN_LAST, COMPONENT_UUIDS, COMPONENT_ROOT_UUIDS, FACET_MODE, PROJECTS, PROJECT_UUIDS, PROJECT_KEYS, COMPONENT_KEYS, MODULE_UUIDS, DIRECTORIES, FILE_UUIDS, AUTHORS, HIDE_COMMENTS, PAGE_SIZE, PAGE_INDEX, SORT, ASC); diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/SearchWsRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/SearchWsRequest.java index 171309a17ea..c6520738eb4 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/SearchWsRequest.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/SearchWsRequest.java @@ -61,6 +61,7 @@ public class SearchWsRequest { private List severities; private List statuses; private List tags; + private List types; @CheckForNull public List getActionPlans() { @@ -392,6 +393,16 @@ public class SearchWsRequest { return this; } + @CheckForNull + public List getTypes() { + return types; + } + + public SearchWsRequest setTypes(@Nullable List types) { + this.types = types; + return this; + } + @CheckForNull public List getComponentRootUuids() { return componentRootUuids; diff --git a/sonar-ws/src/main/protobuf/ws-issues.proto b/sonar-ws/src/main/protobuf/ws-issues.proto index 87a34a07390..077871bebe1 100644 --- a/sonar-ws/src/main/protobuf/ws-issues.proto +++ b/sonar-ws/src/main/protobuf/ws-issues.proto @@ -54,6 +54,17 @@ message Operation { repeated ActionPlan actionPlans = 5; } +enum IssueType { + // Zero is required in order to not get MAINTAINABILITY as default value + // See http://androiddevblog.com/protocol-buffers-pitfall-adding-enum-values/ + UNKNOWN = 0; + + // same name as in Java enum IssueType, + // same index values as in database (see column ISSUES.ISSUE_TYPE) + CODE_SMELL = 1; + BUG = 2; + VULNERABILITY = 3; +} message Issue { optional string key = 1; @@ -90,6 +101,8 @@ message Issue { optional string updateDate = 24; optional string fUpdateAge = 25; optional string closeDate = 26; + + optional IssueType type = 27; } message Transitions { -- 2.39.5