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 {
action.createParam(PARAM_COMPONENT)
.setDescription("Component key")
.setExampleValue(KEY_PROJECT_EXAMPLE_001);
+ settingsWsSupport.addBranchParam(action);
}
@Override
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();
private static ListDefinitionsRequest toWsRequest(Request request) {
return ListDefinitionsRequest.builder()
.setComponent(request.param(PARAM_COMPONENT))
+ .setBranch(request.param(PARAM_BRANCH))
.build();
}
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);
}
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;
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;
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;
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;
this.settingsUpdater = settingsUpdater;
this.settingsChangeNotifier = settingsChangeNotifier;
this.validations = validations;
+ this.settingsWsSupport = settingsWsSupport;
}
@Override
.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
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) {
*/
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) {
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;
.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");
+ }
}
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;
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;
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;
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);
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();
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
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;
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);
@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
public class ListDefinitionsRequest {
private final String component;
+ private final String branch;
private ListDefinitionsRequest(Builder builder) {
this.component = builder.component;
+ this.branch = builder.branch;
}
@CheckForNull
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
return this;
}
+ public Builder setBranch(@Nullable String branch) {
+ this.branch = branch;
+ return this;
+ }
+
public ListDefinitionsRequest build() {
return new ListDefinitionsRequest(this);
}
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());
}
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");
}
}
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();
}