]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9616 Handle branch in api/settings/list_definitions
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 25 Aug 2017 12:35:39 +0000 (14:35 +0200)
committerJanos Gyerik <janos.gyerik@sonarsource.com>
Tue, 12 Sep 2017 09:34:53 +0000 (11:34 +0200)
server/sonar-server/src/main/java/org/sonar/server/setting/ws/ListDefinitionsAction.java
server/sonar-server/src/main/java/org/sonar/server/setting/ws/SetAction.java
server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingsWs.java
server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingsWsSupport.java
server/sonar-server/src/test/java/org/sonar/server/setting/ws/ListDefinitionsActionTest.java
server/sonar-server/src/test/java/org/sonar/server/setting/ws/SetActionTest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/setting/ListDefinitionsRequest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/setting/SettingsService.java
sonar-ws/src/test/java/org/sonarqube/ws/client/setting/ListDefinitionsRequestTest.java
sonar-ws/src/test/java/org/sonarqube/ws/client/setting/SettingsServiceTest.java

index 1cc3b4a39d74d89f30efa6cc4dc4368388880cc4..75293b29194b2aea34069356481aaedf27a7f017 100644 (file)
@@ -39,9 +39,11 @@ import org.sonarqube.ws.client.setting.ListDefinitionsRequest;
 import static com.google.common.base.Strings.emptyToNull;
 import static org.sonar.api.web.UserRole.USER;
 import static org.sonar.core.util.Protobuf.setNullable;
+import static org.sonar.server.setting.ws.SettingsWs.SETTING_ON_BRANCHES;
 import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
 import static org.sonarqube.ws.client.setting.SettingsWsParameters.ACTION_LIST_DEFINITIONS;
+import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_BRANCH;
 import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_COMPONENT;
 
 public class ListDefinitionsAction implements SettingsWsAction {
@@ -79,6 +81,7 @@ public class ListDefinitionsAction implements SettingsWsAction {
     action.createParam(PARAM_COMPONENT)
       .setDescription("Component key")
       .setExampleValue(KEY_PROJECT_EXAMPLE_001);
+    settingsWsSupport.addBranchParam(action);
   }
 
   @Override
@@ -93,6 +96,7 @@ public class ListDefinitionsAction implements SettingsWsAction {
     ListDefinitionsWsResponse.Builder wsResponse = ListDefinitionsWsResponse.newBuilder();
     propertyDefinitions.getAll().stream()
       .filter(definition -> qualifier.isPresent() ? definition.qualifiers().contains(qualifier.get()) : definition.global())
+      .filter(definition -> wsRequest.getBranch() == null || SETTING_ON_BRANCHES.contains(definition.key()))
       .filter(settingsWsSupport.isDefinitionVisible(component))
       .forEach(definition -> addDefinition(definition, wsResponse));
     return wsResponse.build();
@@ -101,6 +105,7 @@ public class ListDefinitionsAction implements SettingsWsAction {
   private static ListDefinitionsRequest toWsRequest(Request request) {
     return ListDefinitionsRequest.builder()
       .setComponent(request.param(PARAM_COMPONENT))
+      .setBranch(request.param(PARAM_BRANCH))
       .build();
   }
 
@@ -108,13 +113,13 @@ public class ListDefinitionsAction implements SettingsWsAction {
     return component.isPresent() ? Optional.of(component.get().qualifier()) : Optional.empty();
   }
 
-  private Optional<ComponentDto> loadComponent(ListDefinitionsRequest valuesRequest) {
+  private Optional<ComponentDto> loadComponent(ListDefinitionsRequest request) {
     try (DbSession dbSession = dbClient.openSession(false)) {
-      String componentKey = valuesRequest.getComponent();
+      String componentKey = request.getComponent();
       if (componentKey == null) {
         return Optional.empty();
       }
-      ComponentDto component = componentFinder.getByKey(dbSession, componentKey);
+      ComponentDto component = componentFinder.getByKeyAndOptionalBranch(dbSession, componentKey, request.getBranch());
       userSession.checkComponentPermission(USER, component);
       return Optional.of(component);
     }
index 910be41d4736787fd341dd960b5fbcf39ce0d9de..f4386026588b8e261572cfd922f4c591ee9657c3 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.server.setting.ws;
 
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ListMultimap;
 import com.google.gson.Gson;
 import com.google.gson.JsonSyntaxException;
@@ -59,8 +58,6 @@ import org.sonarqube.ws.client.setting.SetRequest;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static java.lang.String.format;
-import static org.sonar.core.config.CorePropertyDefinitions.LEAK_PERIOD;
-import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001;
 import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
 import static org.sonar.server.ws.WsUtils.checkRequest;
 import static org.sonarqube.ws.client.setting.SettingsWsParameters.ACTION_SET;
@@ -74,7 +71,6 @@ import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_VALUES;
 public class SetAction implements SettingsWsAction {
   private static final Collector<CharSequence, ?, String> COMMA_JOINER = Collectors.joining(",");
   private static final String MSG_NO_EMPTY_VALUE = "A non empty value must be provided";
-  public static final Set<String> SETTING_ON_BRANCHES = ImmutableSet.of(LEAK_PERIOD);
 
   private final PropertyDefinitions propertyDefinitions;
   private final DbClient dbClient;
@@ -83,9 +79,10 @@ public class SetAction implements SettingsWsAction {
   private final SettingsUpdater settingsUpdater;
   private final SettingsChangeNotifier settingsChangeNotifier;
   private final SettingValidations validations;
+  private final SettingsWsSupport settingsWsSupport;
 
   public SetAction(PropertyDefinitions propertyDefinitions, DbClient dbClient, ComponentFinder componentFinder, UserSession userSession,
-    SettingsUpdater settingsUpdater, SettingsChangeNotifier settingsChangeNotifier, SettingValidations validations) {
+    SettingsUpdater settingsUpdater, SettingsChangeNotifier settingsChangeNotifier, SettingValidations validations, SettingsWsSupport settingsWsSupport) {
     this.propertyDefinitions = propertyDefinitions;
     this.dbClient = dbClient;
     this.componentFinder = componentFinder;
@@ -93,6 +90,7 @@ public class SetAction implements SettingsWsAction {
     this.settingsUpdater = settingsUpdater;
     this.settingsChangeNotifier = settingsChangeNotifier;
     this.validations = validations;
+    this.settingsWsSupport = settingsWsSupport;
   }
 
   @Override
@@ -131,12 +129,7 @@ public class SetAction implements SettingsWsAction {
       .setDescription("Component key")
       .setDeprecatedKey("componentKey", "6.3")
       .setExampleValue(KEY_PROJECT_EXAMPLE_001);
-
-    action.createParam(PARAM_BRANCH)
-      .setDescription("Branch key. Only available on following settings : %s", SETTING_ON_BRANCHES.stream().collect(COMMA_JOINER))
-      .setExampleValue(KEY_BRANCH_EXAMPLE_001)
-      .setInternal(true)
-      .setSince("6.6");
+    settingsWsSupport.addBranchParam(action);
   }
 
   @Override
@@ -207,7 +200,8 @@ public class SetAction implements SettingsWsAction {
     SettingData settingData = new SettingData(settingKey, valuesFromRequest(request), component.orElse(null));
     ImmutableList.of(validations.scope(), validations.qualifier(), validations.valueType())
       .forEach(validation -> validation.accept(settingData));
-    component.map(ComponentDto::getBranch).ifPresent(b -> checkArgument(SETTING_ON_BRANCHES.contains(settingKey), format("Setting '%s' cannot be set on a branch", settingKey)));
+    component.map(ComponentDto::getBranch)
+      .ifPresent(b -> checkArgument(SettingsWs.SETTING_ON_BRANCHES.contains(settingKey), format("Setting '%s' cannot be set on a branch", settingKey)));
   }
 
   private static void validatePropertySet(SetRequest request, @Nullable PropertyDefinition definition) {
index 068d1b0720924815f9c87a8ad84dfe9cb8f4d43a..9a787022b01e28924a62ed58a66a52a6779efcca 100644 (file)
  */
 package org.sonar.server.setting.ws;
 
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
 import org.sonar.api.server.ws.WebService;
 
+import static org.sonar.core.config.CorePropertyDefinitions.LEAK_PERIOD;
 import static org.sonarqube.ws.client.setting.SettingsWsParameters.CONTROLLER_SETTINGS;
 
 public class SettingsWs implements WebService {
 
+  public static final Set<String> SETTING_ON_BRANCHES = ImmutableSet.of(LEAK_PERIOD);
+
   private final SettingsWsAction[] actions;
 
   public SettingsWs(SettingsWsAction... actions) {
index 86bf8bda7dbc6308033d4e9fe47b6587f5ef99cf..89541441ed581884ab5dafac2c328a4c2c80f22a 100644 (file)
@@ -21,21 +21,28 @@ package org.sonar.server.setting.ws;
 
 import java.util.Optional;
 import java.util.function.Predicate;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
 import javax.annotation.Nullable;
 import org.sonar.api.config.PropertyDefinition;
 import org.sonar.api.server.ServerSide;
+import org.sonar.api.server.ws.WebService;
 import org.sonar.db.component.ComponentDto;
-import org.sonar.server.organization.DefaultOrganizationProvider;
 import org.sonar.db.permission.OrganizationPermission;
+import org.sonar.server.organization.DefaultOrganizationProvider;
 import org.sonar.server.user.UserSession;
 
 import static org.sonar.api.PropertyType.LICENSE;
 import static org.sonar.api.web.UserRole.ADMIN;
 import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
+import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001;
+import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_BRANCH;
 
 @ServerSide
 public class SettingsWsSupport {
 
+  private static final Collector<CharSequence, ?, String> COMMA_JOINER = Collectors.joining(",");
+
   public static final String DOT_SECURED = ".secured";
   public static final String DOT_LICENSE = ".license";
   private static final String LICENSE_SUFFIX = DOT_LICENSE + DOT_SECURED;
@@ -81,4 +88,12 @@ public class SettingsWsSupport {
       .map(c -> userSession.hasComponentPermission(projectPermission, c))
       .orElse(false);
   }
+
+  WebService.NewParam addBranchParam(WebService.NewAction action){
+    return action.createParam(PARAM_BRANCH)
+      .setDescription("Branch key. Only available on following settings : %s", SettingsWs.SETTING_ON_BRANCHES.stream().collect(COMMA_JOINER))
+      .setExampleValue(KEY_BRANCH_EXAMPLE_001)
+      .setInternal(true)
+      .setSince("6.6");
+  }
 }
index 962811d1bbc1d349ee92cec19f4c1e37874e8d78..a984bbc78cf65c38d1d559f1a84fe0cf16d05fa4 100644 (file)
@@ -29,6 +29,7 @@ import org.sonar.api.config.PropertyDefinition;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.PropertyFieldDefinition;
 import org.sonar.api.server.ws.WebService;
+import org.sonar.api.server.ws.WebService.Param;
 import org.sonar.api.utils.System2;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbTester;
@@ -38,6 +39,7 @@ import org.sonar.db.component.ComponentTesting;
 import org.sonar.db.organization.OrganizationDto;
 import org.sonar.server.component.TestComponentFinder;
 import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.organization.DefaultOrganizationProvider;
 import org.sonar.server.organization.TestDefaultOrganizationProvider;
 import org.sonar.server.tester.UserSessionRule;
@@ -47,6 +49,7 @@ import org.sonar.test.JsonAssert;
 import org.sonarqube.ws.Settings;
 import org.sonarqube.ws.Settings.ListDefinitionsWsResponse;
 
+import static java.lang.String.format;
 import static java.util.Arrays.asList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.groups.Tuple.tuple;
@@ -379,6 +382,23 @@ public class ListDefinitionsActionTest {
     assertThat(result.getDefinitionsList()).extracting(Settings.Definition::getKey).containsOnly("foo", "secret.secured", "plugin.license.secured");
   }
 
+  @Test
+  public void definitions_on_branch() throws Exception {
+    ComponentDto project = db.components().insertMainBranch();
+    userSession.logIn().addProjectPermission(USER, project);
+    ComponentDto branch = db.components().insertProjectBranch(project);
+    propertyDefinitions.addComponents(asList(
+      PropertyDefinition.builder("sonar.leak.period").onQualifiers(PROJECT).build(),
+      PropertyDefinition.builder("other").onQualifiers(PROJECT).build()));
+
+    ListDefinitionsWsResponse result = ws.newRequest()
+      .setParam("component", branch.getKey())
+      .setParam("branch", branch.getBranch())
+      .executeProtobuf(Settings.ListDefinitionsWsResponse.class);
+
+    assertThat(result.getDefinitionsList()).extracting(Settings.Definition::getKey).containsExactlyInAnyOrder("sonar.leak.period");
+  }
+
   @Test
   public void fail_when_user_has_not_project_browse_permission() throws Exception {
     userSession.logIn("project-admin").addProjectPermission(CODEVIEWER, project);
@@ -389,6 +409,31 @@ public class ListDefinitionsActionTest {
     executeRequest(project.getDbKey());
   }
 
+  @Test
+  public void fail_when_component_not_found() {
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage("Component key 'unknown' not found");
+
+    ws.newRequest()
+      .setParam("component", "unknown")
+      .execute();
+  }
+
+  @Test
+  public void fail_when_branch_not_found() {
+    ComponentDto project = db.components().insertMainBranch();
+    ComponentDto branch = db.components().insertProjectBranch(project);
+    userSession.logIn().addProjectPermission(USER, project);
+
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage(format("Component '%s' on branch 'unknown' not found", branch.getKey()));
+
+    ws.newRequest()
+      .setParam("component", branch.getKey())
+      .setParam("branch", "unknown")
+      .execute();
+  }
+
   @Test
   public void test_ws_definition() {
     WebService.Action action = ws.getDef();
@@ -396,7 +441,7 @@ public class ListDefinitionsActionTest {
     assertThat(action.isInternal()).isFalse();
     assertThat(action.isPost()).isFalse();
     assertThat(action.responseExampleAsString()).isNotEmpty();
-    assertThat(action.params()).hasSize(1);
+    assertThat(action.params()).extracting(Param::key).containsExactlyInAnyOrder("component", "branch");
   }
 
   @Test
index 7f93922865b8d377d17ad7e5d9e60b8ee805daef..1b18dce0a2bf2bbbf1e11c62960fc0e9aeaa23a3 100644 (file)
@@ -54,6 +54,8 @@ import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.i18n.I18nRule;
+import org.sonar.server.organization.DefaultOrganizationProvider;
+import org.sonar.server.organization.TestDefaultOrganizationProvider;
 import org.sonar.server.platform.SettingsChangeNotifier;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.TestRequest;
@@ -92,7 +94,9 @@ public class SetActionTest {
   private FakeSettingsNotifier settingsChangeNotifier = new FakeSettingsNotifier(dbClient);
   private SettingsUpdater settingsUpdater = new SettingsUpdater(dbClient, definitions);
   private SettingValidations validations = new SettingValidations(definitions, dbClient, i18n);
-  private SetAction underTest = new SetAction(definitions, dbClient, componentFinder, userSession, settingsUpdater, settingsChangeNotifier, validations);
+  private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
+  private SetAction underTest = new SetAction(definitions, dbClient, componentFinder, userSession, settingsUpdater, settingsChangeNotifier, validations,
+    new SettingsWsSupport(defaultOrganizationProvider, userSession));
 
   private WsActionTester ws = new WsActionTester(underTest);
 
@@ -939,14 +943,14 @@ public class SetActionTest {
 
   @Test
   public void fail_when_component_not_found() {
-      expectedException.expect(NotFoundException.class);
-      expectedException.expectMessage("Component key 'unknown' not found");
-
-      ws.newRequest()
-        .setParam("key", "foo")
-        .setParam("value", "2")
-        .setParam("component", "unknown")
-        .execute();
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage("Component key 'unknown' not found");
+
+    ws.newRequest()
+      .setParam("key", "foo")
+      .setParam("value", "2")
+      .setParam("component", "unknown")
+      .execute();
   }
 
   @Test
index a5aefe42a9f0aeca409a74b2003d1d9aec5edfa0..0e2ac0ddb1908950f9402cca2c9f86c438c8c84f 100644 (file)
@@ -27,9 +27,11 @@ import javax.annotation.concurrent.Immutable;
 public class ListDefinitionsRequest {
 
   private final String component;
+  private final String branch;
 
   private ListDefinitionsRequest(Builder builder) {
     this.component = builder.component;
+    this.branch = builder.branch;
   }
 
   @CheckForNull
@@ -37,12 +39,18 @@ public class ListDefinitionsRequest {
     return component;
   }
 
+  @CheckForNull
+  public String getBranch() {
+    return branch;
+  }
+
   public static Builder builder() {
     return new Builder();
   }
 
   public static class Builder {
     private String component;
+    private String branch;
 
     private Builder() {
       // enforce factory method use
@@ -53,6 +61,11 @@ public class ListDefinitionsRequest {
       return this;
     }
 
+    public Builder setBranch(@Nullable String branch) {
+      this.branch = branch;
+      return this;
+    }
+
     public ListDefinitionsRequest build() {
       return new ListDefinitionsRequest(this);
     }
index 3348fdb48c53d096de1a512a727ea0d375e33300..2fddb192e23f59983f94d116a0443dd853ac7547 100644 (file)
@@ -46,7 +46,8 @@ public class SettingsService extends BaseService {
 
   public ListDefinitionsWsResponse listDefinitions(ListDefinitionsRequest request) {
     GetRequest getRequest = new GetRequest(path(ACTION_LIST_DEFINITIONS))
-      .setParam(PARAM_COMPONENT, request.getComponent());
+      .setParam(PARAM_COMPONENT, request.getComponent())
+      .setParam(PARAM_BRANCH, request.getBranch());
     return call(getRequest, ListDefinitionsWsResponse.parser());
   }
 
index 989fcbc8eae0d2007a479159c3eb08ddd4cffe4e..3a98984c95d3730370be2bc606020ce6172dcdeb 100644 (file)
@@ -33,17 +33,27 @@ public class ListDefinitionsRequestTest {
   ListDefinitionsRequest.Builder underTest = ListDefinitionsRequest.builder();
 
   @Test
-  public void create_request_with_no_component() {
+  public void create_request_with_nothing() {
     ListDefinitionsRequest result = underTest.build();
 
     assertThat(result.getComponent()).isNull();
+    assertThat(result.getBranch()).isNull();
   }
 
   @Test
-  public void create_request_with_component_key() {
+  public void create_request_with_component() {
     ListDefinitionsRequest result = underTest.setComponent("projectKey").build();
 
     assertThat(result.getComponent()).isEqualTo("projectKey");
+    assertThat(result.getBranch()).isNull();
+  }
+
+  @Test
+  public void create_request_with_component_and_branch() {
+    ListDefinitionsRequest result = underTest.setComponent("projectKey").setBranch("branch").build();
+
+    assertThat(result.getComponent()).isEqualTo("projectKey");
+    assertThat(result.getBranch()).isEqualTo("branch");
   }
 
 }
index 247acd0247f5808b9878cee31ef0c2fab5971986..d3215980f700ffc8bb5a64a62a75d0ee50a3fb9c 100644 (file)
@@ -49,12 +49,14 @@ public class SettingsServiceTest {
   public void list_definitions() {
     underTest.listDefinitions(ListDefinitionsRequest.builder()
       .setComponent("KEY")
+      .setBranch("BRANCH")
       .build());
     GetRequest getRequest = serviceTester.getGetRequest();
 
     assertThat(serviceTester.getGetParser()).isSameAs(ListDefinitionsWsResponse.parser());
     serviceTester.assertThat(getRequest)
       .hasParam(PARAM_COMPONENT, "KEY")
+      .hasParam(PARAM_BRANCH, "BRANCH")
       .andNoOtherParam();
   }