aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/component/ws/ResourcesWs.java23
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/ws/ActivityAction.java1
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsModule.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/ws/ComponentAction.java1
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskAction.java10
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskFormatter.java3
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java125
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatter.java164
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java13
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/UserSession.java7
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/computation/ws/activity-example.json1
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/computation/ws/component-example.json1
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/computation/ws/task-example.json1
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/project_status-example.json85
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/ws/ActivityActionTest.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/ws/ComponentActionTest.java7
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskActionTest.java17
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskFormatterTest.java3
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ProjectStatusActionTest.java167
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatterTest.java147
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/tester/UserSessionRule.java6
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/qualitygate/ws/ProjectStatusActionTest/measure_data.json66
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatterTest/quality_gate_details.json50
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1004_add_ce_activity_snapshot_id.rb2
-rw-r--r--sonar-db/src/main/java/org/sonar/db/ce/CeActivityDto.java33
-rw-r--r--sonar-db/src/main/java/org/sonar/db/ce/CeQueueDto.java24
-rw-r--r--sonar-db/src/main/resources/org/sonar/db/ce/CeActivityMapper.xml2
-rw-r--r--sonar-db/src/test/java/org/sonar/db/ce/CeQueueTesting.java42
-rw-r--r--sonar-db/src/test/java/org/sonar/db/measure/MeasureTesting.java40
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/HttpWsClient.java8
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java3
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/ProjectStatusWsRequest.java34
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesService.java39
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/package-info.java26
-rw-r--r--sonar-ws/src/main/protobuf/ws-ce.proto17
-rw-r--r--sonar-ws/src/main/protobuf/ws-qualitygates.proto69
38 files changed, 1187 insertions, 62 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/ResourcesWs.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/ResourcesWs.java
index 03f16a80f70..5ee2466181f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/ResourcesWs.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/ResourcesWs.java
@@ -26,9 +26,6 @@ import org.sonar.api.server.ws.WebService;
public class ResourcesWs implements WebService {
- private static final String FALSE = "false";
- private static final String TRUE = "true";
-
@Override
public void define(Context context) {
NewController controller = context.createController("api/resources")
@@ -92,8 +89,8 @@ public class ResourcesWs implements WebService {
action.createParam("verbose")
.setDescription("Add some data to response")
- .setDefaultValue(FALSE)
- .setPossibleValues(TRUE, FALSE);
+ .setBooleanPossibleValues()
+ .setDefaultValue(String.valueOf(false));
action.createParam("limit")
.setDescription("Limit the number of results. Only used if one metric, and only one, is set")
@@ -101,19 +98,19 @@ public class ResourcesWs implements WebService {
action.createParam("includetrends")
.setDescription("Include period variations in response: add nodes &ltp*&gt for period variations")
- .setDefaultValue(FALSE)
- .setPossibleValues(TRUE, FALSE);
+ .setDefaultValue(String.valueOf(false))
+ .setBooleanPossibleValues();
action.createParam("includealerts")
.setDescription("Include alerts data: add nodes &ltalert&gt (ERROR, WARN, OK) and &ltalert_text&gt")
- .setDefaultValue(FALSE)
- .setPossibleValues(TRUE, FALSE);
+ .setBooleanPossibleValues()
+ .setDefaultValue(String.valueOf(false));
action.createParam("rules")
.setDescription("Filter on rules: setting it to true will return rules id and rule name for measure having such info " +
"(such as 'blocker_violations', 'critical_violations', ..., 'new_blocker_violations', ...). Possible values: true | false | list of rule ids")
- .setDefaultValue(FALSE)
- .setExampleValue(TRUE);
+ .setBooleanPossibleValues()
+ .setDefaultValue(String.valueOf(true));
RailsHandler.addFormatParam(action);
}
@@ -133,8 +130,8 @@ public class ResourcesWs implements WebService {
action.createParam("display_key")
.setDescription("Return the resource key instead of the resource id")
- .setDefaultValue(FALSE)
- .setPossibleValues(TRUE, FALSE);
+ .setBooleanPossibleValues()
+ .setDefaultValue(String.valueOf(false));
action.createParam("q")
.setDescription("Comma-separated list of qualifiers")
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/ActivityAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/ActivityAction.java
index 6decd092133..e7b483eed85 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/ActivityAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/ActivityAction.java
@@ -74,7 +74,6 @@ public class ActivityAction implements CeWsAction {
@Override
public void define(WebService.NewController controller) {
WebService.NewAction action = controller.createAction("activity")
- .setInternal(true)
.setDescription(format("Search for past task executions. Requires the system administration permission, " +
"or project administration permission if %s is set.", PARAM_COMPONENT_UUID))
.setResponseExample(getClass().getResource("activity-example.json"))
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsModule.java
index 09b9e10599b..5db2f82871f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsModule.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/CeWsModule.java
@@ -25,11 +25,11 @@ public class CeWsModule extends Module {
@Override
protected void configureModule() {
add(
+ CeWs.class,
ActivityAction.class,
CancelAction.class,
CancelAllAction.class,
QueueAction.class,
- CeWs.class,
IsQueueEmptyWs.class,
LogsAction.class,
ComponentAction.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/ComponentAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/ComponentAction.java
index 07b70fd22e0..24822f358a6 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/ComponentAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/ComponentAction.java
@@ -55,7 +55,6 @@ public class ComponentAction implements CeWsAction {
WebService.NewAction action = controller.createAction("component")
.setDescription("Get the pending tasks, in-progress tasks and the last executed task of a given component " +
"(usually a project). Requires the administration permission on the component.")
- .setInternal(true)
.setSince("5.2")
.setResponseExample(getClass().getResource("component-example.json"))
.setHandler(this);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskAction.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskAction.java
index d3c3eb68974..e79851156dd 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskAction.java
@@ -20,6 +20,8 @@
package org.sonar.server.computation.ws;
import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
@@ -39,6 +41,7 @@ public class TaskAction implements CeWsAction {
public static final String ACTION = "task";
public static final String PARAM_TASK_UUID = "id";
+ private static final Set<String> AUTHORIZED_PERMISSIONS = ImmutableSet.of(GlobalPermissions.SCAN_EXECUTION, GlobalPermissions.SYSTEM_ADMIN);
private final DbClient dbClient;
private final TaskFormatter wsTaskFormatter;
@@ -55,7 +58,6 @@ public class TaskAction implements CeWsAction {
WebService.NewAction action = controller.createAction(ACTION)
.setDescription("Give Compute Engine task details such as type, status, duration and associated component.<br />" +
"Requires 'Administer System' or 'Execute Analysis' permission.")
- .setInternal(true)
.setResponseExample(getClass().getResource("task-example.json"))
.setSince("5.2")
.setHandler(this);
@@ -69,11 +71,7 @@ public class TaskAction implements CeWsAction {
@Override
public void handle(Request wsRequest, Response wsResponse) throws Exception {
- if (!userSession.hasGlobalPermission(GlobalPermissions.SYSTEM_ADMIN)
- // WS can be used at the end of an analysis to implement a build breaker
- && !userSession.hasGlobalPermission(GlobalPermissions.SCAN_EXECUTION)) {
- userSession.checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN);
- }
+ userSession.checkAnyGlobalPermissions(AUTHORIZED_PERMISSIONS);
String taskUuid = wsRequest.mandatoryParam(PARAM_TASK_UUID);
DbSession dbSession = dbClient.openSession(false);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskFormatter.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskFormatter.java
index 1346e6e654d..471c9646e30 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskFormatter.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ws/TaskFormatter.java
@@ -115,6 +115,9 @@ public class TaskFormatter {
builder.setComponentId(dto.getComponentUuid());
buildComponent(builder, componentCache.get(dto.getComponentUuid()));
}
+ if (dto.getSnapshotId() != null) {
+ builder.setAnalysisId(String.valueOf(dto.getSnapshotId()));
+ }
if (dto.getSubmitterLogin() != null) {
builder.setSubmitterLogin(dto.getSubmitterLogin());
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
index 53b153bb349..25e8a70c500 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
@@ -206,6 +206,7 @@ import org.sonar.server.qualitygate.ws.CreateConditionAction;
import org.sonar.server.qualitygate.ws.DeleteConditionAction;
import org.sonar.server.qualitygate.ws.DeselectAction;
import org.sonar.server.qualitygate.ws.DestroyAction;
+import org.sonar.server.qualitygate.ws.ProjectStatusAction;
import org.sonar.server.qualitygate.ws.QGatesWs;
import org.sonar.server.qualitygate.ws.SelectAction;
import org.sonar.server.qualitygate.ws.SetAsDefaultAction;
@@ -507,6 +508,7 @@ public class PlatformLevel4 extends PlatformLevel {
DeleteConditionAction.class,
UpdateConditionAction.class,
org.sonar.server.qualitygate.ws.AppAction.class,
+ ProjectStatusAction.class,
QGatesWs.class,
// web services
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java
new file mode 100644
index 00000000000..fb7e92c9a47
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+package org.sonar.server.qualitygate.ws;
+
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.component.SnapshotDto;
+import org.sonar.db.measure.MeasureDto;
+import org.sonar.server.user.UserSession;
+import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse;
+import org.sonarqube.ws.client.qualitygate.ProjectStatusWsRequest;
+
+import static com.google.common.collect.Sets.newHashSet;
+import static org.sonar.server.ws.WsUtils.checkFound;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
+
+public class ProjectStatusAction implements QGateWsAction {
+ private final DbClient dbClient;
+ private final UserSession userSession;
+
+ public ProjectStatusAction(DbClient dbClient, UserSession userSession) {
+ this.dbClient = dbClient;
+ this.userSession = userSession;
+ }
+
+ @Override
+ public void define(WebService.NewController controller) {
+ WebService.NewAction action = controller.createAction("project_status")
+ .setDescription("Quality gate status for a given Compute Engine task. <br />" +
+ "Returns a http code 404 if the analysis associated with the task is not found or does not exist.<br />" +
+ "Requires 'Administer System' or 'Execute Analysis' permission.")
+ .setResponseExample(getClass().getResource("project_status-example.json"))
+ .setSince("5.3")
+ .setHandler(this);
+
+ action.createParam("analysisId")
+ .setDescription("Analysis id")
+ .setRequired(true)
+ .setExampleValue("2963");
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ ProjectStatusWsResponse projectStatusWsResponse = doHandle(toProjectStatusWsRequest(request));
+ writeProtobuf(projectStatusWsResponse, request, response);
+ }
+
+ private ProjectStatusWsResponse doHandle(ProjectStatusWsRequest request) {
+ checkScanOrAdminPermission();
+
+ DbSession dbSession = dbClient.openSession(false);
+ try {
+ String snapshotId = request.getAnalysisId();
+ SnapshotDto snapshotDto = getSnapshot(dbSession, snapshotId);
+ String measureData = getQualityGateDetailsMeasureData(dbSession, snapshotDto);
+
+ return ProjectStatusWsResponse.newBuilder()
+ .setProjectStatus(new QualityGateDetailsFormatter(measureData, snapshotDto).format())
+ .build();
+ } finally {
+ dbClient.closeSession(dbSession);
+ }
+ }
+
+ private SnapshotDto getSnapshot(DbSession dbSession, String snapshotIdFromRequest) {
+ Long snapshotId = null;
+ try {
+ snapshotId = Long.parseLong(snapshotIdFromRequest);
+ } catch (NumberFormatException e) {
+ // checks String is a long
+ }
+
+ SnapshotDto snapshotDto = null;
+ if (snapshotId != null) {
+ snapshotDto = dbClient.snapshotDao().selectById(dbSession, snapshotId);
+ }
+
+ return checkFound(snapshotDto, "Analysis with id '%s' is not found", snapshotIdFromRequest);
+ }
+
+ @CheckForNull
+ private String getQualityGateDetailsMeasureData(DbSession dbSession, SnapshotDto snapshotDto) {
+ List<MeasureDto> measures = dbClient.measureDao().selectBySnapshotIdAndMetricKeys(snapshotDto.getId(),
+ Collections.singleton(CoreMetrics.QUALITY_GATE_DETAILS_KEY), dbSession);
+
+ return measures.isEmpty()
+ ? null
+ : measures.get(0).getData();
+ }
+
+ private static ProjectStatusWsRequest toProjectStatusWsRequest(Request request) {
+ return new ProjectStatusWsRequest()
+ .setAnalysisId(request.mandatoryParam("analysisId"));
+ }
+
+ private void checkScanOrAdminPermission() {
+ userSession.checkAnyGlobalPermissions(newHashSet(GlobalPermissions.SCAN_EXECUTION, GlobalPermissions.SYSTEM_ADMIN));
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatter.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatter.java
new file mode 100644
index 00000000000..0450cbc9f80
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatter.java
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+package org.sonar.server.qualitygate.ws;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.db.component.SnapshotDto;
+import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.sonar.api.utils.DateUtils.formatDateTime;
+
+public class QualityGateDetailsFormatter {
+ @CheckForNull
+ private final String measureData;
+ private final SnapshotDto snapshot;
+ private final ProjectStatusWsResponse.ProjectStatus.Builder projectStatusBuilder;
+
+ public QualityGateDetailsFormatter(@Nullable String measureData, SnapshotDto snapshot) {
+ this.measureData = measureData;
+ this.snapshot = snapshot;
+ this.projectStatusBuilder = ProjectStatusWsResponse.ProjectStatus.newBuilder();
+ }
+
+ public ProjectStatusWsResponse.ProjectStatus format() {
+ if (isNullOrEmpty(measureData)) {
+ return newResponseWithoutQualityGateDetails();
+ }
+
+ JsonParser parser = new JsonParser();
+ JsonObject json = parser.parse(measureData).getAsJsonObject();
+
+ ProjectStatusWsResponse.Status qualityGateStatus = measureLevelToQualityGateStatus(json.get("level").getAsString());
+ projectStatusBuilder.setStatus(qualityGateStatus);
+
+ formatConditions(json.getAsJsonArray("conditions"));
+ formatPeriods();
+
+ return projectStatusBuilder.build();
+ }
+
+ private void formatPeriods() {
+ ProjectStatusWsResponse.Period.Builder periodBuilder = ProjectStatusWsResponse.Period.newBuilder();
+ for (int i = 1; i <= 5; i++) {
+ periodBuilder.clear();
+ boolean doesPeriodExist = false;
+
+ if (!isNullOrEmpty(snapshot.getPeriodMode(i))) {
+ doesPeriodExist = true;
+ periodBuilder.setIndex(i);
+ periodBuilder.setMode(snapshot.getPeriodMode(i));
+ if (snapshot.getPeriodDate(i) != null) {
+ periodBuilder.setDate(formatDateTime(snapshot.getPeriodDate(i)));
+ }
+ if (!isNullOrEmpty(snapshot.getPeriodModeParameter(i))) {
+ periodBuilder.setParameter(snapshot.getPeriodModeParameter(i));
+ }
+ }
+
+ if (doesPeriodExist) {
+ projectStatusBuilder.addPeriods(periodBuilder);
+ }
+ }
+ }
+
+ private void formatConditions(@Nullable JsonArray jsonConditions) {
+ if (jsonConditions == null) {
+ return;
+ }
+
+ for (JsonElement jsonCondition : jsonConditions) {
+ formatCondition(jsonCondition.getAsJsonObject());
+ }
+ }
+
+ private void formatCondition(JsonObject jsonCondition) {
+ ProjectStatusWsResponse.Condition.Builder conditionBuilder = ProjectStatusWsResponse.Condition.newBuilder();
+
+ JsonElement measureLevel = jsonCondition.get("level");
+ if (measureLevel != null && !isNullOrEmpty(measureLevel.getAsString())) {
+ conditionBuilder.setStatus(measureLevelToQualityGateStatus(measureLevel.getAsString()));
+ }
+
+ JsonElement metric = jsonCondition.get("metric");
+ if (metric != null && !isNullOrEmpty(metric.getAsString())) {
+ conditionBuilder.setMetricKey(metric.getAsString());
+ }
+
+ JsonElement op = jsonCondition.get("op");
+ if (op != null && !isNullOrEmpty(op.getAsString())) {
+ String stringOp = op.getAsString();
+ ProjectStatusWsResponse.Comparator comparator = measureOpToQualityGateComparator(stringOp);
+ conditionBuilder.setComparator(comparator);
+ }
+
+ JsonElement periodIndex = jsonCondition.get("period");
+ if (periodIndex != null && !isNullOrEmpty(periodIndex.getAsString())) {
+ conditionBuilder.setPeriodIndex(periodIndex.getAsInt());
+ }
+
+ JsonElement warning = jsonCondition.get("warning");
+ if (warning != null && !isNullOrEmpty(warning.getAsString())) {
+ conditionBuilder.setWarningThreshold(warning.getAsString());
+ }
+
+ JsonElement error = jsonCondition.get("error");
+ if (error != null && !isNullOrEmpty(error.getAsString())) {
+ conditionBuilder.setErrorThreshold(error.getAsString());
+ }
+
+ JsonElement actual = jsonCondition.get("actual");
+ if (actual != null && !isNullOrEmpty(actual.getAsString())) {
+ conditionBuilder.setActualValue(actual.getAsString());
+ }
+
+ projectStatusBuilder.addConditions(conditionBuilder);
+ }
+
+ private static ProjectStatusWsResponse.Status measureLevelToQualityGateStatus(String measureLevel) {
+ for (ProjectStatusWsResponse.Status status : ProjectStatusWsResponse.Status.values()) {
+ if (status.name().equals(measureLevel)) {
+ return status;
+ }
+ }
+
+ throw new IllegalStateException(String.format("Unknown quality gate status '%s'", measureLevel));
+ }
+
+ private static ProjectStatusWsResponse.Comparator measureOpToQualityGateComparator(String measureOp) {
+ for (ProjectStatusWsResponse.Comparator comparator : ProjectStatusWsResponse.Comparator.values()) {
+ if (comparator.name().equals(measureOp)) {
+ return comparator;
+ }
+ }
+
+ throw new IllegalStateException(String.format("Unknown quality gate comparator '%s'", measureOp));
+ }
+
+ private static ProjectStatusWsResponse.ProjectStatus newResponseWithoutQualityGateDetails() {
+ return ProjectStatusWsResponse.ProjectStatus.newBuilder().setStatus(ProjectStatusWsResponse.Status.NONE).build();
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java b/server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java
index e8e6c831c4b..99b43978e7d 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/AbstractUserSession.java
@@ -24,6 +24,7 @@ import com.google.common.base.Strings;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Sets;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
@@ -141,6 +142,18 @@ public abstract class AbstractUserSession<T extends AbstractUserSession> impleme
}
@Override
+ public UserSession checkAnyGlobalPermissions(Collection<String> globalPermissionsToTest) {
+ List<String> userGlobalPermissions = globalPermissions();
+ for (String userGlobalPermission : userGlobalPermissions) {
+ if (globalPermissionsToTest.contains(userGlobalPermission)) {
+ return this;
+ }
+ }
+
+ throw new ForbiddenException(INSUFFICIENT_PRIVILEGES_MESSAGE);
+ }
+
+ @Override
public boolean hasGlobalPermission(String globalPermission) {
return globalPermissions().contains(globalPermission);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java b/server/sonar-server/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java
index eb03462876e..62011a7a252 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/ThreadLocalUserSession.java
@@ -20,6 +20,7 @@
package org.sonar.server.user;
import com.google.common.base.Objects;
+import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Set;
@@ -98,6 +99,11 @@ public class ThreadLocalUserSession implements UserSession {
}
@Override
+ public UserSession checkAnyGlobalPermissions(Collection<String> globalPermissions) {
+ return get().checkAnyGlobalPermissions(globalPermissions);
+ }
+
+ @Override
public boolean hasGlobalPermission(String globalPermission) {
return get().hasGlobalPermission(globalPermission);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/UserSession.java b/server/sonar-server/src/main/java/org/sonar/server/user/UserSession.java
index 64a7b3f6d0e..001c26d75c3 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/UserSession.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/UserSession.java
@@ -19,6 +19,7 @@
*/
package org.sonar.server.user;
+import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Set;
@@ -58,6 +59,12 @@ public interface UserSession {
UserSession checkGlobalPermission(String globalPermission, @Nullable String errorMessage);
/**
+ * Ensures that user implies any of the specified global permissions, otherwise throws a {@link org.sonar.server.exceptions.ForbiddenException} with
+ * the specified error message.
+ */
+ UserSession checkAnyGlobalPermissions(Collection<String> globalPermissions);
+
+ /**
* Does the user have the given permission ?
*/
boolean hasGlobalPermission(String globalPermission);
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/activity-example.json b/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/activity-example.json
index de5018a0661..93d300ba1d7 100644
--- a/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/activity-example.json
+++ b/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/activity-example.json
@@ -12,6 +12,7 @@
"componentKey": "project_1",
"componentName": "Project One",
"componentQualifier": "TRK",
+ "analysisId": "123456",
"status": "SUCCESS",
"submittedAt": "2015-08-13T23:34:59+0200",
"submitterLogin": "john",
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/component-example.json b/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/component-example.json
index 93ead161166..6adb3f0d7aa 100644
--- a/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/component-example.json
+++ b/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/component-example.json
@@ -19,6 +19,7 @@
"componentKey": "com.github.kevinsawicki:http-request-parent",
"componentName": "HttpRequest",
"componentQualifier": "TRK",
+ "analysisId": "123456",
"status": "SUCCESS",
"submittedAt": "2015-09-21T19:25:49+0200",
"startedAt": "2015-09-21T19:25:57+0200",
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/task-example.json b/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/task-example.json
index 5f02d9072bd..089e277fb62 100644
--- a/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/task-example.json
+++ b/server/sonar-server/src/main/resources/org/sonar/server/computation/ws/task-example.json
@@ -6,6 +6,7 @@
"componentKey": "project_1",
"componentName": "Project One",
"componentQualifier": "TRK",
+ "analysisId": "123456",
"status": "SUCCESS",
"submittedAt": "2015-10-02T11:32:15+0200",
"startedAt": "2015-10-02T11:32:16+0200",
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/project_status-example.json b/server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/project_status-example.json
new file mode 100644
index 00000000000..cf46493da0f
--- /dev/null
+++ b/server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/project_status-example.json
@@ -0,0 +1,85 @@
+{
+ "projectStatus": {
+ "status": "ERROR",
+ "conditions": [
+ {
+ "status": "ERROR",
+ "metricKey": "new_coverage",
+ "comparator": "LT",
+ "periodIndex": 1,
+ "errorThreshold": "85",
+ "actualValue": "82.50562381034781"
+ },
+ {
+ "status": "ERROR",
+ "metricKey": "new_blocker_violations",
+ "comparator": "GT",
+ "periodIndex": 1,
+ "errorThreshold": "0",
+ "actualValue": "14"
+ },
+ {
+ "status": "ERROR",
+ "metricKey": "new_critical_violations",
+ "comparator": "GT",
+ "periodIndex": 1,
+ "errorThreshold": "0",
+ "actualValue": "1"
+ },
+ {
+ "status": "OK",
+ "metricKey": "new_sqale_debt_ratio",
+ "comparator": "GT",
+ "periodIndex": 2,
+ "errorThreshold": "5",
+ "actualValue": "0.6562109862671661"
+ },
+ {
+ "status": "OK",
+ "metricKey": "reopened_issues",
+ "comparator": "GT",
+ "periodIndex": 3,
+ "warningThreshold": "0",
+ "actualValue": "0"
+ },
+ {
+ "status": "WARN",
+ "metricKey": "open_issues",
+ "comparator": "GT",
+ "periodIndex": 3,
+ "warningThreshold": "0",
+ "actualValue": "17"
+ },
+ {
+ "status": "OK",
+ "metricKey": "skipped_tests",
+ "comparator": "GT",
+ "periodIndex": 5,
+ "warningThreshold": "0",
+ "actualValue": "0"
+ }
+ ],
+ "periods": [
+ {
+ "index": 1,
+ "mode": "last_period",
+ "date": "2000-04-27T00:45:23+0200"
+ },
+ {
+ "index": 2,
+ "mode": "last_version",
+ "date": "2000-04-27T00:45:23+0200",
+ "parameter": "2015-12-07"
+ },
+ {
+ "index": 3,
+ "mode": "last_analysis"
+ },
+ {
+ "index": 5,
+ "mode": "last_30_days",
+ "parameter": "2015-11-07"
+ }
+ ]
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/ActivityActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/ActivityActionTest.java
index 6a0d284415d..a3f97031f12 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/ActivityActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/ActivityActionTest.java
@@ -95,6 +95,7 @@ public class ActivityActionTest {
assertThat(activityResponse.getTasks(0).getId()).isEqualTo("T2");
assertThat(activityResponse.getTasks(0).getStatus()).isEqualTo(WsCe.TaskStatus.FAILED);
assertThat(activityResponse.getTasks(0).getComponentId()).isEqualTo("PROJECT_2");
+ assertThat(activityResponse.getTasks(0).getAnalysisId()).isEqualTo("123456");
assertThat(activityResponse.getTasks(0).getExecutionTimeMs()).isEqualTo(500L);
assertThat(activityResponse.getTasks(0).getLogs()).isFalse();
assertThat(activityResponse.getTasks(1).getId()).isEqualTo("T1");
@@ -237,6 +238,7 @@ public class ActivityActionTest {
CeActivityDto activityDto = new CeActivityDto(queueDto);
activityDto.setStatus(status);
activityDto.setExecutionTimeMs(500L);
+ activityDto.setSnapshotId(123_456L);
dbTester.getDbClient().ceActivityDao().insert(dbTester.getSession(), activityDto);
dbTester.commit();
return activityDto;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/ComponentActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/ComponentActionTest.java
index 15c2dffa707..73c397f8b4b 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/ComponentActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/ComponentActionTest.java
@@ -71,7 +71,7 @@ public class ComponentActionTest {
.setMediaType(MediaTypes.PROTOBUF)
.execute();
- WsCe.ProjectResponse response = Protobuf.read(wsResponse.getInputStream(), WsCe.ProjectResponse.PARSER);
+ WsCe.ProjectResponse response = Protobuf.read(wsResponse.getInputStream(), WsCe.ProjectResponse.parser());
assertThat(response.getQueueCount()).isEqualTo(0);
assertThat(response.hasCurrent()).isFalse();
}
@@ -90,7 +90,7 @@ public class ComponentActionTest {
.setMediaType(MediaTypes.PROTOBUF)
.execute();
- WsCe.ProjectResponse response = Protobuf.read(wsResponse.getInputStream(), WsCe.ProjectResponse.PARSER);
+ WsCe.ProjectResponse response = Protobuf.read(wsResponse.getInputStream(), WsCe.ProjectResponse.parser());
assertThat(response.getQueueCount()).isEqualTo(2);
assertThat(response.getQueue(0).getId()).isEqualTo("T4");
assertThat(response.getQueue(1).getId()).isEqualTo("T5");
@@ -113,7 +113,7 @@ public class ComponentActionTest {
.setMediaType(MediaTypes.PROTOBUF)
.execute();
- WsCe.ProjectResponse response = Protobuf.read(wsResponse.getInputStream(), WsCe.ProjectResponse.PARSER);
+ WsCe.ProjectResponse response = Protobuf.read(wsResponse.getInputStream(), WsCe.ProjectResponse.parser());
assertThat(response.getQueueCount()).isEqualTo(0);
// T3 is the latest task executed on PROJECT_1 ignoring Canceled ones
assertThat(response.hasCurrent()).isTrue();
@@ -139,6 +139,7 @@ public class ComponentActionTest {
CeActivityDto activityDto = new CeActivityDto(queueDto);
activityDto.setStatus(status);
activityDto.setExecutionTimeMs(500L);
+ activityDto.setSnapshotId(123_456L);
dbTester.getDbClient().ceActivityDao().insert(dbTester.getSession(), activityDto);
dbTester.getSession().commit();
return activityDto;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskActionTest.java
index a67dcbd65df..4bb1ee8da09 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskActionTest.java
@@ -111,6 +111,7 @@ public class TaskActionTest {
CeActivityDto activityDto = new CeActivityDto(queueDto);
activityDto.setStatus(CeActivityDto.Status.FAILED);
activityDto.setExecutionTimeMs(500L);
+ activityDto.setSnapshotId(123_456L);
dbTester.getDbClient().ceActivityDao().insert(dbTester.getSession(), activityDto);
dbTester.commit();
@@ -120,13 +121,15 @@ public class TaskActionTest {
.execute();
WsCe.TaskResponse taskResponse = Protobuf.read(wsResponse.getInputStream(), WsCe.TaskResponse.PARSER);
- assertThat(taskResponse.getTask().getId()).isEqualTo("TASK_1");
- assertThat(taskResponse.getTask().getStatus()).isEqualTo(WsCe.TaskStatus.FAILED);
- assertThat(taskResponse.getTask().getComponentId()).isEqualTo(project.uuid());
- assertThat(taskResponse.getTask().getComponentKey()).isEqualTo(project.key());
- assertThat(taskResponse.getTask().getComponentName()).isEqualTo(project.name());
- assertThat(taskResponse.getTask().getExecutionTimeMs()).isEqualTo(500L);
- assertThat(taskResponse.getTask().getLogs()).isFalse();
+ WsCe.Task task = taskResponse.getTask();
+ assertThat(task.getId()).isEqualTo("TASK_1");
+ assertThat(task.getStatus()).isEqualTo(WsCe.TaskStatus.FAILED);
+ assertThat(task.getComponentId()).isEqualTo(project.uuid());
+ assertThat(task.getComponentKey()).isEqualTo(project.key());
+ assertThat(task.getComponentName()).isEqualTo(project.name());
+ assertThat(task.getAnalysisId()).isEqualTo("123456");
+ assertThat(task.getExecutionTimeMs()).isEqualTo(500L);
+ assertThat(task.getLogs()).isFalse();
}
@Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskFormatterTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskFormatterTest.java
index cca32b55a95..97465abc6fd 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskFormatterTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/ws/TaskFormatterTest.java
@@ -30,7 +30,6 @@ import org.mockito.Mockito;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.ce.CeActivityDto;
import org.sonar.db.ce.CeQueueDto;
@@ -177,6 +176,7 @@ public class TaskFormatterTest {
assertThat(wsTask.getLogs()).isFalse();
assertThat(wsTask.getSubmittedAt()).isEqualTo(DateUtils.formatDateTime(new Date(1_450_000_000_000L)));
assertThat(wsTask.getExecutionTimeMs()).isEqualTo(500L);
+ assertThat(wsTask.getAnalysisId()).isEqualTo("123456");
assertThat(wsTask.getLogs()).isFalse();
}
@@ -209,6 +209,7 @@ public class TaskFormatterTest {
CeActivityDto activityDto = new CeActivityDto(queueDto);
activityDto.setStatus(status);
activityDto.setExecutionTimeMs(500L);
+ activityDto.setSnapshotId(123_456L);
return activityDto;
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ProjectStatusActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ProjectStatusActionTest.java
new file mode 100644
index 00000000000..a11313e030d
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ProjectStatusActionTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+package org.sonar.server.qualitygate.ws;
+
+import com.google.common.base.Throwables;
+import java.io.IOException;
+import org.apache.commons.io.IOUtils;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.utils.System2;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.SnapshotDto;
+import org.sonar.db.measure.MeasureDto;
+import org.sonar.db.metric.MetricDto;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.WsActionTester;
+import org.sonar.test.DbTests;
+import org.sonarqube.ws.MediaTypes;
+import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse;
+import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse.Status;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.db.component.ComponentTesting.newProjectDto;
+import static org.sonar.db.component.SnapshotTesting.newSnapshotForProject;
+import static org.sonar.db.measure.MeasureTesting.newMeasureDto;
+import static org.sonar.db.metric.MetricTesting.newMetricDto;
+import static org.sonar.test.JsonAssert.assertJson;
+
+@Category(DbTests.class)
+public class ProjectStatusActionTest {
+ private static final String ANALYSIS_ID = "task-uuid";
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
+ @Rule
+ public DbTester db = DbTester.create(System2.INSTANCE);
+
+ WsActionTester ws;
+ DbClient dbClient;
+ DbSession dbSession;
+
+ @Before
+ public void setUp() {
+ dbClient = db.getDbClient();
+ dbSession = db.getSession();
+
+ ws = new WsActionTester(new ProjectStatusAction(dbClient, userSession));
+ userSession.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+ }
+
+ @Test
+ public void json_example() throws IOException {
+ ComponentDto project = newProjectDto("project-uuid");
+ dbClient.componentDao().insert(dbSession, project);
+ SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newSnapshotForProject(project)
+ .setPeriodMode(1, "last_period")
+ .setPeriodDate(1, 956789123456L)
+ .setPeriodMode(2, "last_version")
+ .setPeriodParam(2, "2015-12-07")
+ .setPeriodDate(2, 956789123987L)
+ .setPeriodMode(3, "last_analysis")
+ .setPeriodMode(5, "last_30_days")
+ .setPeriodParam(5, "2015-11-07"));
+ MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
+ .setEnabled(true)
+ .setKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY));
+ dbClient.measureDao().insert(dbSession,
+ newMeasureDto(metric, snapshot.getId())
+ .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
+ dbSession.commit();
+
+ String response = ws.newRequest()
+ .setParam("analysisId", snapshot.getId().toString())
+ .execute().getInput();
+
+ assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
+ }
+
+ @Test
+ public void fail_if_no_snapshot_id_found() {
+ expectedException.expect(NotFoundException.class);
+ expectedException.expectMessage("Analysis with id 'task-uuid' is not found");
+
+ newRequest(ANALYSIS_ID);
+ }
+
+ @Test
+ public void return_undefined_status_if_measure_is_not_found() {
+ ComponentDto project = newProjectDto("project-uuid");
+ dbClient.componentDao().insert(dbSession, project);
+ SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newSnapshotForProject(project));
+ dbSession.commit();
+
+ ProjectStatusWsResponse result = newRequest(snapshot.getId().toString());
+
+ assertThat(result.getProjectStatus().getStatus()).isEqualTo(Status.NONE);
+ assertThat(result.getProjectStatus().getConditionsCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void return_undefined_status_if_measure_data_is_not_well_formatted() {
+ userSession.setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+ ComponentDto project = newProjectDto("project-uuid");
+ dbClient.componentDao().insert(dbSession, project);
+ SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newSnapshotForProject(project));
+ MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
+ .setEnabled(true)
+ .setKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY));
+ MeasureDto measure = newMeasureDto(metric, snapshot.getId()).setData("");
+ dbClient.measureDao().insert(dbSession, measure);
+ dbSession.commit();
+
+ ProjectStatusWsResponse result = newRequest(String.valueOf(snapshot.getId()));
+
+ assertThat(result.getProjectStatus().getStatus()).isEqualTo(Status.NONE);
+ assertThat(result.getProjectStatus().getConditionsCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void fail_if_insufficient_privileges() {
+ userSession.setGlobalPermissions(GlobalPermissions.PREVIEW_EXECUTION);
+ expectedException.expect(ForbiddenException.class);
+
+ newRequest(ANALYSIS_ID);
+ }
+
+ private ProjectStatusWsResponse newRequest(String taskId) {
+ try {
+ return ProjectStatusWsResponse.parseFrom(
+ ws.newRequest()
+ .setParam("analysisId", taskId)
+ .setMediaType(MediaTypes.PROTOBUF)
+ .execute().getInputStream());
+ } catch (IOException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatterTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatterTest.java
new file mode 100644
index 00000000000..59488690f8a
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatterTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+
+package org.sonar.server.qualitygate.ws;
+
+import java.io.IOException;
+import java.util.List;
+import org.apache.commons.io.IOUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.db.component.SnapshotDto;
+import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse;
+import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse.ProjectStatus;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class QualityGateDetailsFormatterTest {
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ QualityGateDetailsFormatter underTest;
+
+ @Test
+ public void map_level_conditions_and_periods() throws IOException {
+ String measureData = IOUtils.toString(getClass().getResource("QualityGateDetailsFormatterTest/quality_gate_details.json"));
+ SnapshotDto snapshot = new SnapshotDto()
+ .setPeriodMode(1, "last_period")
+ .setPeriodDate(1, 1449490731764L)
+ .setPeriodMode(2, "last_version")
+ .setPeriodParam(2, "2015-12-07")
+ .setPeriodDate(2, 1449404331764L)
+ .setPeriodMode(3, "last_analysis")
+ .setPeriodMode(5, "last_30_days")
+ .setPeriodParam(5, "2015-11-07");
+ underTest = new QualityGateDetailsFormatter(measureData, snapshot);
+
+ ProjectStatus result = underTest.format();
+
+ assertThat(result.getStatus()).isEqualTo(ProjectStatusWsResponse.Status.ERROR);
+ // check conditions
+ assertThat(result.getConditionsCount()).isEqualTo(5);
+ List<ProjectStatusWsResponse.Condition> conditions = result.getConditionsList();
+ assertThat(conditions).extracting("status").containsExactly(
+ ProjectStatusWsResponse.Status.ERROR,
+ ProjectStatusWsResponse.Status.ERROR,
+ ProjectStatusWsResponse.Status.OK,
+ ProjectStatusWsResponse.Status.OK,
+ ProjectStatusWsResponse.Status.WARN);
+ assertThat(conditions).extracting("metricKey").containsExactly("new_coverage", "new_blocker_violations", "new_critical_violations", "new_sqale_debt_ratio",
+ "new_sqale_debt_ratio");
+ assertThat(conditions).extracting("comparator").containsExactly(
+ ProjectStatusWsResponse.Comparator.LT,
+ ProjectStatusWsResponse.Comparator.GT,
+ ProjectStatusWsResponse.Comparator.NE,
+ ProjectStatusWsResponse.Comparator.EQ,
+ ProjectStatusWsResponse.Comparator.LT);
+ assertThat(conditions).extracting("periodIndex").containsExactly(1, 2, 3, 4, 5);
+ assertThat(conditions).extracting("warningThreshold").containsOnly("80", "");
+ assertThat(conditions).extracting("errorThreshold").containsOnly("85", "0", "5");
+ assertThat(conditions).extracting("actualValue").containsExactly("82.2985024398452", "1", "0", "0.5670339761248853", "0.5670339761248853");
+
+ // check periods
+ assertThat(result.getPeriodsCount()).isEqualTo(4);
+ List<ProjectStatusWsResponse.Period> periods = result.getPeriodsList();
+ assertThat(periods).extracting("index").containsExactly(1, 2, 3, 5);
+ assertThat(periods).extracting("mode").containsExactly("last_period", "last_version", "last_analysis", "last_30_days");
+ assertThat(periods).extracting("parameter").containsExactly("", "2015-12-07", "", "2015-11-07");
+ System.out.println(System.currentTimeMillis());
+ assertThat(periods.get(0).getDate()).startsWith("2015-12-07T");
+ assertThat(periods.get(1).getDate()).startsWith("2015-12-06T");
+ }
+
+ @Test
+ public void undefined_quality_gate_when_ill_formatted_measure_data() {
+ underTest = new QualityGateDetailsFormatter("", new SnapshotDto());
+
+ ProjectStatus result = underTest.format();
+
+ assertThat(result.getStatus()).isEqualTo(ProjectStatusWsResponse.Status.NONE);
+ assertThat(result.getPeriodsCount()).isEqualTo(0);
+ assertThat(result.getConditionsCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void fail_when_measure_level_is_unknown() {
+ String measureData = "{\n" +
+ " \"level\": \"UNKNOWN\",\n" +
+ " \"conditions\": [\n" +
+ " {\n" +
+ " \"metric\": \"new_coverage\",\n" +
+ " \"op\": \"LT\",\n" +
+ " \"period\": 1,\n" +
+ " \"warning\": \"80\",\n" +
+ " \"error\": \"85\",\n" +
+ " \"actual\": \"82.2985024398452\",\n" +
+ " \"level\": \"ERROR\"\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+ underTest = new QualityGateDetailsFormatter(measureData, new SnapshotDto());
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Unknown quality gate status 'UNKNOWN'");
+
+ underTest.format();
+ }
+
+ @Test
+ public void fail_when_measure_op_is_unknown() {
+ String measureData = "{\n" +
+ " \"level\": \"ERROR\",\n" +
+ " \"conditions\": [\n" +
+ " {\n" +
+ " \"metric\": \"new_coverage\",\n" +
+ " \"op\": \"UNKNOWN\",\n" +
+ " \"period\": 1,\n" +
+ " \"warning\": \"80\",\n" +
+ " \"error\": \"85\",\n" +
+ " \"actual\": \"82.2985024398452\",\n" +
+ " \"level\": \"ERROR\"\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+ underTest = new QualityGateDetailsFormatter(measureData, new SnapshotDto());
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Unknown quality gate comparator 'UNKNOWN'");
+
+ underTest.format();
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/tester/UserSessionRule.java b/server/sonar-server/src/test/java/org/sonar/server/tester/UserSessionRule.java
index 4a35ad5473e..9cac2c7efcc 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/tester/UserSessionRule.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/tester/UserSessionRule.java
@@ -20,6 +20,7 @@
package org.sonar.server.tester;
import com.google.common.base.Preconditions;
+import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Set;
@@ -289,6 +290,11 @@ public class UserSessionRule implements TestRule, UserSession {
}
@Override
+ public UserSession checkAnyGlobalPermissions(Collection<String> globalPermissions) {
+ return currentUserSession.checkAnyGlobalPermissions(globalPermissions);
+ }
+
+ @Override
public boolean hasGlobalPermission(String globalPermission) {
return currentUserSession.hasGlobalPermission(globalPermission);
}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualitygate/ws/ProjectStatusActionTest/measure_data.json b/server/sonar-server/src/test/resources/org/sonar/server/qualitygate/ws/ProjectStatusActionTest/measure_data.json
new file mode 100644
index 00000000000..679e0795c0e
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/qualitygate/ws/ProjectStatusActionTest/measure_data.json
@@ -0,0 +1,66 @@
+{
+ "level": "ERROR",
+ "conditions": [
+ {
+ "metric": "new_coverage",
+ "op": "LT",
+ "period": 1,
+ "error": "85",
+ "actual": "82.50562381034781",
+ "level": "ERROR"
+ },
+ {
+ "metric": "new_blocker_violations",
+ "op": "GT",
+ "period": 1,
+ "warning": "",
+ "error": "0",
+ "actual": "14",
+ "level": "ERROR"
+ },
+ {
+ "metric": "new_critical_violations",
+ "op": "GT",
+ "period": 1,
+ "warning": "",
+ "error": "0",
+ "actual": "1",
+ "level": "ERROR"
+ },
+ {
+ "metric": "new_sqale_debt_ratio",
+ "op": "GT",
+ "period": 2,
+ "warning": "",
+ "error": "5",
+ "actual": "0.6562109862671661",
+ "level": "OK"
+ },
+ {
+ "metric": "reopened_issues",
+ "op": "GT",
+ "period": 3,
+ "warning": "0",
+ "actual": "0",
+ "level": "OK"
+ },
+ {
+ "metric": "open_issues",
+ "op": "GT",
+ "period": 3,
+ "warning": "0",
+ "error": "",
+ "actual": "17",
+ "level": "WARN"
+ },
+ {
+ "metric": "skipped_tests",
+ "op": "GT",
+ "period": 5,
+ "warning": "0",
+ "error": "",
+ "actual": "0",
+ "level": "OK"
+ }
+ ]
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatterTest/quality_gate_details.json b/server/sonar-server/src/test/resources/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatterTest/quality_gate_details.json
new file mode 100644
index 00000000000..4122aa76dd2
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatterTest/quality_gate_details.json
@@ -0,0 +1,50 @@
+{
+ "level": "ERROR",
+ "conditions": [
+ {
+ "metric": "new_coverage",
+ "op": "LT",
+ "period": 1,
+ "warning": "80",
+ "error": "85",
+ "actual": "82.2985024398452",
+ "level": "ERROR"
+ },
+ {
+ "metric": "new_blocker_violations",
+ "op": "GT",
+ "period": 2,
+ "warning": "",
+ "error": "0",
+ "actual": "1",
+ "level": "ERROR"
+ },
+ {
+ "metric": "new_critical_violations",
+ "op": "NE",
+ "period": 3,
+ "warning": "",
+ "error": "0",
+ "actual": "0",
+ "level": "OK"
+ },
+ {
+ "metric": "new_sqale_debt_ratio",
+ "op": "EQ",
+ "period": 4,
+ "warning": "",
+ "error": "5",
+ "actual": "0.5670339761248853",
+ "level": "OK"
+ },
+ {
+ "metric": "new_sqale_debt_ratio",
+ "op": "LT",
+ "period": 5,
+ "warning": "",
+ "error": "5",
+ "actual": "0.5670339761248853",
+ "level": "WARN"
+ }
+ ]
+}
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1004_add_ce_activity_snapshot_id.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1004_add_ce_activity_snapshot_id.rb
index b2e67caa934..9f41f740617 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1004_add_ce_activity_snapshot_id.rb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1004_add_ce_activity_snapshot_id.rb
@@ -25,7 +25,7 @@
class AddCeActivitySnapshotId < ActiveRecord::Migration
def self.up
- add_column 'ce_activity', :snapshot_id, :integer, :null => true
+ add_column 'ce_activity', :snapshot_id, :big_integer, :null => true
end
end
diff --git a/sonar-db/src/main/java/org/sonar/db/ce/CeActivityDto.java b/sonar-db/src/main/java/org/sonar/db/ce/CeActivityDto.java
index db945aa9986..4119a12d4d9 100644
--- a/sonar-db/src/main/java/org/sonar/db/ce/CeActivityDto.java
+++ b/sonar-db/src/main/java/org/sonar/db/ce/CeActivityDto.java
@@ -66,17 +66,19 @@ public class CeActivityDto {
return uuid;
}
- public void setUuid(String s) {
+ public CeActivityDto setUuid(String s) {
checkArgument(s.length() <= 40, "Value is too long for column CE_ACTIVITY.UUID: %s", s);
this.uuid = s;
+ return this;
}
public String getTaskType() {
return taskType;
}
- public void setTaskType(String s) {
+ public CeActivityDto setTaskType(String s) {
this.taskType = s;
+ return this;
}
@CheckForNull
@@ -84,25 +86,28 @@ public class CeActivityDto {
return componentUuid;
}
- public void setComponentUuid(@Nullable String s) {
+ public CeActivityDto setComponentUuid(@Nullable String s) {
checkArgument(s == null || s.length() <= 40, "Value is too long for column CE_ACTIVITY.COMPONENT_UUID: %s", s);
this.componentUuid = s;
+ return this;
}
public Status getStatus() {
return status;
}
- public void setStatus(Status s) {
+ public CeActivityDto setStatus(Status s) {
this.status = s;
+ return this;
}
public boolean getIsLast() {
return isLast;
}
- void setIsLast(boolean b) {
+ CeActivityDto setIsLast(boolean b) {
this.isLast = b;
+ return this;
}
public String getIsLastKey() {
@@ -118,8 +123,9 @@ public class CeActivityDto {
return submittedAt;
}
- public void setSubmittedAt(long submittedAt) {
+ public CeActivityDto setSubmittedAt(long submittedAt) {
this.submittedAt = submittedAt;
+ return this;
}
@CheckForNull
@@ -127,8 +133,9 @@ public class CeActivityDto {
return startedAt;
}
- public void setStartedAt(@Nullable Long l) {
+ public CeActivityDto setStartedAt(@Nullable Long l) {
this.startedAt = l;
+ return this;
}
@CheckForNull
@@ -136,24 +143,27 @@ public class CeActivityDto {
return executedAt;
}
- public void setExecutedAt(@Nullable Long l) {
+ public CeActivityDto setExecutedAt(@Nullable Long l) {
this.executedAt = l;
+ return this;
}
public long getCreatedAt() {
return createdAt;
}
- public void setCreatedAt(long l) {
+ public CeActivityDto setCreatedAt(long l) {
this.createdAt = l;
+ return this;
}
public long getUpdatedAt() {
return updatedAt;
}
- public void setUpdatedAt(long l) {
+ public CeActivityDto setUpdatedAt(long l) {
this.updatedAt = l;
+ return this;
}
@CheckForNull
@@ -161,9 +171,10 @@ public class CeActivityDto {
return executionTimeMs;
}
- public void setExecutionTimeMs(@Nullable Long l) {
+ public CeActivityDto setExecutionTimeMs(@Nullable Long l) {
checkArgument(l == null || l >= 0, "Execution time must be positive: %s", l);
this.executionTimeMs = l;
+ return this;
}
@CheckForNull
diff --git a/sonar-db/src/main/java/org/sonar/db/ce/CeQueueDto.java b/sonar-db/src/main/java/org/sonar/db/ce/CeQueueDto.java
index 3031029c0bd..524a93bd713 100644
--- a/sonar-db/src/main/java/org/sonar/db/ce/CeQueueDto.java
+++ b/sonar-db/src/main/java/org/sonar/db/ce/CeQueueDto.java
@@ -44,9 +44,10 @@ public class CeQueueDto {
return uuid;
}
- public void setUuid(String s) {
+ public CeQueueDto setUuid(String s) {
checkArgument(s.length() <= 40, "Value of UUID is too long: %s", s);
this.uuid = s;
+ return this;
}
@CheckForNull
@@ -54,26 +55,29 @@ public class CeQueueDto {
return componentUuid;
}
- public void setComponentUuid(@Nullable String s) {
+ public CeQueueDto setComponentUuid(@Nullable String s) {
checkArgument(s == null || s.length() <= 40, "Value of component UUID is too long: %s", s);
this.componentUuid = s;
+ return this;
}
public Status getStatus() {
return status;
}
- public void setStatus(Status s) {
+ public CeQueueDto setStatus(Status s) {
this.status = s;
+ return this;
}
public String getTaskType() {
return taskType;
}
- public void setTaskType(String s) {
+ public CeQueueDto setTaskType(String s) {
checkArgument(s.length() <= 15, "Value of task type is too long: %s", s);
this.taskType = s;
+ return this;
}
@CheckForNull
@@ -81,9 +85,10 @@ public class CeQueueDto {
return submitterLogin;
}
- public void setSubmitterLogin(@Nullable String s) {
+ public CeQueueDto setSubmitterLogin(@Nullable String s) {
checkArgument(s == null || s.length() <= 255, "Value of submitter login is too long: %s", s);
this.submitterLogin = s;
+ return this;
}
@CheckForNull
@@ -91,24 +96,27 @@ public class CeQueueDto {
return startedAt;
}
- public void setStartedAt(@Nullable Long l) {
+ public CeQueueDto setStartedAt(@Nullable Long l) {
this.startedAt = l;
+ return this;
}
public long getCreatedAt() {
return createdAt;
}
- public void setCreatedAt(long l) {
+ public CeQueueDto setCreatedAt(long l) {
this.createdAt = l;
+ return this;
}
public long getUpdatedAt() {
return updatedAt;
}
- public void setUpdatedAt(long l) {
+ public CeQueueDto setUpdatedAt(long l) {
this.updatedAt = l;
+ return this;
}
@Override
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 1050b096954..c19c97a0800 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
@@ -95,7 +95,7 @@
values (
#{uuid,jdbcType=VARCHAR},
#{componentUuid,jdbcType=VARCHAR},
- #{snapshotId,jdbcType=INTEGER},
+ #{snapshotId,jdbcType=BIGINT},
#{status,jdbcType=VARCHAR},
#{taskType,jdbcType=VARCHAR},
#{isLast,jdbcType=BOOLEAN},
diff --git a/sonar-db/src/test/java/org/sonar/db/ce/CeQueueTesting.java b/sonar-db/src/test/java/org/sonar/db/ce/CeQueueTesting.java
new file mode 100644
index 00000000000..bb46b3e6923
--- /dev/null
+++ b/sonar-db/src/test/java/org/sonar/db/ce/CeQueueTesting.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package org.sonar.db.ce;
+
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
+import static org.apache.commons.lang.math.RandomUtils.nextLong;
+
+public class CeQueueTesting {
+ private CeQueueTesting() {
+ // static methods only
+ }
+
+ public static CeQueueDto newCeQueueDto(String uuid) {
+ return new CeQueueDto()
+ .setUuid(uuid)
+ .setComponentUuid(randomAlphanumeric(40))
+ .setStatus(CeQueueDto.Status.PENDING)
+ .setTaskType(CeTaskTypes.REPORT)
+ .setSubmitterLogin(randomAlphanumeric(255))
+ .setCreatedAt(nextLong())
+ .setUpdatedAt(nextLong())
+ .setStartedAt(nextLong());
+ }
+}
diff --git a/sonar-db/src/test/java/org/sonar/db/measure/MeasureTesting.java b/sonar-db/src/test/java/org/sonar/db/measure/MeasureTesting.java
new file mode 100644
index 00000000000..229d487c2d8
--- /dev/null
+++ b/sonar-db/src/test/java/org/sonar/db/measure/MeasureTesting.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+package org.sonar.db.measure;
+
+import org.sonar.db.metric.MetricDto;
+
+import static org.apache.commons.lang.math.RandomUtils.nextInt;
+
+public class MeasureTesting {
+ private MeasureTesting() {
+ // static methods only
+ }
+
+ public static MeasureDto newMeasureDto(MetricDto metricDto, long snapshotId) {
+ return new MeasureDto()
+ .setMetricId(metricDto.getId())
+ .setMetricKey(metricDto.getKey())
+ .setSnapshotId((long) nextInt())
+ .setComponentId((long) nextInt())
+ .setSnapshotId(snapshotId);
+ }
+}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpWsClient.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpWsClient.java
index d172f4bbf88..0435aed90a8 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpWsClient.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpWsClient.java
@@ -23,6 +23,7 @@ package org.sonarqube.ws.client;
import org.sonarqube.ws.client.component.ComponentsService;
import org.sonarqube.ws.client.issue.IssuesService;
import org.sonarqube.ws.client.permission.PermissionsService;
+import org.sonarqube.ws.client.qualitygate.QualityGatesService;
import org.sonarqube.ws.client.qualityprofile.QualityProfilesService;
import org.sonarqube.ws.client.usertoken.UserTokensService;
@@ -38,6 +39,7 @@ public class HttpWsClient implements WsClient {
private final QualityProfilesService qualityProfilesService;
private final IssuesService issuesService;
private final UserTokensService userTokensService;
+ private final QualityGatesService qualityGatesService;
private final WsConnector wsConnector;
public HttpWsClient(WsConnector wsConnector) {
@@ -47,6 +49,7 @@ public class HttpWsClient implements WsClient {
this.qualityProfilesService = new QualityProfilesService(wsConnector);
this.issuesService = new IssuesService(wsConnector);
this.userTokensService = new UserTokensService(wsConnector);
+ this.qualityGatesService = new QualityGatesService(wsConnector);
}
@Override
@@ -78,4 +81,9 @@ public class HttpWsClient implements WsClient {
public UserTokensService userTokens() {
return userTokensService;
}
+
+ @Override
+ public QualityGatesService qualityGates() {
+ return qualityGatesService;
+ }
}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java
index 3f980d7c591..67e088c46be 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java
@@ -22,6 +22,7 @@ package org.sonarqube.ws.client;
import org.sonarqube.ws.client.component.ComponentsService;
import org.sonarqube.ws.client.issue.IssuesService;
import org.sonarqube.ws.client.permission.PermissionsService;
+import org.sonarqube.ws.client.qualitygate.QualityGatesService;
import org.sonarqube.ws.client.qualityprofile.QualityProfilesService;
import org.sonarqube.ws.client.usertoken.UserTokensService;
@@ -39,5 +40,7 @@ public interface WsClient {
UserTokensService userTokens();
+ QualityGatesService qualityGates();
+
WsConnector wsConnector();
}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/ProjectStatusWsRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/ProjectStatusWsRequest.java
new file mode 100644
index 00000000000..b9d435ff065
--- /dev/null
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/ProjectStatusWsRequest.java
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+package org.sonarqube.ws.client.qualitygate;
+
+public class ProjectStatusWsRequest {
+ private String taskId;
+
+ public String getAnalysisId() {
+ return taskId;
+ }
+
+ public ProjectStatusWsRequest setAnalysisId(String taskId) {
+ this.taskId = taskId;
+ return this;
+ }
+}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesService.java
new file mode 100644
index 00000000000..404619e1814
--- /dev/null
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+package org.sonarqube.ws.client.qualitygate;
+
+import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse;
+import org.sonarqube.ws.client.BaseService;
+import org.sonarqube.ws.client.GetRequest;
+import org.sonarqube.ws.client.WsConnector;
+
+public class QualityGatesService extends BaseService {
+
+ public QualityGatesService(WsConnector wsConnector) {
+ super(wsConnector, "api/qualitygates");
+ }
+
+ public ProjectStatusWsResponse projectStatus(ProjectStatusWsRequest request) {
+ return call(new GetRequest(path("project_status"))
+ .setParam("analysisId", request.getAnalysisId()),
+ ProjectStatusWsResponse.parser());
+ }
+}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/package-info.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/package-info.java
new file mode 100644
index 00000000000..084636cef47
--- /dev/null
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/package-info.java
@@ -0,0 +1,26 @@
+
+/*
+ * 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.
+ */
+
+@ParametersAreNonnullByDefault
+package org.sonarqube.ws.client.qualitygate;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
diff --git a/sonar-ws/src/main/protobuf/ws-ce.proto b/sonar-ws/src/main/protobuf/ws-ce.proto
index b6d930a8f02..9c27b02f4c9 100644
--- a/sonar-ws/src/main/protobuf/ws-ce.proto
+++ b/sonar-ws/src/main/protobuf/ws-ce.proto
@@ -61,14 +61,15 @@ message Task {
optional string componentKey = 4;
optional string componentName = 5;
optional string componentQualifier = 6;
- optional TaskStatus status = 7;
- optional string submittedAt = 8;
- optional string submitterLogin = 9;
- optional string startedAt = 10;
- optional string executedAt = 11;
- optional bool isLastExecuted = 12;
- optional int64 executionTimeMs = 13;
- optional bool logs = 14;
+ optional string analysisId = 7;
+ optional TaskStatus status = 8;
+ optional string submittedAt = 9;
+ optional string submitterLogin = 10;
+ optional string startedAt = 11;
+ optional string executedAt = 12;
+ optional bool isLastExecuted = 13;
+ optional int64 executionTimeMs = 14;
+ optional bool logs = 15;
}
enum TaskStatus {
diff --git a/sonar-ws/src/main/protobuf/ws-qualitygates.proto b/sonar-ws/src/main/protobuf/ws-qualitygates.proto
new file mode 100644
index 00000000000..f4669419d86
--- /dev/null
+++ b/sonar-ws/src/main/protobuf/ws-qualitygates.proto
@@ -0,0 +1,69 @@
+// SonarQube, open source software quality management tool.
+// Copyright (C) 2008-2015 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.
+
+syntax = "proto2";
+
+package sonarqube.ws.qualitygate;
+
+import "ws-commons.proto";
+
+option java_package = "org.sonarqube.ws";
+option java_outer_classname = "WsQualityGates";
+option optimize_for = SPEED;
+
+// GET api/qualitygates/project_status
+message ProjectStatusWsResponse {
+ optional ProjectStatus projectStatus = 1;
+
+ message ProjectStatus {
+ optional Status status = 1;
+ repeated Condition conditions = 2;
+ repeated Period periods = 3;
+ }
+
+ message Condition {
+ optional Status status = 1;
+ optional string metricKey = 2;
+ optional Comparator comparator = 3;
+ optional int32 periodIndex = 4;
+ optional string warningThreshold = 5;
+ optional string errorThreshold = 6;
+ optional string actualValue = 7;
+ }
+
+ message Period {
+ optional int32 index = 1;
+ optional string mode = 2;
+ optional string date = 3;
+ optional string parameter = 4;
+ }
+
+ enum Status {
+ OK = 1;
+ WARN = 2;
+ ERROR = 3;
+ NONE = 4;
+ }
+
+ enum Comparator {
+ GT = 1;
+ LT = 2;
+ EQ = 3;
+ NE = 4;
+ }
+}