aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins CI <ci@sonarsource.com>2016-04-21 08:01:09 +0200
committerJenkins CI <ci@sonarsource.com>2016-04-21 08:01:09 +0200
commit91584ca578a35442467d075ec42151b409778503 (patch)
tree3e1ea4ea59a2d4e4d05de51affca73172fe65f78
parent6c65ff90687ebe7d184864b0d665f8a51aecfc7a (diff)
parent9d70ff56e7d45ca6d26ee5725cdea6288585358b (diff)
downloadsonarqube-91584ca578a35442467d075ec42151b409778503.tar.gz
sonarqube-91584ca578a35442467d075ec42151b409778503.zip
Automatic merge from branch-5.5
* origin/branch-5.5: SONAR-7553 use api/ce/activity_status to get number of pending and failing tasks SONAR-7553 WS api/ce/activity_status display background tasks related metrics for UI SONAR-7553 DAO of CE_QUEUE count number of rows by status SONAR-7553 DAO of CE_ACTIVITY count number of tasks still failing SONAR-7187 WS api/ce/activity stop using count(1) on DB table CE_QUEUE SONAR-7553 Create composite DB index CE_ACTIVITY(is_last, status) SONAR-7187 do not usage pagination SONAR-7187 Remove paging from api/ce/activity
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityAction.java75
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityStatusAction.java127
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWsModule.java1
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/ce/ws/activity_status-example.json4
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java23
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityStatusActionTest.java191
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/ce/ws/CeWsModuleTest.java3
-rw-r--r--server/sonar-web/src/main/js/api/ce.js9
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js2
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/containers/ListFooterContainer.js34
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/store/actions.js23
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/store/reducers.js4
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1125_add_index_ce_activity_islast_status.rb31
-rw-r--r--sonar-db/src/main/java/org/sonar/db/ce/CeActivityDao.java8
-rw-r--r--sonar-db/src/main/java/org/sonar/db/ce/CeActivityMapper.java3
-rw-r--r--sonar-db/src/main/java/org/sonar/db/ce/CeQueueDao.java12
-rw-r--r--sonar-db/src/main/java/org/sonar/db/ce/CeQueueMapper.java4
-rw-r--r--sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java2
-rw-r--r--sonar-db/src/main/resources/org/sonar/db/ce/CeActivityMapper.xml15
-rw-r--r--sonar-db/src/main/resources/org/sonar/db/ce/CeQueueMapper.xml9
-rw-r--r--sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql1
-rw-r--r--sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl4
-rw-r--r--sonar-db/src/test/java/org/sonar/db/DbTester.java2
-rw-r--r--sonar-db/src/test/java/org/sonar/db/ce/CeActivityDaoTest.java66
-rw-r--r--sonar-db/src/test/java/org/sonar/db/ce/CeQueueDaoTest.java43
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java9
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/ce/ActivityStatusWsRequest.java71
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeService.java10
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeWsParameters.java1
-rw-r--r--sonar-ws/src/main/protobuf/ws-ce.proto9
30 files changed, 597 insertions, 199 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityAction.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityAction.java
index 69781bece76..1a15334bd80 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityAction.java
@@ -37,8 +37,8 @@ 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.DateUtils;
-import org.sonar.api.utils.Paging;
import org.sonar.api.web.UserRole;
+import org.sonar.ce.taskprocessor.CeTaskProcessor;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.util.Uuids;
import org.sonar.db.DbClient;
@@ -50,10 +50,8 @@ import org.sonar.db.ce.CeTaskTypes;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentDtoFunctions;
import org.sonar.db.component.ComponentQuery;
-import org.sonar.ce.taskprocessor.CeTaskProcessor;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.user.UserSession;
-import org.sonarqube.ws.Common;
import org.sonarqube.ws.WsCe;
import org.sonarqube.ws.WsCe.ActivityResponse;
import org.sonarqube.ws.client.ce.ActivityWsRequest;
@@ -63,7 +61,6 @@ import static java.util.Collections.singletonList;
import static org.apache.commons.lang.StringUtils.defaultString;
import static org.sonar.api.utils.DateUtils.parseDateQuietly;
import static org.sonar.api.utils.DateUtils.parseDateTimeQuietly;
-import static org.sonar.api.utils.Paging.offset;
import static org.sonar.server.ws.WsUtils.checkRequest;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_ID;
@@ -75,6 +72,7 @@ import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_STATUS;
import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_TYPE;
public class ActivityAction implements CeWsAction {
+ private static final int OFFSET = 0;
private static final int MAX_PAGE_SIZE = 1000;
private final UserSession userSession;
@@ -98,7 +96,8 @@ public class ActivityAction implements CeWsAction {
WebService.NewAction action = controller.createAction("activity")
.setDescription(format("Search for tasks.<br> " +
"Requires the system administration permission, " +
- "or project administration permission if %s is set.", PARAM_COMPONENT_ID))
+ "or project administration permission if %s is set.<br/>" +
+ "Since 5.5, it's no more possible to specify the page parameter", PARAM_COMPONENT_ID))
.setResponseExample(getClass().getResource("activity-example.json"))
.setHandler(this)
.setSince("5.2");
@@ -147,7 +146,11 @@ public class ActivityAction implements CeWsAction {
action.createParam(PARAM_MAX_EXECUTED_AT)
.setDescription("Maximum date of end of task processing (inclusive)")
.setExampleValue(DateUtils.formatDateTime(new Date()));
- action.addPagingParams(100, MAX_PAGE_SIZE);
+ action.createParam(Param.PAGE)
+ .setDescription("Deprecated parameter")
+ .setDeprecatedSince("5.5")
+ .setDeprecatedKey("pageIndex");
+ action.addPageSize(100, MAX_PAGE_SIZE);
}
@Override
@@ -165,21 +168,18 @@ public class ActivityAction implements CeWsAction {
return buildResponse(
singletonList(taskSearchedById.get()),
Collections.<WsCe.Task>emptyList(),
- Paging.forPageIndex(1).withPageSize(request.getPageSize()).andTotal(1));
+ request.getPageSize());
}
CeTaskQuery query = buildQuery(dbSession, request);
checkPermissions(query);
- TaskResult queuedTasks = loadQueuedTasks(dbSession, request, query);
- TaskResult pastTasks = loadPastTasks(dbSession, request, query, queuedTasks.total);
+ Iterable<WsCe.Task> queuedTasks = loadQueuedTasks(dbSession, request, query);
+ Iterable<WsCe.Task> pastTasks = loadPastTasks(dbSession, request, query);
return buildResponse(
- queuedTasks.tasks,
- pastTasks.tasks,
- Paging.forPageIndex(request.getPage())
- .withPageSize(request.getPageSize())
- .andTotal(queuedTasks.total + pastTasks.total));
-
+ queuedTasks,
+ pastTasks,
+ request.getPageSize());
} finally {
dbClient.closeSession(dbSession);
}
@@ -234,24 +234,14 @@ public class ActivityAction implements CeWsAction {
}
}
- private TaskResult loadQueuedTasks(DbSession dbSession, ActivityWsRequest request, CeTaskQuery query) {
- int total = dbClient.ceQueueDao().countByQuery(dbSession, query);
- List<CeQueueDto> dtos = dbClient.ceQueueDao().selectByQueryInDescOrder(dbSession, query,
- Paging.forPageIndex(request.getPage())
- .withPageSize(request.getPageSize())
- .andTotal(total));
- Iterable<WsCe.Task> tasks = formatter.formatQueue(dbSession, dtos);
- return new TaskResult(tasks, total);
+ private Iterable<WsCe.Task> loadQueuedTasks(DbSession dbSession, ActivityWsRequest request, CeTaskQuery query) {
+ List<CeQueueDto> dtos = dbClient.ceQueueDao().selectByQueryInDescOrder(dbSession, query, request.getPageSize());
+ return formatter.formatQueue(dbSession, dtos);
}
- private TaskResult loadPastTasks(DbSession dbSession, ActivityWsRequest request, CeTaskQuery query, int totalQueuedTasks) {
- int total = dbClient.ceActivityDao().countByQuery(dbSession, query);
- // we have to take into account the total number of queue tasks found
- int offset = Math.max(0, offset(request.getPage(), request.getPageSize()) - totalQueuedTasks);
- List<CeActivityDto> dtos = dbClient.ceActivityDao().selectByQuery(dbSession, query, offset, request.getPageSize());
- Iterable<WsCe.Task> ceTasks = formatter.formatActivity(dbSession, dtos);
-
- return new TaskResult(ceTasks, total);
+ private Iterable<WsCe.Task> loadPastTasks(DbSession dbSession, ActivityWsRequest request, CeTaskQuery query) {
+ List<CeActivityDto> dtos = dbClient.ceActivityDao().selectByQuery(dbSession, query, OFFSET, request.getPageSize());
+ return formatter.formatActivity(dbSession, dtos);
}
private void checkPermissions(CeTaskQuery query) {
@@ -285,29 +275,23 @@ public class ActivityAction implements CeWsAction {
return userSession.hasPermission(GlobalPermissions.SYSTEM_ADMIN) || userSession.hasComponentUuidPermission(UserRole.ADMIN, componentUuid);
}
- private static ActivityResponse buildResponse(Iterable<WsCe.Task> queuedTasks, Iterable<WsCe.Task> pastTasks, Paging paging) {
+ private static ActivityResponse buildResponse(Iterable<WsCe.Task> queuedTasks, Iterable<WsCe.Task> pastTasks, int pageSize) {
WsCe.ActivityResponse.Builder wsResponseBuilder = WsCe.ActivityResponse.newBuilder();
int nbInsertedTasks = 0;
for (WsCe.Task queuedTask : queuedTasks) {
- if (nbInsertedTasks < paging.pageSize()) {
+ if (nbInsertedTasks < pageSize) {
wsResponseBuilder.addTasks(queuedTask);
nbInsertedTasks++;
}
}
for (WsCe.Task pastTask : pastTasks) {
- if (nbInsertedTasks < paging.pageSize()) {
+ if (nbInsertedTasks < pageSize) {
wsResponseBuilder.addTasks(pastTask);
nbInsertedTasks++;
}
}
-
- wsResponseBuilder.setPaging(Common.Paging.newBuilder()
- .setPageIndex(paging.pageIndex())
- .setPageSize(paging.pageSize())
- .setTotal(paging.total()));
-
return wsResponseBuilder.build();
}
@@ -320,7 +304,6 @@ public class ActivityAction implements CeWsAction {
.setMinSubmittedAt(request.param(PARAM_MIN_SUBMITTED_AT))
.setMaxExecutedAt(request.param(PARAM_MAX_EXECUTED_AT))
.setOnlyCurrents(request.paramAsBoolean(PARAM_ONLY_CURRENTS))
- .setPage(request.mandatoryParamAsInt(Param.PAGE))
.setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE));
checkRequest(activityWsRequest.getComponentId() == null || activityWsRequest.getQuery() == null, "%s and %s must not be set at the same time",
@@ -329,14 +312,4 @@ public class ActivityAction implements CeWsAction {
return activityWsRequest;
}
-
- private static class TaskResult {
- private final Iterable<WsCe.Task> tasks;
- private final int total;
-
- private TaskResult(Iterable<WsCe.Task> tasks, int total) {
- this.tasks = tasks;
- this.total = total;
- }
- }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityStatusAction.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityStatusAction.java
new file mode 100644
index 00000000000..b8e09db8b56
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/ActivityStatusAction.java
@@ -0,0 +1,127 @@
+/*
+ * 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.ce.ws;
+
+import com.google.common.base.Optional;
+import javax.annotation.Nullable;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.util.Uuids;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.user.UserSession;
+import org.sonar.server.ws.KeyExamples;
+import org.sonarqube.ws.WsCe.ActivityStatusWsResponse;
+import org.sonarqube.ws.client.ce.ActivityStatusWsRequest;
+
+import static org.sonar.server.component.ComponentFinder.ParamNames.COMPONENT_ID_AND_KEY;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_ID;
+import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_KEY;
+
+public class ActivityStatusAction implements CeWsAction {
+ private final UserSession userSession;
+ private final DbClient dbClient;
+ private final ComponentFinder componentFinder;
+
+ public ActivityStatusAction(UserSession userSession, DbClient dbClient, ComponentFinder componentFinder) {
+ this.userSession = userSession;
+ this.dbClient = dbClient;
+ this.componentFinder = componentFinder;
+ }
+
+ @Override
+ public void define(WebService.NewController controller) {
+ WebService.NewAction action = controller
+ .createAction("activity_status")
+ .setDescription("Return CE activity related metrics.<br>" +
+ "Requires 'Administer System' permission or 'Administer' rights on the specified project.")
+ .setSince("5.5")
+ .setResponseExample(getClass().getResource("activity_status-example.json"))
+ .setInternal(true)
+ .setHandler(this);
+
+ action.createParam(PARAM_COMPONENT_ID)
+ .setDescription("Id of the component (project) to filter on")
+ .setExampleValue(Uuids.UUID_EXAMPLE_03);
+ action.createParam(PARAM_COMPONENT_KEY)
+ .setDescription("Key of the component (project) to filter on")
+ .setExampleValue(KeyExamples.KEY_PROJECT_EXAMPLE_001);
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ ActivityStatusWsResponse activityStatusResponse = doHandle(toWsRequest(request));
+ writeProtobuf(activityStatusResponse, request, response);
+ }
+
+ private ActivityStatusWsResponse doHandle(ActivityStatusWsRequest request) {
+ DbSession dbSession = dbClient.openSession(false);
+ try {
+ Optional<ComponentDto> component = searchComponent(dbSession, request);
+ String componentUuid = component.isPresent() ? component.get().uuid() : null;
+ checkPermissions(componentUuid);
+ int pendingCount = dbClient.ceQueueDao().countByStatusAndComponentUuid(dbSession, CeQueueDto.Status.PENDING, componentUuid);
+ int failingCount = dbClient.ceActivityDao().countLastByStatusAndComponentUuid(dbSession, CeActivityDto.Status.FAILED, componentUuid);
+
+ return ActivityStatusWsResponse.newBuilder()
+ .setPending(pendingCount)
+ .setFailing(failingCount)
+ .build();
+ } finally {
+ dbClient.closeSession(dbSession);
+ }
+ }
+
+ private Optional<ComponentDto> searchComponent(DbSession dbSession, ActivityStatusWsRequest request) {
+ ComponentDto component = null;
+ if (hasComponentInRequest(request)) {
+ component = componentFinder.getByUuidOrKey(dbSession, request.getComponentId(), request.getComponentKey(), COMPONENT_ID_AND_KEY);
+ }
+ return Optional.fromNullable(component);
+ }
+
+ private void checkPermissions(@Nullable String componentUuid) {
+ if (componentUuid == null) {
+ userSession.checkPermission(GlobalPermissions.SYSTEM_ADMIN);
+ } else {
+ userSession.checkComponentUuidPermission(UserRole.ADMIN, componentUuid);
+ }
+ }
+
+ private static boolean hasComponentInRequest(ActivityStatusWsRequest request) {
+ return request.getComponentId() != null || request.getComponentKey() != null;
+ }
+
+ private static ActivityStatusWsRequest toWsRequest(Request request) {
+ return ActivityStatusWsRequest.newBuilder()
+ .setComponentId(request.param(PARAM_COMPONENT_ID))
+ .setComponentKey(request.param(PARAM_COMPONENT_KEY))
+ .build();
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWsModule.java
index 73b04cf18ba..ac527405405 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWsModule.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/ce/ws/CeWsModule.java
@@ -27,6 +27,7 @@ public class CeWsModule extends Module {
add(
CeWs.class,
ActivityAction.class,
+ ActivityStatusAction.class,
CancelAction.class,
CancelAllAction.class,
IsQueueEmptyWs.class,
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/activity_status-example.json b/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/activity_status-example.json
new file mode 100644
index 00000000000..c57d76edd38
--- /dev/null
+++ b/server/sonar-server/src/main/resources/org/sonar/server/ce/ws/activity_status-example.json
@@ -0,0 +1,4 @@
+{
+ "pending": 2,
+ "failing": 5
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java
index 59b6d464533..eeb4690492e 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityActionTest.java
@@ -34,15 +34,15 @@ import org.junit.rules.ExpectedException;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
+import org.sonar.ce.log.CeLogging;
+import org.sonar.ce.log.LogFileRef;
+import org.sonar.ce.taskprocessor.CeTaskProcessor;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbTester;
import org.sonar.db.ce.CeActivityDto;
import org.sonar.db.ce.CeQueueDto;
import org.sonar.db.ce.CeTaskTypes;
import org.sonar.db.component.ComponentDbTester;
-import org.sonar.ce.log.CeLogging;
-import org.sonar.ce.log.LogFileRef;
-import org.sonar.ce.taskprocessor.CeTaskProcessor;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
@@ -169,28 +169,23 @@ public class ActivityActionTest {
}
@Test
- public void paginate_results() {
+ public void limit_results() {
userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
insertActivity("T1", "PROJECT_1", CeActivityDto.Status.SUCCESS);
insertActivity("T2", "PROJECT_2", CeActivityDto.Status.FAILED);
insertQueue("T3", "PROJECT_1", CeQueueDto.Status.IN_PROGRESS);
- assertPage(1, 1, 3, asList("T3"));
- assertPage(2, 1, 3, asList("T2"));
- assertPage(1, 10, 3, asList("T3", "T2", "T1"));
- assertPage(2, 10, 3, Collections.<String>emptyList());
+ assertPage(1, asList("T3"));
+ assertPage(2, asList("T3", "T2"));
+ assertPage(10, asList("T3", "T2", "T1"));
+ assertPage(0, Collections.<String>emptyList());
}
- private void assertPage(int pageIndex, int pageSize, int expectedTotal, List<String> expectedOrderedTaskIds) {
+ private void assertPage(int pageSize, List<String> expectedOrderedTaskIds) {
ActivityResponse activityResponse = call(ws.newRequest()
- .setParam(Param.PAGE, Integer.toString(pageIndex))
.setParam(Param.PAGE_SIZE, Integer.toString(pageSize))
.setParam(PARAM_STATUS, "SUCCESS,FAILED,CANCELED,IN_PROGRESS,PENDING"));
- assertThat(activityResponse.getPaging().getPageIndex()).isEqualTo(pageIndex);
- assertThat(activityResponse.getPaging().getPageSize()).isEqualTo(pageSize);
- assertThat(activityResponse.getPaging().getTotal()).isEqualTo(expectedTotal);
-
assertThat(activityResponse.getTasksCount()).isEqualTo(expectedOrderedTaskIds.size());
for (int i = 0; i < expectedOrderedTaskIds.size(); i++) {
String expectedTaskId = expectedOrderedTaskIds.get(i);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityStatusActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityStatusActionTest.java
new file mode 100644
index 00000000000..ad438ce56a4
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/ActivityStatusActionTest.java
@@ -0,0 +1,191 @@
+/*
+ * 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.ce.ws;
+
+import com.google.common.base.Throwables;
+import java.io.IOException;
+import javax.annotation.Nullable;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.util.Uuids;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.ce.CeActivityDto;
+import org.sonar.db.ce.CeQueueDto;
+import org.sonar.db.component.ComponentDbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.WsActionTester;
+import org.sonarqube.ws.MediaTypes;
+import org.sonarqube.ws.WsCe;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.db.ce.CeQueueTesting.newCeQueueDto;
+import static org.sonar.db.component.ComponentTesting.newProjectDto;
+import static org.sonar.test.JsonAssert.assertJson;
+import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_ID;
+import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_KEY;
+
+public class ActivityStatusActionTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
+ @Rule
+ public DbTester db = DbTester.create(System2.INSTANCE);
+ ComponentDbTester componentDb = new ComponentDbTester(db);
+ DbClient dbClient = db.getDbClient();
+ DbSession dbSession = db.getSession();
+
+ WsActionTester ws = new WsActionTester(new ActivityStatusAction(userSession, dbClient, new ComponentFinder(dbClient)));
+
+ @Before
+ public void setUp() {
+ userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+ }
+
+ @Test
+ public void json_example() {
+ dbClient.ceQueueDao().insert(dbSession, newCeQueueDto("ce-queue-uuid-1").setStatus(CeQueueDto.Status.PENDING));
+ dbClient.ceQueueDao().insert(dbSession, newCeQueueDto("ce-queue-uuid-2").setStatus(CeQueueDto.Status.PENDING));
+ for (int i = 0; i < 5; i++) {
+ dbClient.ceActivityDao().insert(dbSession, new CeActivityDto(newCeQueueDto("ce-activity-uuid-" + i))
+ .setStatus(CeActivityDto.Status.FAILED));
+ }
+ db.commit();
+
+ String result = ws.newRequest().execute().getInput();
+
+ assertJson(result).isSimilarTo(getClass().getResource("activity_status-example.json"));
+ }
+
+ @Test
+ public void status_for_a_project_as_project_admin() {
+ String projectUuid = "project-uuid";
+ String anotherProjectUuid = "another-project-uuid";
+ userSession.login().addProjectUuidPermissions(UserRole.ADMIN, projectUuid);
+ componentDb.insertComponent(newProjectDto(projectUuid));
+ componentDb.insertComponent(newProjectDto(anotherProjectUuid));
+ // pending tasks returned
+ insertInQueue(CeQueueDto.Status.PENDING, projectUuid);
+ insertInQueue(CeQueueDto.Status.PENDING, projectUuid);
+ // other tasks not returned
+ insertInQueue(CeQueueDto.Status.IN_PROGRESS, projectUuid);
+ insertInQueue(CeQueueDto.Status.PENDING, anotherProjectUuid);
+ insertInQueue(CeQueueDto.Status.PENDING, null);
+ // only one last activity for a given project
+ insertActivity(CeActivityDto.Status.SUCCESS, projectUuid);
+ insertActivity(CeActivityDto.Status.CANCELED, projectUuid);
+ insertActivity(CeActivityDto.Status.FAILED, projectUuid);
+ insertActivity(CeActivityDto.Status.FAILED, projectUuid);
+ insertActivity(CeActivityDto.Status.FAILED, anotherProjectUuid);
+
+ WsCe.ActivityStatusWsResponse result = call(projectUuid);
+
+ assertThat(result.getPending()).isEqualTo(2);
+ assertThat(result.getFailing()).isEqualTo(1);
+ }
+
+ @Test
+ public void empty_status() {
+ WsCe.ActivityStatusWsResponse result = call();
+
+ assertThat(result.getPending()).isEqualTo(0);
+ assertThat(result.getFailing()).isEqualTo(0);
+ }
+
+ @Test
+ public void fail_if_component_uuid_and_key_are_provided() {
+ ComponentDto project = newProjectDto();
+ componentDb.insertComponent(project);
+ expectedException.expect(IllegalArgumentException.class);
+
+ callByComponentUuidOrComponentKey(project.uuid(), project.key());
+ }
+
+ @Test
+ public void fail_if_component_uuid_is_unknown() {
+ expectedException.expect(NotFoundException.class);
+
+ call("unknown-uuid");
+ }
+
+ @Test
+ public void fail_if_component_key_is_unknown() {
+ expectedException.expect(NotFoundException.class);
+
+ callByComponentKey("unknown-key");
+ }
+
+ private void insertInQueue(CeQueueDto.Status status, @Nullable String componentUuid) {
+ dbClient.ceQueueDao().insert(dbSession, newCeQueueDto(Uuids.createFast())
+ .setStatus(status)
+ .setComponentUuid(componentUuid));
+ db.commit();
+ }
+
+ private void insertActivity(CeActivityDto.Status status, @Nullable String componentUuid) {
+ dbClient.ceActivityDao().insert(dbSession, new CeActivityDto(
+ newCeQueueDto(Uuids.createFast())
+ .setComponentUuid(componentUuid))
+ .setStatus(status));
+ db.commit();
+ }
+
+ private WsCe.ActivityStatusWsResponse call() {
+ return callByComponentUuidOrComponentKey(null, null);
+ }
+
+ private WsCe.ActivityStatusWsResponse call(String componentUuid) {
+ return callByComponentUuidOrComponentKey(componentUuid, null);
+ }
+
+ private WsCe.ActivityStatusWsResponse callByComponentKey(String componentKey) {
+ return callByComponentUuidOrComponentKey(null, componentKey);
+ }
+
+ private WsCe.ActivityStatusWsResponse callByComponentUuidOrComponentKey(@Nullable String componentUuid, @Nullable String componentKey) {
+ TestRequest request = ws.newRequest()
+ .setMediaType(MediaTypes.PROTOBUF);
+ if (componentUuid != null) {
+ request.setParam(PARAM_COMPONENT_ID, componentUuid);
+ }
+ if (componentKey != null) {
+ request.setParam(PARAM_COMPONENT_KEY, componentKey);
+ }
+
+ try {
+ return WsCe.ActivityStatusWsResponse.parseFrom(request.execute().getInputStream());
+ } catch (IOException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/CeWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/CeWsModuleTest.java
index 75eb84a98e0..ddcd9422a37 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/ce/ws/CeWsModuleTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/ce/ws/CeWsModuleTest.java
@@ -21,7 +21,6 @@ package org.sonar.server.ce.ws;
import org.junit.Test;
import org.sonar.core.platform.ComponentContainer;
-import org.sonar.server.ce.ws.CeWsModule;
import static org.assertj.core.api.Assertions.assertThat;
@@ -31,6 +30,6 @@ public class CeWsModuleTest {
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new CeWsModule().configure(container);
- assertThat(container.size()).isEqualTo(11 + 2 /* injected by ComponentContainer */);
+ assertThat(container.size()).isEqualTo(12 + 2 /* injected by ComponentContainer */);
}
}
diff --git a/server/sonar-web/src/main/js/api/ce.js b/server/sonar-web/src/main/js/api/ce.js
index e46eb236026..66c6b3dc8ab 100644
--- a/server/sonar-web/src/main/js/api/ce.js
+++ b/server/sonar-web/src/main/js/api/ce.js
@@ -30,6 +30,15 @@ export function getActivity (data) {
return $.get(url, data);
}
+export function getStatus (componentId) {
+ const url = window.baseUrl + '/api/ce/activity_status';
+ const data = {};
+ if (componentId) {
+ Object.assign(data, { componentId });
+ }
+ return getJSON(url, data);
+}
+
export function getTask (id) {
const url = window.baseUrl + '/api/ce/task';
return getJSON(url, { id }).then(r => r.task);
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js b/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js
index 3e2ec7e3510..aa9515725fd 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js
@@ -25,7 +25,6 @@ import Header from './Header';
import StatsContainer from '../containers/StatsContainer';
import SearchContainer from '../containers/SearchContainer';
import TasksContainer from '../containers/TasksContainer';
-import ListFooterContainer from '../containers/ListFooterContainer';
export default class BackgroundTasksApp extends Component {
componentDidMount () {
@@ -69,7 +68,6 @@ export default class BackgroundTasksApp extends Component {
<StatsContainer/>
<SearchContainer/>
<TasksContainer/>
- <ListFooterContainer/>
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/containers/ListFooterContainer.js b/server/sonar-web/src/main/js/apps/background-tasks/containers/ListFooterContainer.js
deleted file mode 100644
index 048068f63f5..00000000000
--- a/server/sonar-web/src/main/js/apps/background-tasks/containers/ListFooterContainer.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.
- */
-import { connect } from 'react-redux';
-
-import ListFooter from '../../../components/shared/list-footer';
-
-function mapStateToProps (state) {
- return {
- ready: !state.fetching,
- total: state.total,
- count: state.tasks.length
- };
-}
-
-export default connect(
- mapStateToProps
-)(ListFooter);
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/store/actions.js b/server/sonar-web/src/main/js/apps/background-tasks/store/actions.js
index b3d54560da2..095f659f0ca 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/store/actions.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/store/actions.js
@@ -18,12 +18,10 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import _ from 'underscore';
-import { getTypes, getActivity, cancelAllTasks, cancelTask as cancelTaskAPI } from '../../../api/ce';
+import { getTypes, getActivity, getStatus, cancelAllTasks, cancelTask as cancelTaskAPI } from '../../../api/ce';
import { STATUSES, ALL_TYPES, CURRENTS, DEBOUNCE_DELAY } from '../constants';
-const PAGE_SIZE = 1000;
-
export const INIT = 'INIT';
export const REQUEST_TASKS = 'REQUEST_TASKS';
export const RECEIVE_TASKS = 'RECEIVE_TASKS';
@@ -48,11 +46,10 @@ export function requestTasks (filters) {
};
}
-export function receiveTasks (tasks, total) {
+export function receiveTasks (tasks) {
return {
type: RECEIVE_TASKS,
- tasks,
- total
+ tasks
};
}
@@ -145,8 +142,6 @@ function fetchTasks (filters) {
const { component } = getState();
const parameters = mapFiltersToParameters(filters);
- parameters.ps = PAGE_SIZE;
-
if (component) {
parameters.componentId = component.id;
}
@@ -155,17 +150,15 @@ function fetchTasks (filters) {
return Promise.all([
getActivity(parameters),
- getActivity({ ps: 1, onlyCurrents: true, status: STATUSES.FAILED }),
- getActivity({ ps: 1, status: STATUSES.PENDING })
+ getStatus(parameters.componentId)
]).then(responses => {
- const [activity, failingActivity, pendingActivity] = responses;
+ const [activity, status] = responses;
const tasks = activity.tasks;
- const total = activity.paging.total;
- dispatch(receiveTasks(tasks, total));
+ dispatch(receiveTasks(tasks));
- const pendingCount = pendingActivity.paging.total;
- const failingCount = failingActivity.paging.total;
+ const pendingCount = status.pending;
+ const failingCount = status.failing;
dispatch(receiveStats({ pendingCount, failingCount }));
});
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/store/reducers.js b/server/sonar-web/src/main/js/apps/background-tasks/store/reducers.js
index 82ada158894..5ac2f53ee93 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/store/reducers.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/store/reducers.js
@@ -31,7 +31,6 @@ import { DEFAULT_FILTERS } from '../constants';
export const initialState = {
fetching: false,
tasks: [],
- total: 0,
types: [],
@@ -69,8 +68,7 @@ export default function (state = initialState, action = {}) {
return {
...state,
fetching: false,
- tasks: action.tasks,
- total: action.total
+ tasks: action.tasks
};
case UPDATE_QUERY:
return {
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1125_add_index_ce_activity_islast_status.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1125_add_index_ce_activity_islast_status.rb
new file mode 100644
index 00000000000..b4d4d180cae
--- /dev/null
+++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1125_add_index_ce_activity_islast_status.rb
@@ -0,0 +1,31 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# SonarQube is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+#
+# SonarQube 5.5
+# SONAR-7187 & SONAR-7553
+#
+class AddIndexCeActivityIslastStatus < ActiveRecord::Migration
+
+ def self.up
+ add_index :ce_activity, ['is_last','status'], :name => 'ce_activity_islast_status'
+ end
+
+end
diff --git a/sonar-db/src/main/java/org/sonar/db/ce/CeActivityDao.java b/sonar-db/src/main/java/org/sonar/db/ce/CeActivityDao.java
index e32a1be1535..91f155ee3ca 100644
--- a/sonar-db/src/main/java/org/sonar/db/ce/CeActivityDao.java
+++ b/sonar-db/src/main/java/org/sonar/db/ce/CeActivityDao.java
@@ -22,6 +22,7 @@ package org.sonar.db.ce;
import com.google.common.base.Optional;
import java.util.Collections;
import java.util.List;
+import javax.annotation.Nullable;
import org.apache.ibatis.session.RowBounds;
import org.sonar.api.utils.System2;
import org.sonar.db.Dao;
@@ -72,11 +73,8 @@ public class CeActivityDao implements Dao {
return mapper(dbSession).selectByQuery(query, offset, pageSize);
}
- public int countByQuery(DbSession dbSession, CeTaskQuery query) {
- if (query.isShortCircuitedByComponentUuids()) {
- return 0;
- }
- return mapper(dbSession).countByQuery(query);
+ public int countLastByStatusAndComponentUuid(DbSession dbSession, CeActivityDto.Status status, @Nullable String componentUuid) {
+ return mapper(dbSession).countLastByStatusAndComponentUuid(status, componentUuid);
}
private static CeActivityMapper mapper(DbSession dbSession) {
diff --git a/sonar-db/src/main/java/org/sonar/db/ce/CeActivityMapper.java b/sonar-db/src/main/java/org/sonar/db/ce/CeActivityMapper.java
index ea4652d4185..8bdaa57b1af 100644
--- a/sonar-db/src/main/java/org/sonar/db/ce/CeActivityMapper.java
+++ b/sonar-db/src/main/java/org/sonar/db/ce/CeActivityMapper.java
@@ -21,6 +21,7 @@ package org.sonar.db.ce;
import java.util.List;
import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.session.RowBounds;
@@ -37,7 +38,7 @@ public interface CeActivityMapper {
List<CeActivityDto> selectOlderThan(@Param("beforeDate") long beforeDate);
- int countByQuery(@Param("query") CeTaskQuery query);
+ int countLastByStatusAndComponentUuid(@Param("status") CeActivityDto.Status status, @Nullable @Param("componentUuid") String componentUuid);
void insert(CeActivityDto dto);
diff --git a/sonar-db/src/main/java/org/sonar/db/ce/CeQueueDao.java b/sonar-db/src/main/java/org/sonar/db/ce/CeQueueDao.java
index 9670c8c8068..283b3823443 100644
--- a/sonar-db/src/main/java/org/sonar/db/ce/CeQueueDao.java
+++ b/sonar-db/src/main/java/org/sonar/db/ce/CeQueueDao.java
@@ -21,8 +21,8 @@ package org.sonar.db.ce;
import com.google.common.base.Optional;
import java.util.List;
+import javax.annotation.Nullable;
import org.apache.ibatis.session.RowBounds;
-import org.sonar.api.utils.Paging;
import org.sonar.api.utils.System2;
import org.sonar.db.Dao;
import org.sonar.db.DbSession;
@@ -48,14 +48,14 @@ public class CeQueueDao implements Dao {
return mapper(session).selectAllInAscOrder();
}
- public List<CeQueueDto> selectByQueryInDescOrder(DbSession dbSession, CeTaskQuery query, Paging paging) {
+ public List<CeQueueDto> selectByQueryInDescOrder(DbSession dbSession, CeTaskQuery query, int pageSize) {
if (query.isShortCircuitedByComponentUuids()
|| query.isOnlyCurrents()
|| query.getMaxExecutedAt() != null) {
return emptyList();
}
- return mapper(dbSession).selectByQueryInDescOrder(query, new RowBounds(paging.offset(), paging.pageSize()));
+ return mapper(dbSession).selectByQueryInDescOrder(query, new RowBounds(0, pageSize));
}
public int countByQuery(DbSession dbSession, CeTaskQuery query) {
@@ -101,11 +101,11 @@ public class CeQueueDao implements Dao {
}
public int countByStatus(DbSession dbSession, CeQueueDto.Status status) {
- return mapper(dbSession).countByStatus(status);
+ return mapper(dbSession).countByStatusAndComponentUuid(status, null);
}
- public int countAll(DbSession dbSession) {
- return mapper(dbSession).countAll();
+ public int countByStatusAndComponentUuid(DbSession dbSession, CeQueueDto.Status status, @Nullable String componentUuid) {
+ return mapper(dbSession).countByStatusAndComponentUuid(status, componentUuid);
}
public Optional<CeQueueDto> peek(DbSession session) {
diff --git a/sonar-db/src/main/java/org/sonar/db/ce/CeQueueMapper.java b/sonar-db/src/main/java/org/sonar/db/ce/CeQueueMapper.java
index 62fca4a7ff1..aa0645987dd 100644
--- a/sonar-db/src/main/java/org/sonar/db/ce/CeQueueMapper.java
+++ b/sonar-db/src/main/java/org/sonar/db/ce/CeQueueMapper.java
@@ -40,9 +40,7 @@ public interface CeQueueMapper {
@CheckForNull
CeQueueDto selectByUuid(@Param("uuid") String uuid);
- int countByStatus(@Param("status") CeQueueDto.Status status);
-
- int countAll();
+ int countByStatusAndComponentUuid(@Param("status") CeQueueDto.Status status, @Nullable @Param("componentUuid") String componentUuid);
void insert(CeQueueDto dto);
diff --git a/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java b/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java
index 4b0508ef27f..8f51cc19382 100644
--- a/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java
+++ b/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java
@@ -29,7 +29,7 @@ import org.sonar.db.MyBatis;
public class DatabaseVersion {
- public static final int LAST_VERSION = 1124;
+ public static final int LAST_VERSION = 1125;
/**
* The minimum supported version which can be upgraded. Lower
diff --git a/sonar-db/src/main/resources/org/sonar/db/ce/CeActivityMapper.xml b/sonar-db/src/main/resources/org/sonar/db/ce/CeActivityMapper.xml
index 08247b4faa1..69e58b22989 100644
--- a/sonar-db/src/main/resources/org/sonar/db/ce/CeActivityMapper.xml
+++ b/sonar-db/src/main/resources/org/sonar/db/ce/CeActivityMapper.xml
@@ -74,11 +74,6 @@
WHERE rn BETWEEN (#{offset} * #{pageSize} + 1) AND ((#{offset} + 1) * #{pageSize})
</select>
- <select id="countByQuery" parameterType="map" resultType="int">
- select count(ca.id)
- <include refid="sqlSelectByQuery" />
- </select>
-
<sql id="sqlSelectByQuery">
from ce_activity ca
<where>
@@ -114,6 +109,16 @@
from ce_activity ca
where ca.created_at &lt; #{beforeDate,jdbcType=BIGINT}
</select>
+
+ <select id="countLastByStatusAndComponentUuid" resultType="int">
+ select count(1)
+ from ce_activity
+ where status=#{status}
+ and is_last=${_true}
+ <if test="componentUuid!=null">
+ and component_uuid=#{componentUuid}
+ </if>
+ </select>
<insert id="insert" parameterType="org.sonar.db.ce.CeActivityDto" useGeneratedKeys="false">
insert into ce_activity
diff --git a/sonar-db/src/main/resources/org/sonar/db/ce/CeQueueMapper.xml b/sonar-db/src/main/resources/org/sonar/db/ce/CeQueueMapper.xml
index c9924353c1a..e3d71cc85ac 100644
--- a/sonar-db/src/main/resources/org/sonar/db/ce/CeQueueMapper.xml
+++ b/sonar-db/src/main/resources/org/sonar/db/ce/CeQueueMapper.xml
@@ -29,8 +29,13 @@
where cq.uuid=#{uuid}
</select>
- <select id="countByStatus" parameterType="org.sonar.db.ce.CeQueueDto$Status" resultType="int">
- select count(1) from ce_queue where status=#{status}
+ <select id="countByStatusAndComponentUuid" parameterType="map" resultType="int">
+ select count(1)
+ from ce_queue
+ where status=#{status}
+ <if test="componentUuid!=null">
+ and component_uuid=#{componentUuid}
+ </if>
</select>
<select id="countAll" resultType="int">
diff --git a/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql b/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql
index 9b36923ad6c..72e8889de26 100644
--- a/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql
+++ b/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql
@@ -402,6 +402,7 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1121');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1122');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1123');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1124');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1125');
INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, EXTERNAL_IDENTITY, EXTERNAL_IDENTITY_PROVIDER, USER_LOCAL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'admin', 'sonarqube', true, 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '1418215735482', '1418215735482', null, null);
ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;
diff --git a/sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl b/sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl
index 1bbd3df88ce..4b00eea977c 100644
--- a/sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl
+++ b/sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl
@@ -669,6 +669,8 @@ CREATE UNIQUE INDEX "CE_QUEUE_UUID" ON "CE_QUEUE" ("UUID");
CREATE INDEX "CE_QUEUE_COMPONENT_UUID" ON "CE_QUEUE" ("COMPONENT_UUID");
+CREATE INDEX "CE_QUEUE_STATUS" ON "CE_QUEUE" ("STATUS");
+
CREATE UNIQUE INDEX "CE_ACTIVITY_UUID" ON "CE_ACTIVITY" ("UUID");
CREATE INDEX "CE_ACTIVITY_COMPONENT_UUID" ON "CE_ACTIVITY" ("COMPONENT_UUID");
@@ -678,3 +680,5 @@ CREATE UNIQUE INDEX "USER_TOKENS_TOKEN_HASH" ON "USER_TOKENS" ("TOKEN_HASH");
CREATE UNIQUE INDEX "USER_TOKENS_LOGIN_NAME" ON "USER_TOKENS" ("LOGIN", "NAME");
CREATE INDEX "CE_ACTIVITY_ISLASTKEY" ON "CE_ACTIVITY" ("IS_LAST_KEY");
+
+CREATE INDEX "CE_ACTIVITY_ISLAST_STATUS" ON "CE_ACTIVITY" ("IS_LAST", "STATUS");
diff --git a/sonar-db/src/test/java/org/sonar/db/DbTester.java b/sonar-db/src/test/java/org/sonar/db/DbTester.java
index 64c10150619..d58f519899f 100644
--- a/sonar-db/src/test/java/org/sonar/db/DbTester.java
+++ b/sonar-db/src/test/java/org/sonar/db/DbTester.java
@@ -155,7 +155,7 @@ public class DbTester extends ExternalResource {
/**
* Returns the number of rows in the table. Example:
- * <pre>int issues = countTable("issues")</pre>
+ * <pre>int issues = countRowsOfTable("issues")</pre>
*/
public int countRowsOfTable(String tableName) {
Preconditions.checkArgument(StringUtils.containsNone(tableName, " "), "Parameter must be the name of a table. Got " + tableName);
diff --git a/sonar-db/src/test/java/org/sonar/db/ce/CeActivityDaoTest.java b/sonar-db/src/test/java/org/sonar/db/ce/CeActivityDaoTest.java
index bb92b76097b..c233b42c15d 100644
--- a/sonar-db/src/test/java/org/sonar/db/ce/CeActivityDaoTest.java
+++ b/sonar-db/src/test/java/org/sonar/db/ce/CeActivityDaoTest.java
@@ -28,10 +28,13 @@ import javax.annotation.Nonnull;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.db.ce.CeActivityDto.Status.FAILED;
+import static org.sonar.db.ce.CeActivityDto.Status.SUCCESS;
import static org.sonar.db.ce.CeTaskTypes.REPORT;
public class CeActivityDaoTest {
@@ -40,6 +43,7 @@ public class CeActivityDaoTest {
@Rule
public DbTester db = DbTester.create(system2);
+ DbSession dbSession = db.getSession();
CeActivityDao underTest = new CeActivityDao(system2);
@@ -75,7 +79,7 @@ public class CeActivityDaoTest {
assertThat(underTest.selectByUuid(db.getSession(), "TASK_2").get().getIsLast()).isTrue();
// two tasks on PROJECT_1, the most recent one is TASK_3
- insert("TASK_3", REPORT, "PROJECT_1", CeActivityDto.Status.FAILED);
+ insert("TASK_3", REPORT, "PROJECT_1", FAILED);
assertThat(underTest.selectByUuid(db.getSession(), "TASK_1").get().getIsLast()).isFalse();
assertThat(underTest.selectByUuid(db.getSession(), "TASK_2").get().getIsLast()).isTrue();
assertThat(underTest.selectByUuid(db.getSession(), "TASK_3").get().getIsLast()).isTrue();
@@ -91,7 +95,7 @@ public class CeActivityDaoTest {
@Test
public void test_selectByQuery() {
insert("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.SUCCESS);
- insert("TASK_2", REPORT, "PROJECT_1", CeActivityDto.Status.FAILED);
+ insert("TASK_2", REPORT, "PROJECT_1", FAILED);
insert("TASK_3", REPORT, "PROJECT_2", CeActivityDto.Status.SUCCESS);
insert("TASK_4", "views", null, CeActivityDto.Status.SUCCESS);
@@ -141,36 +145,6 @@ public class CeActivityDaoTest {
}
@Test
- public void test_countByQuery() {
- insert("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.SUCCESS);
- insert("TASK_2", REPORT, "PROJECT_1", CeActivityDto.Status.FAILED);
- insert("TASK_3", REPORT, "PROJECT_2", CeActivityDto.Status.SUCCESS);
- insert("TASK_4", "views", null, CeActivityDto.Status.SUCCESS);
-
- // no filters
- CeTaskQuery query = new CeTaskQuery();
- assertThat(underTest.countByQuery(db.getSession(), query)).isEqualTo(4);
-
- // select by component uuid
- query = new CeTaskQuery().setComponentUuid("PROJECT_1");
- assertThat(underTest.countByQuery(db.getSession(), query)).isEqualTo(2);
-
- // select by status
- query = new CeTaskQuery().setStatuses(singletonList(CeActivityDto.Status.SUCCESS.name()));
- assertThat(underTest.countByQuery(db.getSession(), query)).isEqualTo(3);
-
- // select by type
- query = new CeTaskQuery().setType(REPORT);
- assertThat(underTest.countByQuery(db.getSession(), query)).isEqualTo(3);
- query = new CeTaskQuery().setType("views");
- assertThat(underTest.countByQuery(db.getSession(), query)).isEqualTo(1);
-
- // select by multiple conditions
- query = new CeTaskQuery().setType(REPORT).setOnlyCurrents(true).setComponentUuid("PROJECT_1");
- assertThat(underTest.countByQuery(db.getSession(), query)).isEqualTo(1);
- }
-
- @Test
public void selectByQuery_no_results_if_shortcircuited_by_component_uuids() {
insert("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.SUCCESS);
@@ -180,15 +154,6 @@ public class CeActivityDaoTest {
}
@Test
- public void countByQuery_no_results_if_shortcircuited_by_component_uuids() {
- insert("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.SUCCESS);
-
- CeTaskQuery query = new CeTaskQuery();
- query.setComponentUuids(Collections.<String>emptyList());
- assertThat(underTest.countByQuery(db.getSession(), query)).isEqualTo(0);
- }
-
- @Test
public void select_and_count_by_date() {
insertWithDates("UUID1", 1_450_000_000_000L, 1_470_000_000_000L);
insertWithDates("UUID2", 1_460_000_000_000L, 1_480_000_000_000L);
@@ -196,19 +161,16 @@ public class CeActivityDaoTest {
// search by min submitted date
CeTaskQuery query = new CeTaskQuery().setMinSubmittedAt(1_455_000_000_000L);
assertThat(underTest.selectByQuery(db.getSession(), query, 0, 5)).extracting("uuid").containsOnly("UUID2");
- assertThat(underTest.countByQuery(db.getSession(), query)).isEqualTo(1);
// search by max executed date
query = new CeTaskQuery().setMaxExecutedAt(1_475_000_000_000L);
assertThat(underTest.selectByQuery(db.getSession(), query, 0, 5)).extracting("uuid").containsOnly("UUID1");
- assertThat(underTest.countByQuery(db.getSession(), query)).isEqualTo(1);
// search by both dates
query = new CeTaskQuery()
.setMinSubmittedAt(1_400_000_000_000L)
.setMaxExecutedAt(1_475_000_000_000L);
assertThat(underTest.selectByQuery(db.getSession(), query, 0, 5)).extracting("uuid").containsOnly("UUID1");
- assertThat(underTest.countByQuery(db.getSession(), query)).isEqualTo(1);
}
@@ -253,6 +215,22 @@ public class CeActivityDaoTest {
assertThat(underTest.selectByUuid(db.getSession(), "TASK_1").isPresent()).isTrue();
}
+ @Test
+ public void count_last_by_status_and_component_uuid() {
+ insert("TASK_1", CeTaskTypes.REPORT, "COMPONENT1", CeActivityDto.Status.SUCCESS);
+ // component 2
+ insert("TASK_2", CeTaskTypes.REPORT, "COMPONENT2", CeActivityDto.Status.SUCCESS);
+ // status failed
+ insert("TASK_3", CeTaskTypes.REPORT, "COMPONENT1", CeActivityDto.Status.FAILED);
+ // status canceled
+ insert("TASK_4", CeTaskTypes.REPORT, "COMPONENT1", CeActivityDto.Status.CANCELED);
+ insert("TASK_5", CeTaskTypes.REPORT, "COMPONENT1", CeActivityDto.Status.SUCCESS);
+ db.commit();
+
+ assertThat(underTest.countLastByStatusAndComponentUuid(dbSession, SUCCESS, "COMPONENT1")).isEqualTo(1);
+ assertThat(underTest.countLastByStatusAndComponentUuid(dbSession, SUCCESS, null)).isEqualTo(2);
+ }
+
private void insert(String uuid, String type, String componentUuid, CeActivityDto.Status status) {
CeQueueDto queueDto = new CeQueueDto();
queueDto.setUuid(uuid);
diff --git a/sonar-db/src/test/java/org/sonar/db/ce/CeQueueDaoTest.java b/sonar-db/src/test/java/org/sonar/db/ce/CeQueueDaoTest.java
index 479bd23bf76..30c4694047b 100644
--- a/sonar-db/src/test/java/org/sonar/db/ce/CeQueueDaoTest.java
+++ b/sonar-db/src/test/java/org/sonar/db/ce/CeQueueDaoTest.java
@@ -29,7 +29,6 @@ import java.util.Map;
import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.utils.Paging;
import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.DbTester;
@@ -140,7 +139,7 @@ public class CeQueueDaoTest {
system2.setNow(INIT_TIME + 3_000_000);
insert(TASK_UUID_2, COMPONENT_UUID_2, PENDING);
- assertThat(underTest.countAll(db.getSession())).isEqualTo(2);
+ assertThat(db.countRowsOfTable("ce_queue")).isEqualTo(2);
verifyCeQueueStatuses(TASK_UUID_1, PENDING, TASK_UUID_2, PENDING);
// peek first one
@@ -227,7 +226,7 @@ public class CeQueueDaoTest {
.setType(CeTaskTypes.REPORT)
.setMinSubmittedAt(100_000L);
- List<CeQueueDto> result = underTest.selectByQueryInDescOrder(db.getSession(), query, Paging.forPageIndex(1).withPageSize(1_000).andTotal(1_000));
+ List<CeQueueDto> result = underTest.selectByQueryInDescOrder(db.getSession(), query, 1_000);
int total = underTest.countByQuery(db.getSession(), query);
assertThat(result).extracting("uuid").containsExactly("TASK_5", TASK_UUID_2);
@@ -244,7 +243,7 @@ public class CeQueueDaoTest {
CeTaskQuery query = new CeTaskQuery().setOnlyCurrents(true);
- List<CeQueueDto> result = underTest.selectByQueryInDescOrder(db.getSession(), query, Paging.forPageIndex(1).withPageSize(1_000).andTotal(1_000));
+ List<CeQueueDto> result = underTest.selectByQueryInDescOrder(db.getSession(), query, 1_000);
int total = underTest.countByQuery(db.getSession(), query);
assertThat(result).isEmpty();
@@ -261,7 +260,7 @@ public class CeQueueDaoTest {
CeTaskQuery query = new CeTaskQuery().setMaxExecutedAt(1_000_000_000_000L);
- List<CeQueueDto> result = underTest.selectByQueryInDescOrder(db.getSession(), query, Paging.forPageIndex(1).withPageSize(1_000).andTotal(1_000));
+ List<CeQueueDto> result = underTest.selectByQueryInDescOrder(db.getSession(), query, 1_000);
int total = underTest.countByQuery(db.getSession(), query);
assertThat(result).isEmpty();
@@ -278,13 +277,38 @@ public class CeQueueDaoTest {
CeTaskQuery query = new CeTaskQuery().setComponentUuids(Collections.<String>emptyList());
- List<CeQueueDto> result = underTest.selectByQueryInDescOrder(db.getSession(), query, Paging.forPageIndex(1).withPageSize(1_000).andTotal(1_000));
+ List<CeQueueDto> result = underTest.selectByQueryInDescOrder(db.getSession(), query, 1_000);
int total = underTest.countByQuery(db.getSession(), query);
assertThat(result).isEmpty();
assertThat(total).isEqualTo(0);
}
+ @Test
+ public void count_by_status_and_component_uuid() {
+ // task retrieved in the queue
+ insert(newCeQueueDto(TASK_UUID_1)
+ .setComponentUuid(COMPONENT_UUID_1)
+ .setStatus(IN_PROGRESS)
+ .setTaskType(CeTaskTypes.REPORT)
+ .setCreatedAt(100_000L));
+ // on component uuid 2, not returned
+ insert(newCeQueueDto(TASK_UUID_2)
+ .setComponentUuid(COMPONENT_UUID_2)
+ .setStatus(IN_PROGRESS)
+ .setTaskType(CeTaskTypes.REPORT)
+ .setCreatedAt(100_000L));
+ // pending status, not returned
+ insert(newCeQueueDto(TASK_UUID_3)
+ .setComponentUuid(COMPONENT_UUID_1)
+ .setStatus(PENDING)
+ .setTaskType(CeTaskTypes.REPORT)
+ .setCreatedAt(100_000L));
+
+ assertThat(underTest.countByStatusAndComponentUuid(db.getSession(), IN_PROGRESS, COMPONENT_UUID_1)).isEqualTo(1);
+ assertThat(underTest.countByStatus(db.getSession(), IN_PROGRESS)).isEqualTo(2);
+ }
+
private void insert(CeQueueDto dto) {
underTest.insert(db.getSession(), dto);
db.commit();
@@ -315,12 +339,13 @@ public class CeQueueDaoTest {
});
}
- private void verifyCeQueueStatuses(String taskUuid1, CeQueueDto.Status taskStatus1, String taskUuid2, CeQueueDto.Status taskStatus2, String taskUuid3, CeQueueDto.Status taskStatus3) {
- verifyCeQueueStatuses(new String[]{taskUuid1, taskUuid2, taskUuid3}, new CeQueueDto.Status[]{taskStatus1, taskStatus2, taskStatus3});
+ private void verifyCeQueueStatuses(String taskUuid1, CeQueueDto.Status taskStatus1, String taskUuid2, CeQueueDto.Status taskStatus2, String taskUuid3,
+ CeQueueDto.Status taskStatus3) {
+ verifyCeQueueStatuses(new String[] {taskUuid1, taskUuid2, taskUuid3}, new CeQueueDto.Status[] {taskStatus1, taskStatus2, taskStatus3});
}
private void verifyCeQueueStatuses(String taskUuid1, CeQueueDto.Status taskStatus1, String taskUuid2, CeQueueDto.Status taskStatus2) {
- verifyCeQueueStatuses(new String[]{taskUuid1, taskUuid2}, new CeQueueDto.Status[]{taskStatus1, taskStatus2});
+ verifyCeQueueStatuses(new String[] {taskUuid1, taskUuid2}, new CeQueueDto.Status[] {taskStatus1, taskStatus2});
}
private void verifyCeQueueStatuses(String[] taskUuids, CeQueueDto.Status[] statuses) {
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java b/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java
index 484956d7a68..3a9b87fe478 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java
@@ -349,12 +349,21 @@ public interface WebService extends Definable<WebService.Context> {
* Note the maximum is a documentation only feature. It does not check anything.
*/
public NewAction addPagingParams(int defaultPageSize, int maxPageSize) {
+ addPageParam();
+ addPageSize(defaultPageSize, maxPageSize);
+ return this;
+ }
+
+ public NewAction addPageParam() {
createParam(Param.PAGE)
.setDescription("1-based page number")
.setExampleValue("42")
.setDeprecatedKey("pageIndex")
.setDefaultValue("1");
+ return this;
+ }
+ public NewAction addPageSize(int defaultPageSize, int maxPageSize) {
createParam(Param.PAGE_SIZE)
.setDescription("Page size. Must be greater than 0 and less than " + maxPageSize)
.setExampleValue("20")
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/ActivityStatusWsRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/ActivityStatusWsRequest.java
new file mode 100644
index 00000000000..66407145b75
--- /dev/null
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/ActivityStatusWsRequest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.sonarqube.ws.client.ce;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+public class ActivityStatusWsRequest {
+ private final String componentId;
+ private final String componentKey;
+
+ private ActivityStatusWsRequest(Builder builder) {
+ this.componentId = builder.componentId;
+ this.componentKey = builder.componentKey;
+ }
+
+ @CheckForNull
+ public String getComponentId() {
+ return componentId;
+ }
+
+ @CheckForNull
+ public String getComponentKey() {
+ return componentKey;
+ }
+
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private String componentId;
+ private String componentKey;
+
+ private Builder() {
+ // enforce newBuilder() use for instantiation
+ }
+
+ public Builder setComponentId(@Nullable String componentId) {
+ this.componentId = componentId;
+ return this;
+ }
+
+ public Builder setComponentKey(@Nullable String componentKey) {
+ this.componentKey = componentKey;
+ return this;
+ }
+
+ public ActivityStatusWsRequest build() {
+ return new ActivityStatusWsRequest(this);
+ }
+ }
+}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeService.java
index 1871cd800d9..460ddb53faa 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeService.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeService.java
@@ -28,6 +28,7 @@ import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.WsConnector;
import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_ID;
+import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_KEY;
import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_MAX_EXECUTED_AT;
import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_MIN_SUBMITTED_AT;
import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_ONLY_CURRENTS;
@@ -71,4 +72,13 @@ public class CeService extends BaseService {
public WsCe.TaskResponse task(String id) {
return call(new GetRequest(path("task")).setParam("id", id), WsCe.TaskResponse.parser());
}
+
+ public WsCe.ActivityStatusWsResponse activityStatus(ActivityStatusWsRequest request) {
+ return call(
+ new GetRequest(path("activity_status"))
+ .setParam(PARAM_COMPONENT_ID, request.getComponentId())
+ .setParam(PARAM_COMPONENT_KEY, request.getComponentKey()),
+ WsCe.ActivityStatusWsResponse.parser());
+ }
+
}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeWsParameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeWsParameters.java
index 3b4fc97e4f1..e2254619a2a 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeWsParameters.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/ce/CeWsParameters.java
@@ -22,6 +22,7 @@ package org.sonarqube.ws.client.ce;
public class CeWsParameters {
public static final String PARAM_COMPONENT_ID = "componentId";
+ public static final String PARAM_COMPONENT_KEY = "componentKey";
public static final String PARAM_COMPONENT_QUERY = "componentQuery";
public static final String PARAM_TYPE = "type";
public static final String PARAM_STATUS = "status";
diff --git a/sonar-ws/src/main/protobuf/ws-ce.proto b/sonar-ws/src/main/protobuf/ws-ce.proto
index 1db7111abcf..4440851e45a 100644
--- a/sonar-ws/src/main/protobuf/ws-ce.proto
+++ b/sonar-ws/src/main/protobuf/ws-ce.proto
@@ -39,10 +39,17 @@ message TaskResponse {
// GET api/ce/activity
message ActivityResponse {
- optional sonarqube.ws.commons.Paging paging = 1;
+ // paging has been deprecated in 5.5
+ optional sonarqube.ws.commons.Paging unusedPaging = 1;
repeated Task tasks = 2;
}
+// GET api/ce/activity_status
+message ActivityStatusWsResponse {
+ optional int32 pending = 1;
+ optional int32 failing = 2;
+}
+
// GET api/ce/project
message ProjectResponse {
repeated Task queue = 1;