Skip to content

Commit

Permalink
SONAR-8116 Return rating metrics in api/qualitygates/app
Browse files Browse the repository at this point in the history
  • Loading branch information
julienlancelot committed Sep 22, 2016
1 parent fe748d1 commit 1d84558
Show file tree
Hide file tree
Showing 8 changed files with 273 additions and 222 deletions.
Expand Up @@ -51,7 +51,6 @@
import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.Message; import org.sonar.server.exceptions.Message;
import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.ServerException;
import org.sonar.server.user.UserSession; import org.sonar.server.user.UserSession;
import org.sonar.server.util.Validation; import org.sonar.server.util.Validation;


Expand Down Expand Up @@ -242,23 +241,6 @@ public void dissociateProject(Long qGateId, Long projectId) {
} }
} }


public Collection<Metric> gateMetrics() {
return metricFinder.findAll().stream()
.filter(QualityGates::isAvailableForInit)
.collect(Collectors.toList());
}

public boolean currentUserHasWritePermission() {
boolean hasWritePermission = false;
try {
checkPermission();
hasWritePermission = true;
} catch (ServerException unallowed) {
// Ignored
}
return hasWritePermission;
}

private Collection<QualityGateConditionDto> getConditions(long qGateId, @Nullable Long conditionId) { private Collection<QualityGateConditionDto> getConditions(long qGateId, @Nullable Long conditionId) {
Collection<QualityGateConditionDto> conditions = conditionDao.selectForQualityGate(qGateId); Collection<QualityGateConditionDto> conditions = conditionDao.selectForQualityGate(qGateId);
if (conditionId == null) { if (conditionId == null) {
Expand Down Expand Up @@ -315,14 +297,14 @@ private static void validateMetric(Metric metric, Errors errors) {
errors.check(isAlertable(metric), format("Metric '%s' cannot be used to define a condition.", metric.getKey())); errors.check(isAlertable(metric), format("Metric '%s' cannot be used to define a condition.", metric.getKey()));
} }


private static boolean isAvailableForInit(Metric metric) {
return !metric.isDataType() && !CoreMetrics.ALERT_STATUS.equals(metric) && ValueType.RATING != metric.getType();
}

private static boolean isAlertable(Metric metric) { private static boolean isAlertable(Metric metric) {
return isAvailableForInit(metric) && BooleanUtils.isFalse(metric.isHidden()); return isAvailableForInit(metric) && BooleanUtils.isFalse(metric.isHidden());
} }


private static boolean isAvailableForInit(Metric metric) {
return !metric.isDataType() && !CoreMetrics.ALERT_STATUS.equals(metric) && ValueType.RATING != metric.getType();
}

private boolean isDefault(QualityGateDto qGate) { private boolean isDefault(QualityGateDto qGate) {
return qGate.getId().equals(getDefaultId()); return qGate.getId().equals(getDefaultId());
} }
Expand Down
Expand Up @@ -19,20 +19,32 @@
*/ */
package org.sonar.server.qualitygate.ws; package org.sonar.server.qualitygate.ws;


import org.apache.commons.lang.BooleanUtils; import java.util.Collection;
import org.sonar.api.measures.Metric; import java.util.stream.Collectors;
import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.text.JsonWriter; import org.sonar.db.DbClient;
import org.sonar.server.qualitygate.QualityGates; import org.sonar.db.DbSession;
import org.sonar.db.metric.MetricDto;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.WsQualityGates.AppWsResponse.Metric;

import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
import static org.sonar.api.measures.Metric.ValueType.DATA;
import static org.sonar.api.measures.Metric.ValueType.DISTRIB;
import static org.sonar.core.permission.GlobalPermissions.QUALITY_GATE_ADMIN;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.WsQualityGates.AppWsResponse;


public class AppAction implements QualityGatesWsAction { public class AppAction implements QualityGatesWsAction {


private final QualityGates qualityGates; private final UserSession userSession;
private final DbClient dbClient;


public AppAction(QualityGates qualityGates) { public AppAction(UserSession userSession, DbClient dbClient) {
this.qualityGates = qualityGates; this.userSession = userSession;
this.dbClient = dbClient;
} }


@Override @Override
Expand All @@ -47,39 +59,42 @@ public void define(WebService.NewController controller) {


@Override @Override
public void handle(Request request, Response response) { public void handle(Request request, Response response) {
JsonWriter writer = response.newJsonWriter().beginObject(); writeProtobuf(AppWsResponse.newBuilder()
addPermissions(writer); .setEdit(userSession.hasPermission(QUALITY_GATE_ADMIN))
addPeriods(writer); .addAllMetrics(loadMetrics()
addMetrics(writer); .stream()
writer.endObject().close(); .map(AppAction::toMetric)
.collect(Collectors.toList()))
.build(),
request, response);
} }


private void addPermissions(JsonWriter writer) { private static Metric toMetric(MetricDto metricDto) {
writer.prop("edit", qualityGates.currentUserHasWritePermission()); String domain = metricDto.getDomain();
Metric.Builder metricBuilder = Metric.newBuilder()
.setKey(metricDto.getKey())
.setName(metricDto.getShortName())
.setType(metricDto.getValueType())
.setHidden(metricDto.isHidden());
if (domain != null) {
metricBuilder.setDomain(domain);
}
return metricBuilder.build();
} }


private static void addPeriods(JsonWriter writer) { private Collection<MetricDto> loadMetrics() {
writer.name("periods").beginArray(); DbSession dbSession = dbClient.openSession(false);
writer.beginObject() try {
.prop("key", 1L) return dbClient.metricDao().selectEnabled(dbSession).stream()
.prop("text", "Leak") .filter(metric -> !isDataType(metric) && !ALERT_STATUS_KEY.equals(metric.getKey()))
.endObject(); .collect(Collectors.toList());
writer.endArray(); } finally {
dbClient.closeSession(dbSession);
}
} }


private void addMetrics(JsonWriter writer) { private static boolean isDataType(MetricDto metric) {
writer.name("metrics").beginArray(); return DATA.name().equals(metric.getValueType()) || DISTRIB.name().equals(metric.getValueType());
for (Metric metric : qualityGates.gateMetrics()) {
writer.beginObject()
.prop("id", metric.getId())
.prop("key", metric.getKey())
.prop("name", metric.getName())
.prop("type", metric.getType().toString())
.prop("domain", metric.getDomain())
.prop("hidden", BooleanUtils.isNotFalse(metric.isHidden()))
.endObject();
}
writer.endArray();
} }


} }
@@ -1,83 +1,19 @@
{ {
"edit": false, "edit": false,
"periods": [
{
"key": 1,
"text": "since previous analysis"
},
{
"key": 2,
"text": "over 365 days"
},
{
"key": 3,
"text": "since previous version"
},
{
"key": 4,
"text": "over period 4 - defined at project level"
},
{
"key": 5,
"text": "over period 5 - defined at project level"
}
],
"metrics": [ "metrics": [
{ {
"id": 10,
"key": "accessors", "key": "accessors",
"name": "Accessors", "name": "Accessors",
"type": "INT", "type": "INT",
"domain": "Size", "domain": "Size",
"hidden": true "hidden": true
}, },
{ {
"id": 111,
"key": "clirr_api_behavior_changes",
"name": "API behavior changes",
"type": "INT",
"domain": "API compatibility",
"hidden": false
},
{
"id": 110,
"key": "clirr_api_breaks",
"name": "API breaks",
"type": "INT",
"domain": "API compatibility",
"hidden": false
},
{
"id": 62,
"key": "blocker_violations",
"name": "Blocker issues",
"type": "INT",
"domain": "Issues",
"hidden": false
},
{
"id": 138,
"key": "blocker_remediation_cost", "key": "blocker_remediation_cost",
"name": "Blocker Technical Debt", "name": "Blocker Technical Debt",
"type": "WORK_DUR", "type": "WORK_DUR",
"domain": "SQALE", "domain": "SQALE",
"hidden": false "hidden": false
},
{
"id": 45,
"key": "conditions_to_cover",
"name": "Branches to cover",
"type": "INT",
"domain": "Tests",
"hidden": true
},
{
"id": 131,
"key": "new_it_conditions_to_cover",
"name": "Branches to cover by IT on new code",
"type": "INT",
"domain": "Tests (Integration)",
"hidden": true
} }
] ]
} }
Expand Up @@ -122,23 +122,6 @@ public void should_list_qgates() {
assertThat(underTest.list()).isEqualTo(allQgates); assertThat(underTest.list()).isEqualTo(allQgates);
} }


@Test
public void should_create_qgate() {
String name = "SG-1";
QualityGateDto sg1 = underTest.create(name);
assertThat(sg1.getName()).isEqualTo(name);
verify(dao).selectByName(name);
verify(dao).insert(sg1);
assertThat(underTest.currentUserHasWritePermission()).isTrue();
}

@Test(expected = ForbiddenException.class)
public void should_fail_create_on_anonymous() {
userSessionRule.set(unauthenticatedUserSession);
assertThat(underTest.currentUserHasWritePermission()).isFalse();
underTest.create("polop");
}

@Test(expected = ForbiddenException.class) @Test(expected = ForbiddenException.class)
public void should_fail_create_on_missing_permission() { public void should_fail_create_on_missing_permission() {
userSessionRule.set(unauthorizedUserSession); userSessionRule.set(unauthorizedUserSession);
Expand Down Expand Up @@ -637,7 +620,6 @@ public void should_list_gate_metrics() {
when(classicMetric.getType()).thenReturn(ValueType.BOOL); when(classicMetric.getType()).thenReturn(ValueType.BOOL);
when(metricFinder.findAll()).thenReturn(ImmutableList.of( when(metricFinder.findAll()).thenReturn(ImmutableList.of(
dataMetric, hiddenMetric, nullHiddenMetric, alertMetric, ratingMetric, classicMetric)); dataMetric, hiddenMetric, nullHiddenMetric, alertMetric, ratingMetric, classicMetric));
assertThat(underTest.gateMetrics()).hasSize(3).containsOnly(classicMetric, hiddenMetric, nullHiddenMetric);
} }


private Metric addMetric(String metricKey, String metricName) { private Metric addMetric(String metricKey, String metricName) {
Expand Down

0 comments on commit 1d84558

Please sign in to comment.