]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7333 add field "type" to issues (db and elasticsearch)
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Wed, 24 Feb 2016 10:44:01 +0000 (11:44 +0100)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Fri, 26 Feb 2016 13:30:35 +0000 (14:30 +0100)
80 files changed:
server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java
server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueLifecycle.java
server/sonar-server/src/main/java/org/sonar/server/computation/issue/Rule.java
server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleTypeCopier.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/issue/IssueQuery.java
server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java
server/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueDoc.java
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueResultSetIterator.java
server/sonar-server/src/main/java/org/sonar/server/issue/ws/CreateAction.java
server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java
server/sonar-server/src/main/resources/org/sonar/server/issue/ws/example-search.json
server/sonar-server/src/test/java/org/sonar/server/computation/issue/DumbRule.java
server/sonar-server/src/test/java/org/sonar/server/computation/issue/IssueAssignerTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/issue/RuleTagsCopierTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/issue/RuleTypeCopierTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/issue/UpdateConflictResolverTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistIssuesStepTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/IssueStorageTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/IssueTesting.java
server/sonar-server/src/test/java/org/sonar/server/issue/ServerIssueStorageTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/actionplan/ActionPlanServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueResultSetIteratorTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/close_issue-result.xml
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/insert_new_issue-result.xml
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistIssuesStepTest/shared.xml
server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_insert_new_issues-result.xml
server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_resolve_conflicts_on_updates-result.xml
server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_resolve_conflicts_on_updates.xml
server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_update_issues-result.xml
server/sonar-server/src/test/resources/org/sonar/server/issue/IssueStorageTest/should_update_issues.xml
server/sonar-server/src/test/resources/org/sonar/server/issue/ServerIssueStorageTest/should_insert_new_issues-result.xml
server/sonar-server/src/test/resources/org/sonar/server/issue/ServerIssueStorageTest/should_update_issues-result.xml
server/sonar-server/src/test/resources/org/sonar/server/issue/ServerIssueStorageTest/should_update_issues.xml
server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueIndexerTest/index.xml
server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueIndexerTest/index_project.xml
server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/extract_directory_path.xml
server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/extract_file_path.xml
server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/many_projects.xml
server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/one_issue.xml
server/sonar-server/src/test/resources/org/sonar/server/issue/index/IssueResultSetIteratorTest/shared.xml
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1106_add_issues_type.rb [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java
sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java
sonar-core/src/main/java/org/sonar/core/issue/IssueType.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/issue/IssueDto.java
sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java
sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java
sonar-db/src/main/java/org/sonar/db/version/TinyIntColumnDef.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/version/v55/AddIssuesType.java [new file with mode: 0644]
sonar-db/src/main/resources/org/sonar/db/issue/IssueMapper.xml
sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql
sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl
sonar-db/src/test/java/org/sonar/db/issue/IssueDaoTest.java
sonar-db/src/test/java/org/sonar/db/issue/IssueDtoTest.java
sonar-db/src/test/java/org/sonar/db/issue/IssueMapperTest.java
sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java
sonar-db/src/test/java/org/sonar/db/version/TinyIntColumnDefTest.java [new file with mode: 0644]
sonar-db/src/test/resources/org/sonar/db/issue/IssueDaoTest/insert-result.xml
sonar-db/src/test/resources/org/sonar/db/issue/IssueMapperTest/testInsert-result.xml
sonar-db/src/test/resources/org/sonar/db/issue/IssueMapperTest/testUpdate-result.xml
sonar-db/src/test/resources/org/sonar/db/issue/IssueMapperTest/testUpdate.xml
sonar-db/src/test/resources/org/sonar/db/issue/IssueMapperTest/updateBeforeSelectedDate_with_conflict-result.xml
sonar-db/src/test/resources/org/sonar/db/issue/IssueMapperTest/updateBeforeSelectedDate_with_conflict.xml
sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/disable_resources_without_last_snapshot-result.xml
sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/disable_resources_without_last_snapshot.xml
sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/shouldDeleteProject.xml
sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/should_delete_all_closed_issues-result.xml
sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/should_delete_all_closed_issues.xml
sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/should_delete_old_closed_issues-result.xml
sonar-db/src/test/resources/org/sonar/db/purge/PurgeDaoTest/should_delete_old_closed_issues.xml
sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssueFilterParameters.java
sonar-ws/src/main/java/org/sonarqube/ws/client/issue/SearchWsRequest.java
sonar-ws/src/main/protobuf/ws-issues.proto

index c35f5b8a6340310086edacd4206aeeb260b6949c..0ca26aef8024adfe33389a008e37cdff39371b4b 100644 (file)
@@ -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
index 33ab0b5f1d2d18d9f962c0ab67b0cfa2b4228c85..fb7d388ba295253d375fcf9b1e34d9c535060952 100644 (file)
@@ -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());
index b8573cb144293c81603e9df50cbdcd8a7d907a04..aae0d4073dcbdf9d89f66f83d6dada8adb6874b2 100644 (file)
@@ -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.
    */
index 14cc9118a5d202f420863f57fd467256324ae28f..1cb90d033d9ddf1a8e801791bf35412930a5482f 100644 (file)
@@ -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<String> 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 (file)
index 0000000..3c902c8
--- /dev/null
@@ -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());
+    }
+  }
+}
index d3e45a7bbaed6234340aff94606798897a89318e..9c75dbf564062e21be535496dead3e7b1e65fc4d 100644 (file)
@@ -72,6 +72,7 @@ public class IssueQuery {
   private final Collection<String> authors;
   private final Collection<String> languages;
   private final Collection<String> tags;
+  private final Collection<String> 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<String> types() {
+    return types;
+  }
+
   @CheckForNull
   public Boolean onComponentOnly() {
     return onComponentOnly;
@@ -303,6 +309,7 @@ public class IssueQuery {
     private Collection<String> authors;
     private Collection<String> languages;
     private Collection<String> tags;
+    private Collection<String> 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<String> 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
index 443b139303a2b316f9d3ec2807d4e60dab6c726d..2cc8d64f2343b22bc3a6cd05da7b8cca77e66f67 100644 (file)
@@ -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()))
index 09c2c041d2cb3add384e6753fd4e2b20988595b9..46109f8393614a67377e925f046c1c417ebe9065 100644 (file)
@@ -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<String> setTags(String issueKey, Collection<String> tags) {
-    verifyLoggedIn();
+    userSession.checkLoggedIn();
 
     DbSession session = dbClient.openSession(false);
     try {
index 3e6d4829242e79699055968aa15f9f8a81ea298d..bc98b0cfd80864813a5ad2c99ea22b484c3b0d1b 100644 (file)
@@ -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<IssueComment> 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;
+  }
 }
index 477cec3239cf141646b2346f8f2f379f2b734209..ef3be38d93566b8757ea62428bc76b2c745cc814 100644 (file)
@@ -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));
       }
index 271ad04e7f3e78d6836c18ab307d89336846c2c8..1e019ce9a92e1dc97e58836b92e2731ed9df949a 100644 (file)
@@ -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();
   }
 }
index 6283b66dea2e6ce92dcb25d8edeaa9990f5ad792..37857d1264f431a3ccea12e9b64f43238405baf9 100644 (file)
@@ -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<IssueDoc> {
     "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<IssueDoc> {
     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;
   }
 }
index 1ef04aa330d6d00b5f108956c94932056b4aa073..fb3bf745ddc565b63987aa490bdeabfeadad7ce4 100644 (file)
  */
 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"));
index b3fb5a407a75ec88b46d1ec5f736a34d4e95ee1a..f4fa7f5b4b07ae0a0716fb23064e492e3d46da71 100644 (file)
@@ -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<String> actionPlans = Lists.newArrayList("");
     List<String> 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<IssueDoc, String> {
index 246fe4eb118da0ecccd59c554b122a229ec4c046..e828f36db1b37ec8cfb18752387628bb0bbde330 100644 (file)
@@ -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
index b02142ae1e22acaedf9aa8be792b2c9768621766..61908702dd9b859196a55f2c065c7a4a053c33d9 100644 (file)
@@ -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",
index 55465a81e2e9cbd8da2d9d9897d3a88419954777..e73f8486acc01407b8a6939d61eb11579b88f39f 100644 (file)
@@ -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<String> 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<String> tags) {
     this.tags = tags;
   }
+
+  public void setType(IssueType type) {
+    this.type = type;
+  }
 }
index 5a929c0d1492c6bab7191712eab0b7b32e16dcdf..a390f5e0c37d9daff8a5577cba2cccf88656044c 100644 (file)
@@ -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=<null>,componentUuid=<null>,componentKey=<null>,moduleUuid=<null>,moduleUuidPath=<null>," +
-        "projectUuid=<null>,projectKey=<null>,ruleKey=<null>,language=<null>,severity=<null>,manualSeverity=false,message=<null>,line=2,effortToFix=<null>,debt=<null>," +
-        "status=<null>,resolution=<null>,reporter=<null>,assignee=<null>,checksum=<null>,attributes=<null>,authorLogin=<null>,actionPlanKey=<null>,comments=<null>,tags=<null>,l" +
-        "ocations=<null>,creationDate=<null>,updateDate=<null>,closeDate=<null>,currentChange=<null>,changes=<null>,isNew=true,beingClosed=false,onDisabledRule=false," +
-        "isChanged=false,sendNotifications=false,selectedAt=<null>]");
+      "No SCM info has been found for issue DefaultIssue[key=<null>,type=VULNERABILITY,componentUuid=<null>,componentKey=<null>,moduleUuid=<null>,moduleUuidPath=<null>,projectUuid=<null>,projectKey=<null>,ruleKey=<null>,language=<null>,severity=<null>,manualSeverity=false,message=<null>,line=2,effortToFix=<null>,debt=<null>,status=<null>,resolution=<null>,reporter=<null>,assignee=<null>,checksum=<null>,attributes=<null>,authorLogin=<null>,actionPlanKey=<null>,comments=<null>,tags=<null>,locations=<null>,creationDate=<null>,updateDate=<null>,closeDate=<null>,currentChange=<null>,changes=<null>,isNew=true,beingClosed=false,onDisabledRule=false,isChanged=false,sendNotifications=false,selectedAt=<null>]");
   }
 
   private void setSingleChangeset(String author, Long date, String revision) {
index 1446354cc13fdbf416e174b8beaae0f4bcccb66f..1c75cc6f91c4f3fe118c53d439bd3c37f799e6a4 100644 (file)
@@ -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.<String>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 (file)
index 0000000..e81f28b
--- /dev/null
@@ -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);
+  }
+}
index e0d40c64aa4d0e7931e2a7e97876600655155ced..4af8c294a399a7f901f2969bcda6b6ede14dd32a 100644 (file)
@@ -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")
index 5ae798b9fd4de365342bfb4e5d5ef8ae08750b7a..85adce10b33b23224393cdf0e0d1376aff4376e2 100644 (file)
@@ -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")
index 7f802a5f4b6d180d77f2b6b16aa85177efe8e92c..f033679ff74fd218212a27f13d485c4d224b997e 100644 (file)
@@ -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
index f7c62ea5e173577b1991b9aa1036e90c2e8936be..c3c088b4fc158cbd2e5f6abb7423454c6eb62c8b 100644 (file)
@@ -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)
 
index d015d8b2e2f8c721ee5442ffd0535ecc95886433..8af8c688263bdb7d5cb82eb39a588c2fe590e805 100644 (file)
@@ -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.<String, Object>newHashMap());
     doc.setKey("ABC");
     doc.setRuleKey(RuleTesting.XOO_X1.toString());
+    doc.setType(IssueType.CODE_SMELL);
     doc.setActionPlanKey(null);
     doc.setReporter(null);
     doc.setAssignee("steve");
index e1714bc3c3f07dcb35befe6f5990ccf2075fb3cf..0e9d88413372925d278c74417e16af11f9737a2e 100644 (file)
@@ -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)
 
index 3076cf36686fd49dc2fd81870b4e3c3a88fa15d1..e4acd7aa6ac7cd6bb45a531e18868cf5ec10d229 100644 (file)
@@ -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);
 
index 4ed283308bf47eb22648f4c1a61ae7d6443ad861..89799c9ff5d800c797f7448e4c8de6d2798aa550 100644 (file)
@@ -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
index caa55c7845e1ff1af51a5ad11ea7d7492337ed69..69295b395da92b2e690218a5e879cc686abc27d2 100644 (file)
@@ -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
index 263f957b3844b863f601e43fccba105ea7038f81..a06f7a729e0279984a804c4e6f88335759488601 100644 (file)
@@ -39,6 +39,7 @@
       created_at="1300000000000"
       updated_at="1300000000000"
       locations="[null]"
+      issue_type="[null]"
       />
 
 </dataset>
index 3db758bb13b9098c324644f0157accb119ec69fe..47a64e727e1fbb5e122e0e44256eff1f9f986be5 100644 (file)
@@ -20,6 +20,7 @@
           issue_update_date="1368878400000"
           issue_close_date="1368878400000"
           locations="[null]"
+          issue_type="2"
     />
 
   <issue_changes id="1" kee="FGHIJ" issue_key="ABCDE" change_type="comment" user_login="emmerik"
index 8d08984e61df47346c2aaefbc44badf4fde0252f..cf4bf606187377f35acc211cc161c58332704633 100644 (file)
@@ -30,5 +30,6 @@
           issue_update_date="1368828000000"
           issue_close_date="[null]"
           locations="[null]"
+          issue_type="2"
     />
 </dataset>
index 76ef67e4569318b97cbd95562c6ef4b5fbd9e325..e1b2e8f4cf179d5cc1a026c44a422a77c32cef5d 100644 (file)
@@ -32,5 +32,6 @@
           issue_update_date="1368878400000"
           issue_close_date="[null]"
           locations="[null]"
+          issue_type="2"
     />
 </dataset>
index f5ffd879c4592559967e8b63b200adbdeaefd03f..f29278e59ae592612378b46cafebe90e86e5cf74 100644 (file)
@@ -25,6 +25,7 @@
           issue_update_date="1368878400000"
           issue_close_date="1368878400000"
           locations="[null]"
+          issue_type="2"
     />
 
   <issue_changes id="1" kee="FGHIJ" issue_key="ABCDE" change_type="comment" user_login="emmerik"
index 613f21bef9b7af1d1c3ae70f8aabdb407ae79667..3617769b872ceceb953fc169c6d60f685c9c5176 100644 (file)
@@ -25,5 +25,6 @@
           issue_update_date="1265065200000"
           issue_close_date="[null]"
           locations="[null]"
+          issue_type="2"
     />
 </dataset>
index 29ff12edfe0546936c8c009a98e00ad9ff41c6e8..6e6bba1dc508240f2ec70a47715705811fe379a0 100644 (file)
@@ -20,6 +20,7 @@
           issue_update_date="1368878400000"
           issue_close_date="1368878400000"
           locations="[null]"
+          issue_type="2"
       />
 
   <issue_changes id="1" kee="FGHIJ" issue_key="ABCDE" change_type="comment" user_login="emmerik"
index be8f39e9bce12ebcb5e9d91e0f8bac0172939a8c..35fda9aeac0ac0141a6afa8405d4caf1db1dc328 100644 (file)
@@ -25,6 +25,7 @@
           issue_update_date="1368878400000"
           issue_close_date="1368878400000"
           locations="[null]"
+          issue_type="2"
       />
 
   <issue_changes id="1" kee="FGHIJ" issue_key="ABCDE" change_type="comment" user_login="emmerik"
index 5ac4459b439910721c218488e1005eae8ea5693c..c57d71c333ef5d1ec65e01bb9fa8245699a7d126 100644 (file)
@@ -31,5 +31,6 @@
           issue_update_date="1265065200000"
           issue_close_date="[null]"
           locations="[null]"
+          issue_type="[null]"
       />
 </dataset>
index 1277674a21f6eed5e2d0a43e93be17f7e2420bda..942bd4a30cc8fd79f4ff31874e8f21e079e57367 100644 (file)
@@ -33,5 +33,6 @@
           issue_update_date="1368828000000"
           issue_close_date="[null]"
           locations="[null]"
+          issue_type="2"
       />
 </dataset>
index 0f83fdf49456e02f76f35a5b3d0a9a647a5451da..098f110a70a8b944a163b14ec330f439da0974a9 100644 (file)
@@ -34,6 +34,7 @@
           issue_update_date="1368828000000"
           issue_close_date="[null]"
           locations="[null]"
+          issue_type="2"
   />
 
   <!-- Project 2 -->
@@ -68,5 +69,6 @@
           issue_update_date="1368828000000"
           issue_close_date="[null]"
           locations="[null]"
+          issue_type="2"
   />
 </dataset>
index 939428fa0d5224cb8fd982b463e93ec463becf42..938137b4782308667344651450b9aa36ad8b0cc0 100644 (file)
@@ -33,7 +33,8 @@
       issue_creation_date="1115848800000"
       issue_update_date="1356994800000"
       issue_close_date="[null]"
-      locations="[null]"/>
+      locations="[null]"
+      issue_type="1"/>
 
   <issues
       id="2"
@@ -61,7 +62,8 @@
       issue_creation_date="1115848800000"
       issue_update_date="1368828000000"
       issue_close_date="[null]"
-      locations="[null]"/>
+      locations="[null]"
+      issue_type="1"/>
 
   <issues
       id="3"
@@ -89,7 +91,8 @@
       issue_creation_date="1115848800000"
       issue_update_date="1368828000000"
       issue_close_date="[null]"
-      locations="[null]"/>
+      locations="[null]"
+      issue_type="1"/>
 
   <issues
       id="4"
       issue_creation_date="1115848800000"
       issue_update_date="1368828000000"
       issue_close_date="[null]"
-      locations="[null]"/>
+      locations="[null]"
+      issue_type="1"/>
 
 </dataset>
index 939428fa0d5224cb8fd982b463e93ec463becf42..938137b4782308667344651450b9aa36ad8b0cc0 100644 (file)
@@ -33,7 +33,8 @@
       issue_creation_date="1115848800000"
       issue_update_date="1356994800000"
       issue_close_date="[null]"
-      locations="[null]"/>
+      locations="[null]"
+      issue_type="1"/>
 
   <issues
       id="2"
@@ -61,7 +62,8 @@
       issue_creation_date="1115848800000"
       issue_update_date="1368828000000"
       issue_close_date="[null]"
-      locations="[null]"/>
+      locations="[null]"
+      issue_type="1"/>
 
   <issues
       id="3"
@@ -89,7 +91,8 @@
       issue_creation_date="1115848800000"
       issue_update_date="1368828000000"
       issue_close_date="[null]"
-      locations="[null]"/>
+      locations="[null]"
+      issue_type="1"/>
 
   <issues
       id="4"
       issue_creation_date="1115848800000"
       issue_update_date="1368828000000"
       issue_close_date="[null]"
-      locations="[null]"/>
+      locations="[null]"
+      issue_type="1"/>
 
 </dataset>
index 15c812029756e87b52060fe941f1413066ed953c..a5ec593268fb72a57d29ae9cd88b1606d08dd439 100644 (file)
@@ -34,6 +34,7 @@
           issue_update_date="1368828000000"
           issue_close_date="[null]"
           locations="[null]"
+          issue_type="1"
   />
 
   <issues id="2"
@@ -61,6 +62,7 @@
           issue_update_date="2368828000000"
           issue_close_date="[null]"
           locations="[null]"
+          issue_type="1"
   />
 
   <!-- Project 2 -->
@@ -95,5 +97,6 @@
           issue_update_date="1368828000000"
           issue_close_date="[null]"
           locations="[null]"
+          issue_type="1"
   />
 </dataset>
index f9cb45385b0863d435c2ab98f256be5a701c262a..374d2b24f0815ffb9aa14419e900184fc43bb738 100644 (file)
@@ -33,6 +33,8 @@
       issue_creation_date="1115848800000"
       issue_update_date="1356994800000"
       issue_close_date="[null]"
-      locations="[null]"/>
+      locations="[null]"
+      issue_type="2"
+  />
 
 </dataset>
index 417b2fdce4c0a89d4906945f8ebc89d04489919b..6939692204f2eb8d423f087bc3ca669626fffd36 100644 (file)
@@ -34,6 +34,7 @@
     issue_update_date="1356994800000"
     issue_close_date="[null]"
     locations="[null]"
+    issue_type="1"
     />
 
   <issues
@@ -63,6 +64,7 @@
     issue_update_date="1356994800000"
     issue_close_date="[null]"
     locations="[null]"
+    issue_type="2"
     />
 
   <issues
@@ -91,7 +93,9 @@
     issue_creation_date="1115848800000"
     issue_update_date="1368828000000"
     issue_close_date="[null]"
-    locations="[null]"/>
+    locations="[null]"
+    issue_type="1"
+  />
 
   <issues
     id="4"
     issue_update_date="1356994800000"
     issue_close_date="[null]"
     locations="[null]"
+    issue_type="1"
     />
 
 </dataset>
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 (file)
index 0000000..bd1a3e3
--- /dev/null
@@ -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
index ecc151a8d08e93f3f5db5032ee7d9268ba3d2f1f..1f623fa01b90b0591cf8df76bf9a6d3f4c329703 100644 (file)
@@ -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
    */
index 356880b1859760866ff52ad039795d3deba33643..2607d9384ff63592f94298ddc308afd8c6b1aea6 100644 (file)
@@ -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<String, String> 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 (file)
index 0000000..2ce7353
--- /dev/null
@@ -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));
+  }
+}
index e4aa61e80fedbc9c388b8766d834d59dac3c698a..c4f8dedae2d9433a54b9a730771588542a760b0e 100644 (file)
@@ -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);
index 14aa4f3b3d7a58d5c97729ff161ca94da44bd336..113ee4f5fdded16ab2d3d59eaba59d5efe092348 100644 (file)
@@ -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
index 6e9c1d24bf6ed65f74cb211a7cdb4b81db7a605a..7df3779ced9a288a7a6dc690571ed55a18e4d9b3 100644 (file)
@@ -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 (file)
index 0000000..013e3c6
--- /dev/null
@@ -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 (file)
index 0000000..734dc8b
--- /dev/null
@@ -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();
+  }
+
+}
index de76d8cd2057b7cc096d10a53e0201d7e19893d4..ff137839e05e52337b0b7448ed0834468e11a655 100644 (file)
@@ -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
   </sql>
 
   <sql id="sortColumn">
@@ -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})
   </insert>
 
   <!--
     issue_creation_date=#{issueCreationTime,jdbcType=BIGINT},
     issue_update_date=#{issueUpdateTime,jdbcType=BIGINT},
     issue_close_date=#{issueCloseTime,jdbcType=BIGINT},
-    updated_at=#{updatedAt,jdbcType=BIGINT}
+    updated_at=#{updatedAt,jdbcType=BIGINT},
+    issue_type=#{type,jdbcType=INTEGER}
     where kee = #{kee}
   </update>
 
     issue_creation_date=#{issueCreationTime,jdbcType=BIGINT},
     issue_update_date=#{issueUpdateTime,jdbcType=BIGINT},
     issue_close_date=#{issueCloseTime,jdbcType=BIGINT},
-    updated_at=#{updatedAt,jdbcType=BIGINT}
+    updated_at=#{updatedAt,jdbcType=BIGINT},
+    issue_type=#{type,jdbcType=INTEGER}
     where kee = #{kee} and updated_at &lt;= #{selectedAt}
   </update>
 
     i.issue_close_date as issueCloseTime,
     i.created_at as createdAt,
     i.updated_at as updatedAt,
+    i.issue_type as type,
     r.plugin_rule_key as ruleKey,
     r.plugin_name as ruleRepo,
     p.kee as componentKey,
index 94bc2592c1cadf585b164c7c7e423c100015f57e..2016f764ae9ad181a372c8a8f9b71c0ed629ccf6 100644 (file)
@@ -381,6 +381,7 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1100');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1101');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1102');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1103');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1106');
 
 INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, EXTERNAL_IDENTITY, EXTERNAL_IDENTITY_PROVIDER, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'admin', 'sonarqube', 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '1418215735482', '1418215735482', null, null);
 ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;
index 2889c1496a2d396aaeb1c774d50465d4613c3307..bd490bd5036e36624f4ec968b1f3315146cde570 100644 (file)
@@ -423,6 +423,7 @@ CREATE TABLE "ISSUES" (
   "CREATED_AT" BIGINT,
   "UPDATED_AT" BIGINT,
   "LOCATIONS" BLOB(167772150),
+  "ISSUE_TYPE" TINYINT
 );
 
 CREATE TABLE "ISSUE_CHANGES" (
index 632f9c4a6efa3cffa295390f95ab4f158c95dc00..ddd3920af680aa5d5a81778350e076f9b0fb8065 100644 (file)
@@ -27,6 +27,7 @@ import org.junit.experimental.categories.Category;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.System2;
+import org.sonar.core.issue.IssueType;
 import org.sonar.db.DbTester;
 import org.sonar.db.RowNotFoundException;
 import org.sonar.db.component.ComponentDto;
@@ -205,6 +206,7 @@ public class IssueDaoTest {
     dto.setProject(new ComponentDto().setKey("struts").setId(100L).setUuid("project-uuid"));
     dto.setRule(RuleTesting.newDto(RuleKey.of("squid", "S001")).setId(200));
     dto.setKee("ABCDE");
+    dto.setType(2);
     dto.setLine(500);
     dto.setEffortToFix(3.14);
     dto.setDebt(10L);
index bd8777a2b852ecba818fcb7e375dba0a4fcad1b5..459149820245a9d97cb08746587583fa9f0b753a 100644 (file)
@@ -29,6 +29,7 @@ import org.junit.rules.ExpectedException;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.utils.Duration;
 import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueType;
 import org.sonar.db.rule.RuleDto;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -58,6 +59,7 @@ public class IssueDtoTest {
 
     IssueDto dto = new IssueDto()
       .setKee("100")
+      .setType(IssueType.VULNERABILITY)
       .setRuleId(1)
       .setRuleKey("squid", "AvoidCycle")
       .setLanguage("xoo")
@@ -85,6 +87,7 @@ public class IssueDtoTest {
 
     DefaultIssue issue = dto.toDefaultIssue();
     assertThat(issue.key()).isEqualTo("100");
+    assertThat(issue.type()).isEqualTo(IssueType.VULNERABILITY);
     assertThat(issue.ruleKey().toString()).isEqualTo("squid:AvoidCycle");
     assertThat(issue.language()).isEqualTo("xoo");
     assertThat(issue.componentUuid()).isEqualTo("CDEF");
index fffee7781cf585063e6987f03ec958ed88470d49..af47700e03e59aa4deeb602aaea9dacbf1e6461f 100644 (file)
@@ -43,6 +43,7 @@ public class IssueMapperTest {
     dto.setComponentUuid("uuid-123");
     dto.setProjectUuid("uuid-100");
     dto.setRuleId(200);
+    dto.setType(2);
     dto.setKee("ABCDE");
     dto.setLine(500);
     dto.setEffortToFix(3.14);
@@ -78,6 +79,7 @@ public class IssueMapperTest {
     dto.setComponentUuid("uuid-123");
     dto.setProjectUuid("uuid-101");
     dto.setRuleId(200);
+    dto.setType(3);
     dto.setKee("ABCDE");
     dto.setLine(500);
     dto.setEffortToFix(3.14);
@@ -113,6 +115,7 @@ public class IssueMapperTest {
     dto.setComponentUuid("uuid-123");
     dto.setProjectUuid("uuid-101");
     dto.setRuleId(200);
+    dto.setType(3);
     dto.setKee("ABCDE");
     dto.setLine(500);
     dto.setEffortToFix(3.14);
index 599f12c04a42028b2feb449f88151b1d48e6c57a..033448a921e38add2bb42441e2c37aa7ec73e4ce 100644 (file)
@@ -29,6 +29,6 @@ public class MigrationStepModuleTest {
   public void verify_count_of_added_MigrationStep_types() {
     ComponentContainer container = new ComponentContainer();
     new MigrationStepModule().configure(container);
-    assertThat(container.size()).isEqualTo(54);
+    assertThat(container.size()).isEqualTo(55);
   }
 }
diff --git a/sonar-db/src/test/java/org/sonar/db/version/TinyIntColumnDefTest.java b/sonar-db/src/test/java/org/sonar/db/version/TinyIntColumnDefTest.java
new file mode 100644 (file)
index 0000000..da7b10c
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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 org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+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.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class TinyIntColumnDefTest {
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  @Test
+  public void build_string_column_def() throws Exception {
+    TinyIntColumnDef def = new TinyIntColumnDef.Builder()
+      .setColumnName("foo")
+      .setIsNullable(true)
+      .build();
+
+    assertThat(def.getName()).isEqualTo("foo");
+    assertThat(def.isNullable()).isTrue();
+  }
+
+  @Test
+  public void generate_sql_type() throws Exception {
+    TinyIntColumnDef def = new TinyIntColumnDef.Builder()
+      .setColumnName("foo")
+      .setIsNullable(true)
+      .build();
+
+    assertThat(def.generateSqlType(new H2())).isEqualTo("TINYINT");
+    assertThat(def.generateSqlType(new PostgreSql())).isEqualTo("SMALLINT");
+    assertThat(def.generateSqlType(new MsSql())).isEqualTo("TINYINT");
+    assertThat(def.generateSqlType(new MySql())).isEqualTo("TINYINT(1)");
+    assertThat(def.generateSqlType(new Oracle())).isEqualTo("NUMBER(3)");
+  }
+
+  @Test
+  public void fail_with_UOE_to_generate_sql_type_when_unknown_dialect() throws Exception {
+    thrown.expect(UnsupportedOperationException.class);
+    thrown.expectMessage("Unknown dialect 'unknown'");
+
+    TinyIntColumnDef def = new TinyIntColumnDef.Builder()
+      .setColumnName("foo")
+      .setIsNullable(true)
+      .build();
+
+    Dialect dialect = mock(Dialect.class);
+    when(dialect.getId()).thenReturn("unknown");
+    def.generateSqlType(dialect);
+  }
+}
index 130d6b737b0be85044c47904cc891d812ff5fdaa..e757170fca0c4f627dc549cd5aabf71cc33983ba 100644 (file)
@@ -26,5 +26,6 @@
       updated_at="1450000000000"
       action_plan_key="current_sprint"
       locations="[null]"
+      issue_type="2"
     />
 </dataset>
index faeae1850351e2d1cec8b4f1e1d9c6e4a80d8c66..2f9d5a587091af46fe524831456dbf57ea696afe 100644 (file)
@@ -26,5 +26,6 @@
     updated_at="1500000000000"
     action_plan_key="current_sprint"
     locations="[null]"
+    issue_type="2"
     />
 </dataset>
index 3ff7dda68ea0a7843d765fbe3f9abccd7373c837..609e9bda87b525dacb78650fa5a6d0f7fc32b9b7 100644 (file)
@@ -26,5 +26,6 @@
     updated_at="1500000000000"
     action_plan_key="current_sprint"
     locations="[null]"
+    issue_type="3"
     />
 </dataset>
index a0bb2436319ad98dbd62275c55e799082a0e7f45..54bf38bb28f84ced1e398198f2694b68bef6502b 100644 (file)
@@ -24,5 +24,6 @@
     updated_at="1500000000000"
     action_plan_key="[null]"
     locations="[null]"
+    issue_type="2"
     />
 </dataset>
index c48d24ec9e5f66b04986dc58848f52522caebefa..b1de89b30676d7e0ecff3e01e4867a2252b9ee21 100644 (file)
@@ -25,5 +25,6 @@
     updated_at="1450000000000"
     action_plan_key="[null]"
     locations="[null]"
+    issue_type="[null]"
     />
 </dataset>
index a29dac6c3f5d8bdb1bfdc94ca006064114e47f12..0abcffe1af9fee6f2e0e2396059c35b08a0f689b 100644 (file)
@@ -76,6 +76,7 @@ What has been changed :
           updated_at="1450000000000" issue_creation_date="1366063200000" issue_update_date="1396994400000"
           created_at="1450000000000" tags="[null]"
           locations="[null]"
+          issue_type="[null]"
     />
 
   <!-- Open issue on directory -->
@@ -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]"/>
 
   <!-- Open issue on project -->
   <issues id="3" kee="ISSUE-3"
@@ -102,7 +104,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]"/>
 
   <!-- Resolved issue on file -> not to be updated -->
   <issues id="4" kee="ISSUE-4"
@@ -115,6 +118,7 @@ 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="1396908000000"
-          created_at="1450000000000" tags="[null]" locations="[null]"/>
+          created_at="1450000000000" tags="[null]" locations="[null]"
+          issue_type="[null]"/>
 
 </dataset>
index 987811379780fe77ca943cdc01f9ba16c37772cf..d88f4f5d439815fc3316d738d5d43ff036e6c4a9 100644 (file)
@@ -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]"/>
 
   <!-- Open issue on directory -->
   <issues id="2" kee="ISSUE-2"
@@ -79,7 +80,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]"/>
 
   <!-- Open issue on project -->
   <issues id="3" kee="ISSUE-3"
@@ -92,7 +94,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]"/>
 
   <!-- Resolved issue on file -> not to be updated -->
   <issues id="4" kee="ISSUE-4"
           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="1396908000000"
-          created_at="1450000000000" locations="[null]"/>
+          created_at="1450000000000" locations="[null]"
+          issue_type="[null]"/>
 
 </dataset>
index dc6abb440dc9c5074869dfc81034a1e26ee33644..f1948def48577202cc976305f0530c2c7887dbce 100644 (file)
@@ -33,6 +33,7 @@
           issue_update_date="1366063200000"
           issue_close_date="1366063200000"
           locations="[null]"
+          issue_type="[null]"
     />
 
   <issues id="2" kee="ABCDF" component_uuid="A" project_uuid="A" status="CLOSED" resolution="[null]" line="200"
@@ -47,6 +48,7 @@
           issue_update_date="1366063200000"
           issue_close_date="1366063200000"
           locations="[null]"
+          issue_type="[null]"
     />
 
   <issue_changes id="1" kee="[null]" issue_key="ABCDF" created_at="[null]" updated_at="[null]" user_login="admin"
index b77fb6a2cc38af647c7d79087a317d0fe9841303..381c5993068ac1db484a385bd1843af6719be923 100644 (file)
@@ -57,7 +57,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]"/>
   <issue_changes id="3" kee="[null]" issue_key="ISSUE-3" created_at="[null]" updated_at="[null]" user_login="admin"
                  change_type="comment" change_data="abc" issue_change_creation_date="[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]"/>
   <issue_changes id="4" kee="[null]" issue_key="ISSUE-4" created_at="[null]" updated_at="[null]" user_login="admin"
                  change_type="comment" change_data="abc" issue_change_creation_date="[null]"/>
 
index 90dfe2ed797750114429d5fc47358d62ff2b19c3..3daba8cc28722d5dea4dc205408cfbc13549ac06 100644 (file)
@@ -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]"/>
   <issue_changes id="1" kee="[null]" issue_key="ISSUE-1" created_at="[null]" updated_at="[null]" user_login="admin"
                  change_type="comment" change_data="abc" issue_change_creation_date="[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]"/>
   <issue_changes id="2" kee="[null]" issue_key="ISSUE-2" created_at="[null]" updated_at="[null]" user_login="admin"
                  change_type="comment" change_data="abc" issue_change_creation_date="[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]"/>
   <issue_changes id="3" kee="[null]" issue_key="ISSUE-3" created_at="[null]" updated_at="[null]" user_login="admin"
                  change_type="comment" change_data="abc" issue_change_creation_date="[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]"/>
   <issue_changes id="4" kee="[null]" issue_key="ISSUE-4" created_at="[null]" updated_at="[null]" user_login="admin"
                  change_type="comment" change_data="abc" issue_change_creation_date="[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]"/>
   <issue_changes id="5" kee="[null]" issue_key="ISSUE-5" created_at="[null]" updated_at="[null]" user_login="admin"
                  change_type="comment" change_data="abc" issue_change_creation_date="[null]"/>
 
index fc37dd89259a86258d9be883e0b8617cd6cd1600..bff1ed1ba8ee00beb43794d9b53bea402c78d48d 100644 (file)
@@ -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]"/>
   <issue_changes id="3" kee="[null]" issue_key="ISSUE-3" created_at="[null]" updated_at="[null]" user_login="admin"
                  change_type="comment" change_data="abc" issue_change_creation_date="[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]"/>
   <issue_changes id="4" kee="[null]" issue_key="ISSUE-4" created_at="[null]" updated_at="[null]" user_login="admin"
                  change_type="comment" change_data="abc" issue_change_creation_date="[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]"/>
   <issue_changes id="5" kee="[null]" issue_key="ISSUE-5" created_at="[null]" updated_at="[null]" user_login="admin"
                  change_type="comment" change_data="abc" issue_change_creation_date="[null]"/>
 
index 4688bc5f6f8e40c5deb3ba069bf586d3aa35255c..e44cbf283d157a14e987bca196330ac403d083f2 100644 (file)
@@ -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]"/>
   <issue_changes id="1" kee="[null]" issue_key="ISSUE-1" created_at="[null]" updated_at="[null]" user_login="admin"
                  change_type="comment" change_data="abc" issue_change_creation_date="[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]"/>
   <issue_changes id="3" kee="[null]" issue_key="ISSUE-3" created_at="[null]" updated_at="[null]" user_login="admin"
                  change_type="comment" change_data="abc" issue_change_creation_date="[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]"/>
   <issue_changes id="4" kee="[null]" issue_key="ISSUE-4" created_at="[null]" updated_at="[null]" user_login="admin"
                  change_type="comment" change_data="abc" issue_change_creation_date="[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]"/>
   <issue_changes id="5" kee="[null]" issue_key="ISSUE-5" created_at="[null]" updated_at="[null]" user_login="admin"
                  change_type="comment" change_data="abc" issue_change_creation_date="[null]"/>
 
index b2ab430dd00c84266e23421f1dd6d02a2653d26d..96e71ee495c10b042aa0be22cab8cd2621a10b14 100644 (file)
@@ -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<String> ALL = ImmutableList.of(ISSUES, SEVERITIES, STATUSES, RESOLUTIONS, RESOLVED, COMPONENTS, COMPONENT_ROOTS, RULES, ACTION_PLANS, REPORTERS, TAGS,
+  public static final List<String> 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);
 
index 171309a17ea44e0b1ee18a677e3b89a5e881df88..c6520738eb4441fd497b9335d70d260e2f21fbf3 100644 (file)
@@ -61,6 +61,7 @@ public class SearchWsRequest {
   private List<String> severities;
   private List<String> statuses;
   private List<String> tags;
+  private List<String> types;
 
   @CheckForNull
   public List<String> getActionPlans() {
@@ -392,6 +393,16 @@ public class SearchWsRequest {
     return this;
   }
 
+  @CheckForNull
+  public List<String> getTypes() {
+    return types;
+  }
+
+  public SearchWsRequest setTypes(@Nullable List<String> types) {
+    this.types = types;
+    return this;
+  }
+
   @CheckForNull
   public List<String> getComponentRootUuids() {
     return componentRootUuids;
index 87a34a07390b4773ff78b36526c761e027be099e..077871bebe15eff985c54d75e7e14862fd882f66 100644 (file)
@@ -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 {