]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-3755 Add sort in IssueQuery
authorJulien Lancelot <julien.lancelot@gmail.com>
Wed, 24 Apr 2013 15:43:59 +0000 (17:43 +0200)
committerJulien Lancelot <julien.lancelot@gmail.com>
Wed, 24 Apr 2013 15:43:59 +0000 (17:43 +0200)
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingDecorator.java
sonar-core/src/main/java/org/sonar/core/issue/IssueDao.java
sonar-core/src/main/resources/org/sonar/core/issue/IssueMapper.xml
sonar-core/src/test/java/org/sonar/core/issue/IssueDaoTest.java
sonar-core/src/test/resources/org/sonar/core/issue/IssueDaoTest/should_select_by_date_creation.xml
sonar-core/src/test/resources/org/sonar/core/issue/IssueDaoTest/should_select_returned_sorted_result.xml [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/issue/IssueQuery.java
sonar-plugin-api/src/test/java/org/sonar/api/issue/IssueQueryTest.java
sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueQuery.java
sonar-ws-client/src/test/java/org/sonar/wsclient/issue/IssueQueryTest.java

index e4ae221f2eb38730139d38c1dd5f1e590dd2e9ba..0d66c96f94d0b0810db61ca0216887775b27719f 100644 (file)
@@ -36,6 +36,7 @@ import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.issue.IssueDto;
 
 import javax.annotation.Nullable;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
@@ -75,7 +76,6 @@ public class IssueTrackingDecorator implements Decorator {
         // not in newIssues
         addManualIssuesAndCloseResolvedOnes(openIssue);
 
-
         closeResolvedStandardIssues(openIssue, issueKeys);
         keepFalsePositiveIssues(openIssue);
         reopenUnresolvedIssues(openIssue);
index 4a190ba34492ced335d9d76ec8725a0a3b0dac42..faa60590ef80808410ad2b57de31cc05aa1a0b30 100644 (file)
@@ -35,6 +35,7 @@ import java.util.List;
 import java.util.Map;
 
 import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Maps.newHashMap;
 
 /**
  * @since 3.6
@@ -43,8 +44,11 @@ public class IssueDao implements BatchComponent, ServerComponent {
 
   private final MyBatis mybatis;
 
+  private Map<String, String> avalailableSorts;
+
   public IssueDao(MyBatis mybatis) {
     this.mybatis = mybatis;
+    this.avalailableSorts = getAvalailableSorts();
   }
 
   public void insert(IssueDto issueDto) {
@@ -145,4 +149,13 @@ public class IssueDao implements BatchComponent, ServerComponent {
     return session.selectList("org.sonar.core.issue.IssueMapper.selectByIds", params);
   }
 
+  private Map<String, String> getAvalailableSorts() {
+    Map<String, String> availableSorts = newHashMap();
+    availableSorts.put("created", "i.created_at");
+    availableSorts.put("updated", "i.updated_at");
+    availableSorts.put("closed", "i.closed_at");
+    availableSorts.put("assignee", "i.assignee");
+    return availableSorts;
+  }
+
 }
index bad09e26d695909bcdf7e6053cf5eb2bfd65c98a..15e299742a3a71862343e51d265eed88406c7e50 100644 (file)
       <if test="rules != null and rules.size() > 0">
         and (<foreach item="rule" index="index" collection="rules" open="(" separator=" or " close=")">r.plugin_name=#{rule.repository} and r.plugin_rule_key=#{rule.rule}</foreach>)
       </if>
-      <if test="createdAfter">
+      <if test="createdAfter != null">
         and i.created_at &gt; #{createdAfter}
       </if>
-      <if test="createdBefore">
+      <if test="createdBefore != null">
         and i.created_at &lt; #{createdBefore}
       </if>
     </where>
+    <if test="sort != null">
+      order by
+      <choose>
+        <when test="'created'.equals(sort)">
+          i.created_at
+        </when>
+        <when test="'updated'.equals(sort)">
+          i.updated_at
+        </when>
+        <when test="'closed'.equals(sort)">
+          i.closed_at
+        </when>
+        <when test="'assignee'.equals(sort)">
+          i.assignee_login
+        </when>
+      </choose>
+      <choose>
+        <when test="true.equals(asc)">
+          asc
+        </when>
+        <otherwise>
+          desc
+        </otherwise>
+      </choose>
+    </if>
   </sql>
 
 </mapper>
index 3880b69cf9e67b7c6ca6629447885bf7e433254b..37dfa625f4523173d786f25139229281e1ae8594 100644 (file)
@@ -178,7 +178,7 @@ public class IssueDaoTest extends AbstractDaoTestCase {
     assertThat(dao.select(query)).hasSize(1);
 
     query = IssueQuery.builder().createdBefore(DateUtils.parseDate("2013-04-17")).build();
-    assertThat(dao.select(query)).hasSize(1);
+    assertThat(dao.select(query)).hasSize(2);
   }
 
   @Test
@@ -200,6 +200,18 @@ public class IssueDaoTest extends AbstractDaoTestCase {
     assertThat(dao.select(query)).hasSize(3);
   }
 
+  @Test
+  public void should_select_sort_by_assignee() {
+    setupData("shared", "should_select_returned_sorted_result");
+
+    IssueQuery query = IssueQuery.builder().sort("assignee").asc(true).build();
+    List<IssueDto> results = newArrayList(dao.select(query));
+    assertThat(results).hasSize(3);
+    assertThat(results.get(0).getAssignee()).isEqualTo("arthur");
+    assertThat(results.get(1).getAssignee()).isEqualTo("henry");
+    assertThat(results.get(2).getAssignee()).isEqualTo("perceval");
+  }
+
   @Test
   public void should_select_issue_ids_and_components_ids() {
     setupData("shared", "should_select_issue_ids_and_components_ids");
@@ -230,4 +242,5 @@ public class IssueDaoTest extends AbstractDaoTestCase {
     assertThat(results).hasSize(3);
   }
 
+
 }
index 11fe9b857b8b41e363cf582be3c4f427371aa86e..e4d6cac1cd6e4ce23f3f6cd58d0e0f222b515c7e 100644 (file)
       closed_at="2013-04-16"
       />
 
+  <issues
+      id="101"
+      kee="ABCDE"
+      resource_id="400"
+      rule_id="500"
+      severity="BLOCKER"
+      manual_severity="[false]"
+      manual_issue="[false]"
+      description="[null]"
+      line="200"
+      cost="4.2"
+      status="OPEN"
+      resolution="FIXED"
+      checksum="XXX"
+      user_login="arthur"
+      assignee_login="perceval"
+      author_login="[null]"
+      attributes="JIRA=FOO-1234"
+      created_at="2013-04-13"
+      updated_at="2013-04-13"
+      closed_at="2013-04-13"
+      />
+
 </dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/IssueDaoTest/should_select_returned_sorted_result.xml b/sonar-core/src/test/resources/org/sonar/core/issue/IssueDaoTest/should_select_returned_sorted_result.xml
new file mode 100644 (file)
index 0000000..e77de41
--- /dev/null
@@ -0,0 +1,74 @@
+<dataset>
+
+  <!-- rule 500 -->
+  <issues
+      id="100"
+      kee="ABCDE"
+      resource_id="400"
+      rule_id="500"
+      severity="BLOCKER"
+      manual_severity="[false]"
+      manual_issue="[false]"
+      description="[null]"
+      line="200"
+      cost="4.2"
+      status="OPEN"
+      resolution="FIXED"
+      checksum="XXX"
+      user_login="arthur"
+      assignee_login="arthur"
+      author_login="[null]"
+      attributes="JIRA=FOO-1234"
+      created_at="2013-04-16"
+      updated_at="2013-04-16"
+      closed_at="2013-04-16"
+      />
+
+  <issues
+      id="101"
+      kee="ABCDE"
+      resource_id="400"
+      rule_id="500"
+      severity="BLOCKER"
+      manual_severity="[false]"
+      manual_issue="[false]"
+      description="[null]"
+      line="200"
+      cost="4.2"
+      status="OPEN"
+      resolution="FIXED"
+      checksum="XXX"
+      user_login="arthur"
+      assignee_login="perceval"
+      author_login="[null]"
+      attributes="JIRA=FOO-1234"
+      created_at="2013-04-16"
+      updated_at="2013-04-16"
+      closed_at="2013-04-16"
+      />
+
+
+  <!-- rule 501 -->
+  <issues
+      id="102"
+      kee="ABCDE"
+      resource_id="400"
+      rule_id="501"
+      severity="BLOCKER"
+      manual_severity="[false]"
+      manual_issue="[false]"
+      description="[null]"
+      line="200"
+      cost="4.2"
+      status="OPEN"
+      resolution="FIXED"
+      checksum="XXX"
+      user_login="arthur"
+      assignee_login="henry"
+      author_login="[null]"
+      attributes="JIRA=FOO-1234"
+      created_at="2013-04-16"
+      updated_at="2013-04-16"
+      closed_at="2013-04-16"
+      />
+</dataset>
index bde2cab4488714bce7564ea9dc1bfd6a93189b4b..7ca75e4e14a133cfef7c80df548c56fc0bd6d0c8 100644 (file)
@@ -24,6 +24,7 @@ import com.google.common.base.Preconditions;
 import org.apache.commons.lang.builder.ReflectionToStringBuilder;
 import org.sonar.api.rule.RuleKey;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
 
@@ -45,6 +46,8 @@ public class IssueQuery {
   private final Collection<String> assignees;
   private final Date createdAfter;
   private final Date createdBefore;
+  private final String sort;
+  private final boolean asc;
 
   // max results per page
   private final int pageSize;
@@ -64,6 +67,8 @@ public class IssueQuery {
     this.assignees = builder.assignees;
     this.createdAfter = builder.createdAfter;
     this.createdBefore = builder.createdBefore;
+    this.sort = builder.sort;
+    this.asc = builder.asc;
     this.pageSize = builder.pageSize;
     this.pageIndex = builder.pageIndex;
   }
@@ -112,6 +117,14 @@ public class IssueQuery {
     return createdBefore;
   }
 
+  public String sort() {
+    return sort;
+  }
+
+  public boolean asc() {
+    return asc;
+  }
+
   public int pageSize() {
     return pageSize;
   }
@@ -134,6 +147,11 @@ public class IssueQuery {
    * @since 3.6
    */
   public static class Builder {
+
+    private enum Sort {
+      created, updated, closed, assignee;
+    }
+
     private static final int DEFAULT_PAGE_SIZE = 100;
     private static final int MAX_PAGE_SIZE = 1000;
     private static final int DEFAULT_PAGE_INDEX = 1;
@@ -149,6 +167,8 @@ public class IssueQuery {
     private Collection<String> assignees;
     private Date createdAfter;
     private Date createdBefore;
+    private String sort;
+    private boolean asc = false;
     private int pageSize = DEFAULT_PAGE_SIZE;
     private int pageIndex = DEFAULT_PAGE_INDEX;
 
@@ -210,6 +230,20 @@ public class IssueQuery {
       return this;
     }
 
+    public Builder sort(String sort) {
+      try {
+        this.sort = Sort.valueOf(sort).name();
+      } catch (IllegalArgumentException e){
+        throw new IllegalArgumentException("Sort should contain only : " + Arrays.toString(Sort.values()), e);
+      }
+      return this;
+    }
+
+    public Builder asc(boolean asc) {
+      this.asc = asc;
+      return this;
+    }
+
     public Builder pageSize(Integer i) {
       Preconditions.checkArgument(i == null || i.intValue() > 0, "Page size must be greater than 0 (got " + i + ")");
       Preconditions.checkArgument(i == null || i.intValue() < MAX_PAGE_SIZE, "Page size must be less than " + MAX_PAGE_SIZE + " (got " + i + ")");
index cb47aec4e18e275d872fdf8ef2abda1e1e846b0f..9d8a9adbdcce997ebc32f264f64a4465dd708953 100644 (file)
@@ -27,6 +27,7 @@ import org.sonar.api.rule.Severity;
 import java.util.Date;
 
 import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
 
 public class IssueQueryTest {
 
@@ -44,6 +45,7 @@ public class IssueQueryTest {
       .assignees(Lists.newArrayList("gargantua"))
       .createdAfter(new Date())
       .createdBefore(new Date())
+      .sort("assignee")
       .pageSize(10)
       .pageIndex(2)
       .build();
@@ -58,7 +60,56 @@ public class IssueQueryTest {
     assertThat(query.rules()).containsOnly(RuleKey.of("squid", "AvoidCycle"));
     assertThat(query.createdAfter()).isNotNull();
     assertThat(query.createdBefore()).isNotNull();
+    assertThat(query.sort()).isEqualTo("assignee");
     assertThat(query.pageSize()).isEqualTo(10);
     assertThat(query.pageIndex()).isEqualTo(2);
   }
+
+  @Test
+  public void should_validate_page_size() throws Exception {
+    try {
+      IssueQuery.builder()
+        .pageSize(0)
+        .build();
+      fail();
+    } catch (Exception e) {
+      assertThat(e).hasMessage("Page size must be greater than 0 (got 0)").isInstanceOf(IllegalArgumentException.class);
+    }
+  }
+
+  @Test
+  public void should_validate_page_size_too_high() throws Exception {
+    try {
+      IssueQuery.builder()
+        .pageSize(10000)
+        .build();
+      fail();
+    } catch (Exception e) {
+      assertThat(e).hasMessage("Page size must be less than 1000 (got 10000)").isInstanceOf(IllegalArgumentException.class);
+    }
+  }
+
+  @Test
+  public void should_validate_page_index() throws Exception {
+    try {
+      IssueQuery.builder()
+        .pageIndex(0)
+        .build();
+      fail();
+    } catch (Exception e) {
+      assertThat(e).hasMessage("Page index must be greater than 0 (got 0)").isInstanceOf(IllegalArgumentException.class);
+    }
+  }
+
+  @Test
+  public void should_validate_sort() throws Exception {
+    try {
+      IssueQuery.builder()
+        .sort("INVALID SORT")
+        .build();
+      fail();
+    } catch (Exception e) {
+      assertThat(e).hasMessage("Sort should contain only : [created, updated, closed, assignee]").isInstanceOf(IllegalArgumentException.class);
+    }
+  }
 }
index 34b822230f526640a227ef3c211a09f56b837eee..e4d38dc3bef211049a3bedbb4cf685f0117b112a 100644 (file)
@@ -90,6 +90,16 @@ public class IssueQuery {
     return this;
   }
 
+  public IssueQuery sort(String sort) {
+    params.put("sort", sort);
+    return this;
+  }
+
+  public IssueQuery asc(boolean asc) {
+    params.put("asc", asc);
+    return this;
+  }
+
   public IssueQuery pageSize(int pageSize) {
     params.put("pageSize", pageSize);
     return this;
index a82a6658f1b351a80415e57ccc432018e450b85b..4a37fed1e80fc6ef5889aa6dfa97fdf4241e37db 100644 (file)
@@ -43,10 +43,12 @@ public class IssueQueryTest {
       .statuses("OPEN", "CLOSED")
       .severities("BLOCKER", "INFO")
       .userLogins("login1", "login2")
+      .sort("assignee")
+      .asc(false)
       .pageSize(5)
       .pageIndex(4);
 
-    assertThat(query.urlParams()).hasSize(11);
+    assertThat(query.urlParams()).hasSize(13);
     assertThat(query.urlParams()).includes(entry("keys", "ABCDE,FGHIJ"));
     assertThat(query.urlParams()).includes(entry("assignees", "arthur,perceval"));
     assertThat(query.urlParams()).includes(entry("components", "Action.java,Filter.java"));
@@ -55,6 +57,8 @@ public class IssueQueryTest {
     assertThat(query.urlParams()).includes(entry("statuses", "OPEN,CLOSED"));
     assertThat(query.urlParams()).includes(entry("severities", "BLOCKER,INFO"));
     assertThat(query.urlParams()).includes(entry("userLogins", "login1,login2"));
+    assertThat(query.urlParams()).includes(entry("sort", "assignee"));
+    assertThat(query.urlParams()).includes(entry("asc", false));
     assertThat(query.urlParams()).includes(entry("pageSize", 5));
     assertThat(query.urlParams()).includes(entry("pageIndex", 4));
   }