]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-17513 Deprecated legacy pagination parameters in APIs results
authorMalek-Ben-Anes <malek.benanes@sonarsource.com>
Tue, 25 Oct 2022 12:07:15 +0000 (14:07 +0200)
committersonartech <sonartech@sonarsource.com>
Fri, 28 Oct 2022 20:03:23 +0000 (20:03 +0000)
28 files changed:
server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/ChangelogAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/SearchAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/usergroups/ws/UsersAction.java
server/sonar-webserver-webapi/src/main/resources/org/sonar/server/metric/ws/example-search.json
server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualityprofile/ws/changelog-example.json
server/sonar-webserver-webapi/src/main/resources/org/sonar/server/rule/ws/search-example.json
server/sonar-webserver-webapi/src/main/resources/org/sonar/server/usergroups/ws/users-example.json
server/sonar-webserver-webapi/src/main/resources/org/sonar/server/ws/ws/response_example-example.json
server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/usergroups/ws/UsersActionTest.java
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/apply_paging_with_multiple_components.json
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/apply_paging_with_one_component.json
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/ignore_paging_with_one_component.json
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/no_issue.json
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/paging.json
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/qualityprofile/ws/ChangelogActionTest/changelog_example.json [new file with mode: 0644]
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/rule/ws/SearchActionMediumTest/filter_by_tags.json
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/rule/ws/SearchActionMediumTest/get_note_as_markdown_and_html.json
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/rule/ws/SearchActionMediumTest/search_2_rules.json
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/rule/ws/SearchActionMediumTest/search_2_rules_fields.json
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/rule/ws/SearchActionMediumTest/search_active_rules.json
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/rule/ws/SearchActionMediumTest/search_debt_rules_with_default_and_overridden_debt_values.json
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/rule/ws/SearchActionMediumTest/search_debt_rules_with_default_linear_offset_and_overridden_constant_debt.json
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/rule/ws/SearchActionMediumTest/search_debt_rules_with_default_linear_offset_and_overridden_linear_debt.json
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/rule/ws/SearchActionMediumTest/search_no_rules.json
server/sonar-webserver-webapi/src/test/resources/org/sonar/server/rule/ws/SearchActionTest/paging.json [new file with mode: 0644]
sonar-ws/src/main/protobuf/ws-rules.proto

index a47320dd6e4e3adb4dc27e361fcedeae9b0d825f..776829ddc16f2d76d8df7fd181e6b6750b5049ad 100644 (file)
@@ -70,6 +70,9 @@ public class ChangelogAction implements QProfileWsAction {
       .setSince("5.2")
       .setDescription("Get the history of changes on a quality profile: rule activation/deactivation, change in parameters/severity. " +
         "Events are ordered by date in descending order (most recent first).")
+      .setChangelog(
+        new org.sonar.api.server.ws.Change("9.8", "response fields 'total', 's', 'ps' have been deprecated, please use 'paging' object instead"),
+        new org.sonar.api.server.ws.Change("9.8", "The field 'paging' has been added to the response"))
       .setHandler(this)
       .setResponseExample(getClass().getResource("changelog-example.json"));
 
@@ -141,9 +144,12 @@ public class ChangelogAction implements QProfileWsAction {
   private static void writeResponse(JsonWriter json, int total, int page, int pageSize, List<Change> changelogs,
     Map<String, UserDto> usersByUuid, Map<String, RuleDto> rulesByRuleUuids) {
     json.beginObject();
-    json.prop("total", total);
-    json.prop(Param.PAGE, page);
-    json.prop(Param.PAGE_SIZE, pageSize);
+    writePaging(json, total, page, pageSize);
+    json.name("paging").beginObject()
+      .prop("pageIndex", page)
+      .prop("pageSize", pageSize)
+      .prop("total", total)
+      .endObject();
     json.name("events").beginArray();
     changelogs.forEach(change -> {
       JsonWriter changeWriter = json.beginObject();
@@ -178,6 +184,16 @@ public class ChangelogAction implements QProfileWsAction {
     json.endObject();
   }
 
+  /**
+   * @deprecated since 9.8 - replaced by 'paging' object structure.
+   */
+  @Deprecated(since = "9.8")
+  private static void writePaging(JsonWriter json, int total, int page, int pageSize) {
+    json.prop("total", total);
+    json.prop(Param.PAGE, page);
+    json.prop(Param.PAGE_SIZE, pageSize);
+  }
+
   /**
    * @return non-null list of changes, by descending order of date
    */
index 016d1da1236379e997d8ea8d06710a4c62eba12a..13ea8a5011bcaae1d3ce38699b83082e15d3f2c4 100644 (file)
@@ -138,6 +138,8 @@ public class SearchAction implements RulesWsAction {
       .addPagingParams(100, MAX_PAGE_SIZE)
       .setHandler(this)
       .setChangelog(
+        new Change("9.8", "response fields 'total', 's', 'ps' have been deprecated, please use 'paging' object instead"),
+        new Change("9.8", "The field 'paging' has been added to the response"),
         new Change("5.5", "The field 'effortToFixDescription' has been deprecated use 'gapDescription' instead"),
         new Change("5.5", "The field 'debtRemFnCoeff' has been deprecated use 'remFnGapMultiplier' instead"),
         new Change("5.5", "The field 'defaultDebtRemFnCoeff' has been deprecated use 'defaultRemFnGapMultiplier' instead"),
@@ -202,6 +204,14 @@ public class SearchAction implements RulesWsAction {
     response.setTotal(searchResult.total);
     response.setP(context.getPage());
     response.setPs(context.getLimit());
+    response.setPaging(formatPaging(searchResult.total, context.getPage(), context.getLimit()));
+  }
+
+  private static Common.Paging.Builder formatPaging(Long total, int pageIndex, int limit) {
+    return Common.Paging.newBuilder()
+      .setPageIndex(pageIndex)
+      .setPageSize(limit)
+      .setTotal(total.intValue());
   }
 
   private void writeRules(DbSession dbSession, SearchResponse.Builder response, SearchResult result, SearchOptions context) {
index 651230763c130d174d039d27ec0a63cb23561369..d51d675790fd73d29abd8e955ddf394df765d062 100644 (file)
@@ -68,6 +68,8 @@ public class UsersAction implements UserGroupsWsAction {
       .addSearchQuery("freddy", "names", "logins")
       .addPagingParams(25)
       .setChangelog(
+        new Change("9.8", "response fields 'total', 's', 'ps' have been deprecated, please use 'paging' object instead."),
+        new Change("9.8", "The field 'paging' has been added to the response."),
         new Change("8.4", "Parameter 'id' is deprecated. Format changes from integer to string. Use 'name' instead."));
 
     defineGroupWsParameters(action);
@@ -99,6 +101,11 @@ public class UsersAction implements UserGroupsWsAction {
         json.beginObject();
         writeMembers(json, users);
         writePaging(json, paging);
+        json.name("paging").beginObject()
+          .prop("pageIndex", page)
+          .prop("pageSize", pageSize)
+          .prop("total", total)
+          .endObject();
         json.endObject();
       }
     }
@@ -116,6 +123,10 @@ public class UsersAction implements UserGroupsWsAction {
     json.endArray();
   }
 
+  /**
+   * @deprecated since 9.8 - replaced by 'paging' object structure.
+   */
+  @Deprecated(since = "9.8")
   private static void writePaging(JsonWriter json, Paging paging) {
     json.prop(Param.PAGE, paging.pageIndex())
       .prop(Param.PAGE_SIZE, paging.pageSize())
index a10a1d76c866fe5f30cc9c7efa6f0413e2ed54c5..4de63316bb595aa32d797220ec8df626e3388979 100644 (file)
@@ -25,7 +25,9 @@
       "custom": false
     }
   ],
-  "total": 2,
-  "p": 1,
-  "ps": 100
+  "paging": {
+    "pageSize": 100,
+    "total": 2,
+    "pageIndex": 1
+  }
 }
index 49556046226be0ef69da8ff1f71be1998243e921..0bf3a77442edc5c77019e5a29dd8bf74a07a1bdc 100644 (file)
@@ -1,7 +1,9 @@
 {
-  "total": 3,
-  "ps": 10,
-  "p": 1,
+  "paging": {
+    "pageSize": 10,
+    "total": 3,
+    "pageIndex": 1
+  },
   "events": [
     {
       "date" : "2015-02-23T17:58:39+0100",
index cc1dfc766223c51c2066477c08045c2e90bab96a..e2a94d528529a01aec6144442570805686843a29 100644 (file)
@@ -1,7 +1,9 @@
 {
-  "total": 4,
-  "p": 1,
-  "ps": 3,
+  "paging": {
+    "pageSize": 3,
+    "total": 4,
+    "pageIndex": 1
+  },
   "rules": [
     {
       "key": "squid:S1067",
index d90046c468683ad0fc10ffd0801abafe6426abb2..9b38c59393ebe2c12ac11152a7ae460fd9a1c74e 100644 (file)
@@ -11,7 +11,9 @@
       "selected": true
     }
   ],
-  "p":1,
-  "ps":25,
-  "total":2
+  "paging": {
+    "pageIndex": 1,
+    "pageSize": 25,
+    "total": 2
+  }
 }
index 86a6548d865862b420fdac8d45b933647c98e1ce..46674b77634efdf4b001e2904de4535320552026 100644 (file)
@@ -1,4 +1,91 @@
 {
   "format": "json",
-  "example": "{\n  \"paging\": {\n    \"pageIndex\": 1,\n    \"pageSize\": 100,\n    \"total\": 1\n  },\n  \"issues\": [\n    {\n      \"key\": \"01fc972e-2a3c-433e-bcae-0bd7f88f5123\",\n      \"component\": \"com.github.kevinsawicki:http-request:com.github.kevinsawicki.http.HttpRequest\",\n      \"project\": \"com.github.kevinsawicki:http-request\",\n      \"rule\": \"checkstyle:com.puppycrawl.tools.checkstyle.checks.coding.MagicNumberCheck\",\n      \"status\": \"RESOLVED\",\n      \"resolution\": \"FALSE-POSITIVE\",\n      \"severity\": \"MINOR\",\n      \"message\": \"'3' is a magic number.\",\n      \"line\": 530,\n      \"textRange\": {\n        \"startLine\": 81,\n        \"endLine\": 81,\n        \"startOffset\": 0,\n        \"endOffset\": 134\n      },\n      \"author\": \"Developer 1\",\n      \"debt\": \"2h1min\",\n      \"creationDate\": \"2013-05-13T17:55:39+0200\",\n      \"updateDate\": \"2013-05-13T17:55:39+0200\",\n      \"tags\": [\"bug\"],\n      \"comments\": [\n        {\n          \"key\": \"7d7c56f5-7b5a-41b9-87f8-36fa70caa5ba\",\n          \"login\": \"john.smith\",\n          \"htmlText\": \"Must be &quot;final&quot;!\",\n          \"markdown\": \"Must be \\\"final\\\"!\",\n          \"updatable\": false,\n          \"createdAt\": \"2013-05-13T18:08:34+0200\"\n        }\n      ],\n      \"attr\": {\n        \"jira-issue-key\": \"SONAR-1234\"\n      },\n      \"transitions\": [\n        \"unconfirm\",\n        \"resolve\",\n        \"falsepositive\"\n      ],\n      \"actions\": [\n        \"comment\"\n      ]\n    }\n  ],\n  \"components\": [\n    {\n      \"key\": \"com.github.kevinsawicki:http-request:src/main/java/com/github/kevinsawicki/http/HttpRequest.java\",\n      \"enabled\": true,\n      \"qualifier\": \"FIL\",\n      \"name\": \"HttpRequest.java\",\n      \"longName\": \"src/main/java/com/github/kevinsawicki/http/HttpRequest.java\",\n      \"path\": \"src/main/java/com/github/kevinsawicki/http/HttpRequest.java\"\n    },\n    {\n      \"key\": \"com.github.kevinsawicki:http-request\",\n      \"enabled\": true,\n      \"qualifier\": \"TRK\",\n      \"name\": \"http-request\",\n      \"longName\": \"http-request\"\n    }\n  ],\n  \"rules\": [\n    {\n      \"key\": \"checkstyle:com.puppycrawl.tools.checkstyle.checks.coding.MagicNumberCheck\",\n      \"name\": \"Magic Number\",\n      \"status\": \"READY\",\n      \"lang\": \"java\",\n      \"langName\": \"Java\"\n    }\n  ],\n  \"users\": [\n    {\n      \"login\": \"admin\",\n      \"name\": \"Administrator\",\n      \"active\": true,\n      \"email\": \"admin@sonarqube.org\"\n    }\n  ]\n\n}"
+  "example": {
+    "paging": {
+      "pageIndex": 1,
+      "pageSize": 100,
+      "total": 1
+    },
+    "issues": [
+      {
+        "key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
+        "component": "com.github.kevinsawicki:http-request:com.github.kevinsawicki.http.HttpRequest",
+        "project": "com.github.kevinsawicki:http-request",
+        "rule": "checkstyle:com.puppycrawl.tools.checkstyle.checks.coding.MagicNumberCheck",
+        "status": "RESOLVED",
+        "resolution": "FALSE-POSITIVE",
+        "severity": "MINOR",
+        "message": "'3' is a magic number.",
+        "line": 530,
+        "textRange": {
+          "startLine": 81,
+          "endLine": 81,
+          "startOffset": 0,
+          "endOffset": 134
+        },
+        "author": "Developer 1",
+        "debt": "2h1min",
+        "creationDate": "2013-05-13T17: 55: 39+0200",
+        "updateDate": "2013-05-13T17: 55: 39+0200",
+        "tags": [
+          "bug"
+        ],
+        "comments": [
+          {
+            "key": "7d7c56f5-7b5a-41b9-87f8-36fa70caa5ba",
+            "login": "john.smith",
+            "htmlText": "Must be &quot;final&quot;!",
+            "markdown": "Must be \"final\"!",
+            "updatable": false,
+            "createdAt": "2013-05-13T18: 08: 34+0200"
+          }
+        ],
+        "attr": {
+          "jira-issue-key": "SONAR-1234"
+        },
+        "transitions": [
+          "unconfirm",
+          "resolve",
+          "falsepositive"
+        ],
+        "actions": [
+          "comment"
+        ]
+      }
+    ],
+    "components": [
+      {
+        "key": "com.github.kevinsawicki:http-request:src/main/java/com/github/kevinsawicki/http/HttpRequest.java",
+        "enabled": true,
+        "qualifier": "FIL",
+        "name": "HttpRequest.java",
+        "longName": "src/main/java/com/github/kevinsawicki/http/HttpRequest.java",
+        "path": "src/main/java/com/github/kevinsawicki/http/HttpRequest.java"
+      },
+      {
+        "key": "com.github.kevinsawicki:http-request",
+        "enabled": true,
+        "qualifier": "TRK",
+        "name": "http-request",
+        "longName": "http-request"
+      }
+    ],
+    "rules": [
+      {
+        "key": "checkstyle:com.puppycrawl.tools.checkstyle.checks.coding.MagicNumberCheck",
+        "name": "Magic Number",
+        "status": "READY",
+        "lang": "java",
+        "langName": "Java"
+      }
+    ],
+    "users": [
+      {
+        "login": "admin",
+        "name": "Administrator",
+        "active": true,
+        "email": "admin@sonarqube.org"
+      }
+    ]
+  }
 }
index 46e70c7404b4c0f76cdefd669d4c6d7933cfd99f..b6836a277363d4c75521437d614b4b3160a62c7e 100644 (file)
@@ -83,6 +83,11 @@ public class ChangelogActionTest {
       "  \"total\": 1,\n" +
       "  \"p\": 1,\n" +
       "  \"ps\": 50,\n" +
+      "  \"paging\": {\n" +
+      "     \"pageIndex\": 1,\n" +
+      "     \"pageSize\": 50,\n" +
+      "     \"total\": 1\n" +
+      "  }," +
       "  \"events\": [\n" +
       "    {\n" +
       "      \"date\": \"" + DATE + "\",\n" +
@@ -168,14 +173,13 @@ public class ChangelogActionTest {
   @Test
   public void changelog_empty() {
     QProfileDto qualityProfile = db.qualityProfiles().insert();
-
     String response = ws.newRequest()
       .setParam(PARAM_LANGUAGE, qualityProfile.getLanguage())
       .setParam(PARAM_QUALITY_PROFILE, qualityProfile.getName())
       .execute()
       .getInput();
 
-    assertJson(response).isSimilarTo("{\"total\":0,\"p\":1,\"ps\":50,\"events\":[]}");
+    assertJson(response).isSimilarTo("{\"total\":0,\"p\":1,\"ps\":50,\"paging\":{\"pageIndex\":1,\"pageSize\":50,\"total\":0},\"events\":[]}");
   }
 
   @Test
@@ -315,7 +319,7 @@ public class ChangelogActionTest {
   }
 
   @Test
-  public void example() {
+  public void changelog_example() {
     QProfileDto profile = db.qualityProfiles().insert();
     String profileUuid = profile.getRulesProfileUuid();
 
@@ -343,15 +347,13 @@ public class ChangelogActionTest {
       .setChangeType(ActiveRuleChange.Type.ACTIVATED.name())
       .setData(ImmutableMap.of("severity", "MAJOR", "param_format", "^[A-Z][a-zA-Z0-9]*$", "ruleUuid", rule3.getUuid())));
 
-    String response = ws.newRequest()
+    ws.newRequest()
       .setMethod("GET")
       .setParam(PARAM_LANGUAGE, profile.getLanguage())
       .setParam(PARAM_QUALITY_PROFILE, profile.getName())
       .setParam("ps", "10")
       .execute()
-      .getInput();
-
-    assertJson(response).isSimilarTo(getClass().getResource("changelog-example.json"));
+      .assertJson(this.getClass(), "changelog_example.json");
   }
 
   @Test
index fc3326436799536a5ba75268cc366807b7c9caff..f2a7e1a94b511c669b1d0eb62179189f5222a44e 100644 (file)
@@ -161,6 +161,9 @@ public class SearchActionTest {
 
     assertThat(response.getTotal()).isZero();
     assertThat(response.getP()).isOne();
+    assertThat(response.getPaging().getTotal()).isZero();
+    assertThat(response.getPaging().getPageIndex()).isOne();
+    assertThat(response.getPaging().getPageSize()).isNotZero();
     assertThat(response.getRulesCount()).isZero();
   }
 
@@ -541,6 +544,8 @@ public class SearchActionTest {
       .setParam("f", "langName")
       .executeProtobuf(SearchResponse.class);
     assertThat(result.getTotal()).isOne();
+    assertThat(result.getPaging().getTotal()).isOne();
+    assertThat(result.getPaging().getPageIndex()).isOne();
     assertThat(result.getRulesCount()).isOne();
 
     Rule searchedRule = result.getRules(0);
@@ -564,6 +569,8 @@ public class SearchActionTest {
       .setParam("f", "debtRemFn,debtOverloaded,defaultDebtRemFn")
       .executeProtobuf(SearchResponse.class);
     assertThat(result.getTotal()).isOne();
+    assertThat(result.getPaging().getTotal()).isOne();
+    assertThat(result.getPaging().getPageIndex()).isOne();
     assertThat(result.getRulesCount()).isOne();
 
     Rule searchedRule = result.getRules(0);
@@ -596,6 +603,8 @@ public class SearchActionTest {
       .setParam("f", "debtRemFn,debtOverloaded,defaultDebtRemFn")
       .executeProtobuf(SearchResponse.class);
     assertThat(result.getTotal()).isOne();
+    assertThat(result.getPaging().getTotal()).isOne();
+    assertThat(result.getPaging().getPageIndex()).isOne();
     assertThat(result.getRulesCount()).isOne();
 
     Rule searchedRule = result.getRules(0);
@@ -628,6 +637,8 @@ public class SearchActionTest {
       .setParam("f", "debtRemFn,debtOverloaded,defaultDebtRemFn")
       .executeProtobuf(SearchResponse.class);
     assertThat(result.getTotal()).isOne();
+    assertThat(result.getPaging().getTotal()).isOne();
+    assertThat(result.getPaging().getPageIndex()).isOne();
     assertThat(result.getRulesCount()).isOne();
 
     Rule searchedRule = result.getRules(0);
@@ -658,6 +669,8 @@ public class SearchActionTest {
       .setParam("is_template", "true")
       .executeProtobuf(SearchResponse.class);
     assertThat(result.getTotal()).isOne();
+    assertThat(result.getPaging().getTotal()).isOne();
+    assertThat(result.getPaging().getPageIndex()).isOne();
     assertThat(result.getRulesCount()).isOne();
 
     Rule searchedRule = result.getRules(0);
@@ -680,6 +693,8 @@ public class SearchActionTest {
       .setParam("template_key", templateRule.getRepositoryKey() + ":" + templateRule.getRuleKey())
       .executeProtobuf(SearchResponse.class);
     assertThat(result.getTotal()).isOne();
+    assertThat(result.getPaging().getTotal()).isOne();
+    assertThat(result.getPaging().getPageIndex()).isOne();
     assertThat(result.getRulesCount()).isOne();
 
     Rule searchedRule = result.getRules(0);
@@ -696,6 +711,8 @@ public class SearchActionTest {
     SearchResponse result = ws.newRequest().executeProtobuf(SearchResponse.class);
 
     assertThat(result.getTotal()).isZero();
+    assertThat(result.getPaging().getTotal()).isZero();
+    assertThat(result.getPaging().getPageIndex()).isOne();
     assertThat(result.getRulesCount()).isZero();
   }
 
@@ -713,6 +730,8 @@ public class SearchActionTest {
       .setParam("activation", "true")
       .executeProtobuf(SearchResponse.class);
     assertThat(result.getTotal()).isOne();
+    assertThat(result.getPaging().getTotal()).isOne();
+    assertThat(result.getPaging().getPageIndex()).isOne();
     assertThat(result.getRulesCount()).isOne();
 
     Rule searchedRule = result.getRules(0);
@@ -756,6 +775,8 @@ public class SearchActionTest {
       .setParam("qprofile", profile.getKee())
       .executeProtobuf(SearchResponse.class);
     assertThat(result.getTotal()).isOne();
+    assertThat(result.getPaging().getTotal()).isOne();
+    assertThat(result.getPaging().getPageIndex()).isOne();
     assertThat(result.getRulesCount()).isOne();
     assertThat(result.getActives()).isNotNull();
     assertThat(result.getActives().getActives().get(rule.getKey().toString())).isNotNull();
@@ -811,6 +832,8 @@ public class SearchActionTest {
       .executeProtobuf(SearchResponse.class);
 
     assertThat(result.getTotal()).isOne();
+    assertThat(result.getPaging().getTotal()).isOne();
+    assertThat(result.getPaging().getPageIndex()).isOne();
     assertThat(result.getRulesCount()).isOne();
     assertThat(result.getActives()).isNotNull();
     assertThat(result.getActives().getActives().get(rule.getKey().toString())).isNotNull();
@@ -949,6 +972,20 @@ public class SearchActionTest {
       tuple(rule3.getKey().toString(), rule3.getStatus().name()));
   }
 
+  @Test
+  public void paging() {
+    for (int i = 0; i < 12; i++) {
+      db.rules().insert(r -> r.setLanguage("java"));
+    }
+    indexRules();
+
+    ws.newRequest()
+            .setParam(WebService.Param.PAGE, "2")
+            .setParam(WebService.Param.PAGE_SIZE, "9")
+            .execute()
+            .assertJson(this.getClass(), "paging.json");
+  }
+
   @Test
   public void compare_to_another_profile() {
     QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage(JAVA));
@@ -1009,11 +1046,14 @@ public class SearchActionTest {
     Rules.SearchResponse response = request.executeProtobuf(Rules.SearchResponse.class);
 
     assertThat(response.getP()).isOne();
+    assertThat(response.getPaging().getPageIndex()).isOne();
+    assertThat(response.getPaging().getPageSize()).isNotZero();
     RuleKey[] expectedRuleKeys = stream(expectedRules).map(RuleDto::getKey).collect(MoreCollectors.toList()).toArray(new RuleKey[0]);
     assertThat(response.getRulesList())
       .extracting(r -> RuleKey.parse(r.getKey()))
       .containsExactlyInAnyOrder(expectedRuleKeys);
     assertThat(response.getTotal()).isEqualTo(expectedRules.length);
+    assertThat(response.getPaging().getTotal()).isEqualTo(expectedRules.length);
     assertThat(response.getRulesCount()).isEqualTo(expectedRules.length);
   }
 
index 3e6e408f79b712ea38c87d989489da6c60f5f16d..f08ac493e655954b22d77f57e2a148b9e42a9a51 100644 (file)
@@ -61,6 +61,8 @@ public class UsersActionTest {
     assertThat(wsDef.since()).isEqualTo("5.2");
     assertThat(wsDef.isPost()).isFalse();
     assertThat(wsDef.changelog()).extracting(Change::getVersion, Change::getDescription).containsOnly(
+      tuple("9.8", "response fields 'total', 's', 'ps' have been deprecated, please use 'paging' object instead."),
+      tuple("9.8", "The field 'paging' has been added to the response."),
       tuple("8.4", "Parameter 'id' is deprecated. Format changes from integer to string. Use 'name' instead."));
   }
 
@@ -104,6 +106,11 @@ public class UsersActionTest {
     assertJson(result).isSimilarTo("{\n" +
       "  \"p\": 1,\n" +
       "  \"total\": 0,\n" +
+      "  \"paging\": {\n" +
+      "    \"pageIndex\": 1,\n" +
+      "    \"pageSize\": 25,\n" +
+      "    \"total\": 0\n" +
+      "  }," +
       "  \"users\": []\n" +
       "}");
   }
@@ -232,6 +239,11 @@ public class UsersActionTest {
         "  \"p\": 1,\n" +
         "  \"ps\": 1,\n" +
         "  \"total\": 2,\n" +
+        "  \"paging\": {\n" +
+        "    \"pageIndex\": 1,\n" +
+        "    \"pageSize\": 1,\n" +
+        "    \"total\": 2\n" +
+        "  }," +
         "  \"users\": [\n" +
         "    {\"login\": \"ada\", \"name\": \"Ada Lovelace\", \"selected\": true}\n" +
         "  ]\n" +
@@ -247,6 +259,11 @@ public class UsersActionTest {
         "  \"p\": 2,\n" +
         "  \"ps\": 1,\n" +
         "  \"total\": 2,\n" +
+        "  \"paging\": {\n" +
+        "    \"pageIndex\": 2,\n" +
+        "    \"pageSize\": 1,\n" +
+        "    \"total\": 2\n" +
+        "  }," +
         "  \"users\": [\n" +
         "    {\"login\": \"grace\", \"name\": \"Grace Hopper\", \"selected\": false}\n" +
         "  ]\n" +
index ce8bbfbeeb7039afd13b415678d6a62657d9fa89..5d7390f509ea274ec32e51076de5f7d0ac140803 100644 (file)
@@ -1,4 +1,9 @@
 {
   "total": 0,
-  "issues": []
+  "issues": [],
+  "paging": {
+    "pageIndex": 1,
+    "pageSize": 100,
+    "total": 0
+  }
 }
index d16592f64082c26e75670e924c320c3d0c4fc9ba..e9042aabbe7f001a708c73213a331baad77bfeb1 100644 (file)
@@ -1,5 +1,10 @@
 {
   "total": 12,
   "p": 2,
-  "ps": 9
+  "ps": 9,
+  "paging": {
+    "pageIndex": 2,
+    "pageSize": 9,
+    "total": 12
+  }
 }
diff --git a/server/sonar-webserver-webapi/src/test/resources/org/sonar/server/qualityprofile/ws/ChangelogActionTest/changelog_example.json b/server/sonar-webserver-webapi/src/test/resources/org/sonar/server/qualityprofile/ws/ChangelogActionTest/changelog_example.json
new file mode 100644 (file)
index 0000000..c40c1bb
--- /dev/null
@@ -0,0 +1,43 @@
+{
+  "total": 3,
+  "ps": 10,
+  "p": 1,
+  "paging": {
+    "pageSize": 10,
+    "total": 3,
+    "pageIndex": 1
+  },
+  "events": [
+    {
+      "date" : "2015-02-23T17:58:39+0100",
+      "action" : "ACTIVATED",
+      "authorLogin" : "anakin.skywalker",
+      "authorName" : "Anakin Skywalker",
+      "ruleKey" : "java:S2438",
+      "ruleName" : "\"Threads\" should not be used where \"Runnables\" are expected",
+      "params" : {
+        "severity" : "CRITICAL"
+      }
+    },
+    {
+      "date" : "2015-02-23T17:58:18+0100",
+      "action" : "DEACTIVATED",
+      "authorLogin" : "padme.amidala",
+      "authorName" : "Padme Amidala",
+      "ruleKey" : "java:S2162",
+      "ruleName" : "\"equals\" methods should be symmetric and work for subclasses"
+    },
+    {
+      "action" : "ACTIVATED",
+      "authorLogin" : "obiwan.kenobi",
+      "authorName" : "Obiwan Kenobi",
+      "ruleKey" : "java:S00101",
+      "ruleName" : "Class names should comply with a naming convention",
+      "date" : "2014-09-12T15:20:46+0200",
+      "params" : {
+        "severity" : "MAJOR",
+        "format" : "^[A-Z][a-zA-Z0-9]*$"
+      }
+    }
+  ]
+}
index e109ed28cc87826e1ab8f6687095dc9420a875da..20697e5b8ecca6ab77dfe1b0ba0f153967d80174 100644 (file)
@@ -1,11 +1,20 @@
-{"total": 1, "p": 1, "ps": 100, "rules": [
-  {
-    "key": "xoo:x1",
-    "sysTags": ["tag1"],
-    "tags": []
-  }
-],
-"facets": [
+{
+  "total": 1,
+  "p": 1,
+  "ps": 100,
+  "paging": {
+    "pageIndex": 1,
+    "pageSize": 100,
+    "total": 1
+  },
+  "rules": [
+    {
+      "key": "xoo:x1",
+      "sysTags": ["tag1"],
+      "tags": []
+    }
+  ],
+  "facets": [
   {
     "property": "tags",
     "values": [
index 68a29b47e6552bcd4d81702079b5a61e21a7cb2d..fcee129b4b13c7ef3587cfcfaa614fa0e1ecb1d8 100644 (file)
@@ -1,5 +1,12 @@
 {
-  "total": 1, "p": 1, "ps": 100,
+  "total": 1,
+  "p": 1,
+  "ps": 100,
+  "paging": {
+    "pageIndex": 1,
+    "pageSize": 100,
+    "total": 1
+  },
   "rules": [
     {
       "key": "xoo:x1",
index 315359d66f96c3ee5ddf1c1640a4a66523cee280..cd8c7024d555d7cf65c4e783fb0e6a5846b4d9d5 100644 (file)
@@ -2,6 +2,11 @@
   "total": 2,
   "p": 1,
   "ps": 100,
+  "paging": {
+    "pageIndex": 1,
+    "pageSize": 100,
+    "total": 2
+  },
   "rules": [
     {
       "key": "xoo:x2",
index 30c6468a86b8b05c70acd02b734f52e4c2302a9f..404203e522f739b60b7a0ce5a3defb9241a12238 100644 (file)
@@ -2,6 +2,11 @@
   "total": 2,
   "p": 1,
   "ps": 100,
+  "paging": {
+    "pageIndex": 1,
+    "pageSize": 100,
+    "total": 2
+  },
   "rules": [
     {
       "key": "xoo:x2",
index 76e721d0b858e9ef3e1293b643581aa6e07236cc..fdc460c739dc75b7d1888ee50175cab8775d4d7d 100644 (file)
@@ -1,5 +1,12 @@
 {
-  "total": 1, "p": 1, "ps": 100,
+  "total": 1,
+  "p": 1,
+  "ps": 100,
+  "paging": {
+    "pageIndex": 1,
+    "pageSize": 100,
+    "total": 2
+  },
   "rules": [
     {
       "key": "xoo:x1"
index ac69b2e9ea7299e6dc52c75749f979a883234c86..2fce4c1f7be94d9908de65ab87b233025e3e5063 100644 (file)
@@ -1,4 +1,13 @@
-{"total": 1, "p": 1, "ps": 100, "rules": [
+{
+  "total": 1,
+  "p": 1,
+  "ps": 100,
+  "paging": {
+    "pageIndex": 1,
+    "pageSize": 100,
+    "total": 1
+  },
+  "rules": [
   {
     "key": "xoo:x1",
     "remFnType": "LINEAR_OFFSET",
index d744e2ed7da93e01521565d06b71feddc2a5d204..435010e807cc12e2c7d3ea73ac7ed75f36932427 100644 (file)
@@ -1,11 +1,21 @@
-{"total": 1, "p": 1, "ps": 100, "rules": [
-  {
-    "key": "xoo:x1",
-    "remFnType": "CONSTANT_ISSUE",
-    "remFnBaseEffort": "5min",
-    "debtOverloaded": true,
-    "defaultRemFnType": "LINEAR_OFFSET",
-    "defaultRemFnGapMultiplier": "1h",
-    "defaultRemFnBaseEffort": "15min"
-  }
-]}
+{
+  "total": 1,
+  "p": 1,
+  "ps": 100,
+  "paging": {
+    "pageIndex": 1,
+    "pageSize": 100,
+    "total": 1
+  },
+  "rules": [
+    {
+      "key": "xoo:x1",
+      "remFnType": "CONSTANT_ISSUE",
+      "remFnBaseEffort": "5min",
+      "debtOverloaded": true,
+      "defaultRemFnType": "LINEAR_OFFSET",
+      "defaultRemFnGapMultiplier": "1h",
+      "defaultRemFnBaseEffort": "15min"
+    }
+  ]
+}
index 0e7286cf282a7c77fd13308763b86542df9b8995..f62d34353362b88a08f72ef6e93a84a5b8c41444 100644 (file)
@@ -2,6 +2,11 @@
     "total": 0,
     "p": 1,
     "ps": 100,
+    "paging": {
+        "pageIndex": 1,
+        "pageSize": 100,
+        "total": 99999
+    },
     "rules": [],
     "actives": {},
     "qProfiles": {}
diff --git a/server/sonar-webserver-webapi/src/test/resources/org/sonar/server/rule/ws/SearchActionTest/paging.json b/server/sonar-webserver-webapi/src/test/resources/org/sonar/server/rule/ws/SearchActionTest/paging.json
new file mode 100644 (file)
index 0000000..e9042aa
--- /dev/null
@@ -0,0 +1,10 @@
+{
+  "total": 12,
+  "p": 2,
+  "ps": 9,
+  "paging": {
+    "pageIndex": 2,
+    "pageSize": 9,
+    "total": 12
+  }
+}
index 7ec1c827f9f91dbec20c19d852459e62a2fbfa58..96c6fb6479780d1ed7e3bb987052e2cb00788cf2 100644 (file)
@@ -41,13 +41,15 @@ message ListResponse {
 
 // WS api/rules/search
 message SearchResponse {
-  optional int64 total = 1;
-  optional int32 p = 2;
-  optional int64 ps = 3;
+  optional int64 total = 1 [deprecated=true];
+  optional int32 p = 2 [deprecated=true];
+  optional int64 ps = 3 [deprecated=true];
+
   repeated Rule rules = 4;
   optional Actives actives = 5;
   optional QProfiles qProfiles = 6;
   optional sonarqube.ws.commons.Facets facets = 7;
+  optional sonarqube.ws.commons.Paging paging = 8;
 }
 
 //WS api/rules/show