import static org.apache.commons.lang.StringUtils.isEmpty;
import static org.sonar.api.PropertyType.PROPERTY_SET;
import static org.sonar.api.web.UserRole.USER;
+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.writeProtobuf;
import static org.sonarqube.ws.client.setting.SettingsWsParameters.ACTION_VALUES;
+import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_BRANCH;
import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_COMPONENT;
import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_KEYS;
.setResponseExample(getClass().getResource("values-example.json"))
.setSince("6.3")
.setHandler(this);
- action.createParam(PARAM_COMPONENT)
- .setDescription("Component key")
- .setExampleValue(KEY_PROJECT_EXAMPLE_001);
action.createParam(PARAM_KEYS)
.setDescription("List of setting keys")
.setExampleValue("sonar.test.inclusions,sonar.dbcleaner.cleanDirectory");
+ action.createParam(PARAM_COMPONENT)
+ .setDescription("Component key")
+ .setExampleValue(KEY_PROJECT_EXAMPLE_001);
+ action.createParam(PARAM_BRANCH)
+ .setDescription("Branch key")
+ .setExampleValue(KEY_BRANCH_EXAMPLE_001)
+ .setInternal(true)
+ .setSince("6.6");
}
@Override
private static ValuesRequest toWsRequest(Request request) {
ValuesRequest.Builder builder = ValuesRequest.builder()
- .setComponent(request.param(PARAM_COMPONENT));
+ .setComponent(request.param(PARAM_COMPONENT))
+ .setBranch(request.param(PARAM_BRANCH));
if (request.hasParam(PARAM_KEYS)) {
builder.setKeys(request.paramAsStrings(PARAM_KEYS));
}
if (componentKey == null) {
return Optional.empty();
}
- ComponentDto component = componentFinder.getByKey(dbSession, componentKey);
+ ComponentDto component = componentFinder.getByKeyAndOptionalBranch(dbSession, componentKey, valuesRequest.getBranch());
userSession.checkComponentPermission(USER, component);
return Optional.of(component);
}
private List<Setting> loadSettings(DbSession dbSession, Optional<ComponentDto> component, Set<String> keys) {
- // List of settings must be kept in the following orders : default -> global -> component
+ // List of settings must be kept in the following orders : default -> global -> component -> branch
List<Setting> settings = new ArrayList<>();
settings.addAll(loadDefaultSettings(keys));
settings.addAll(settingsFinder.loadGlobalSettings(dbSession, keys));
+ if (component.isPresent() && component.get().getBranch() != null && component.get().getMainBranchProjectUuid() != null) {
+ ComponentDto project = dbClient.componentDao().selectOrFailByUuid(dbSession, component.get().getMainBranchProjectUuid());
+ settings.addAll(settingsFinder.loadComponentSettings(dbSession, keys, project).values());
+ }
component.ifPresent(componentDto -> settings.addAll(settingsFinder.loadComponentSettings(dbSession, keys, componentDto).values()));
return settings.stream()
.filter(settingsWsSupport.isSettingVisible(component))
assertThat(result.getSettings(0).getValue()).isEqualTo("fi±∞…");
}
+ @Test
+ public void branch_values() throws Exception {
+ ComponentDto project = db.components().insertMainBranch();
+ userSession.logIn().addProjectPermission(USER, project);
+ ComponentDto branch = db.components().insertProjectBranch(project);
+ definitions.addComponent(PropertyDefinition.builder("sonar.leak.period").onQualifiers(PROJECT).build());
+ propertyDb.insertProperties(newComponentPropertyDto(branch).setKey("sonar.leak.period").setValue("two"));
+
+ ValuesWsResponse result = ws.newRequest()
+ .setParam("keys", "sonar.leak.period")
+ .setParam("component", branch.getKey())
+ .setParam("branch", branch.getBranch())
+ .executeProtobuf(ValuesWsResponse.class);
+
+ assertThat(result.getSettingsList()).hasSize(1);
+ assertSetting(result.getSettings(0), "sonar.leak.period", "two", false);
+ }
+
+ @Test
+ public void branch_values_inherit_from_project() throws Exception {
+ ComponentDto project = db.components().insertMainBranch();
+ userSession.logIn().addProjectPermission(USER, project);
+ ComponentDto branch = db.components().insertProjectBranch(project);
+ definitions.addComponent(PropertyDefinition.builder("sonar.leak.period").onQualifiers(PROJECT).build());
+ propertyDb.insertProperties(newComponentPropertyDto(project).setKey("sonar.leak.period").setValue("two"));
+
+ ValuesWsResponse result = ws.newRequest()
+ .setParam("keys", "sonar.leak.period")
+ .setParam("component", branch.getKey())
+ .setParam("branch", branch.getBranch())
+ .executeProtobuf(ValuesWsResponse.class);
+
+ assertThat(result.getSettingsList()).hasSize(1);
+ assertSetting(result.getSettings(0), "sonar.leak.period", "two", true);
+ }
+
@Test
public void fail_when_user_has_not_project_browse_permission() throws Exception {
userSession.logIn("project-admin").addProjectPermission(CODEVIEWER, project);
executeRequestForGlobalProperties("foo", "deprecated");
}
+ @Test
+ public void fail_when_component_not_found() {
+ expectedException.expect(NotFoundException.class);
+ expectedException.expectMessage("Component key 'unknown' not found");
+
+ ws.newRequest()
+ .setParam("keys", "foo")
+ .setParam("component", "unknown")
+ .execute();
+ }
+
+ @Test
+ public void fail_when_branch_not_found() {
+ ComponentDto project = db.components().insertMainBranch();
+ ComponentDto branch = db.components().insertProjectBranch(project);
+ String settingKey = "not_allowed_on_branch";
+ userSession.logIn().addProjectPermission(USER, project);
+
+ expectedException.expect(NotFoundException.class);
+ expectedException.expectMessage(format("Component '%s' on branch 'unknown' not found", branch.getKey()));
+
+ ws.newRequest()
+ .setParam("keys", settingKey)
+ .setParam("component", branch.getKey())
+ .setParam("branch", "unknown")
+ .execute();
+ }
+
@Test
public void test_example_json_response() {
logIn();
assertThat(action.isInternal()).isFalse();
assertThat(action.isPost()).isFalse();
assertThat(action.responseExampleAsString()).isNotEmpty();
- assertThat(action.params()).hasSize(2);
+ assertThat(action.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("keys", "component", "branch");
}
private ValuesWsResponse executeRequestForComponentProperties(ComponentDto componentDto, String... keys) {
public ValuesWsResponse values(ValuesRequest request) {
GetRequest getRequest = new GetRequest(path(ACTION_VALUES))
.setParam(PARAM_KEYS, inlineMultipleParamValue(request.getKeys()))
- .setParam(PARAM_COMPONENT, request.getComponent());
+ .setParam(PARAM_COMPONENT, request.getComponent())
+ .setParam(PARAM_BRANCH, request.getBranch());
return call(getRequest, ValuesWsResponse.parser());
}
.setParam(PARAM_VALUES, request.getValues())
.setParam(PARAM_FIELD_VALUES, request.getFieldValues())
.setParam(PARAM_COMPONENT, request.getComponent())
- .setParam(PARAM_BRANCH, request.getBranch())
- );
+ .setParam(PARAM_BRANCH, request.getBranch()));
}
public void reset(ResetRequest request) {
call(new PostRequest(path(ACTION_RESET))
.setParam(PARAM_KEYS, inlineMultipleParamValue(request.getKeys()))
.setParam(PARAM_COMPONENT, request.getComponent())
- .setParam(PARAM_BRANCH, request.getBranch())
- );
+ .setParam(PARAM_BRANCH, request.getBranch()));
}
}
public class ValuesRequest {
- private final String component;
private final List<String> keys;
+ private final String component;
+ private final String branch;
private ValuesRequest(Builder builder) {
- this.component = builder.component;
this.keys = builder.keys;
+ this.component = builder.component;
+ this.branch = builder.branch;
+ }
+
+ public List<String> getKeys() {
+ return keys;
}
@CheckForNull
return component;
}
- public List<String> getKeys() {
- return keys;
+ @CheckForNull
+ public String getBranch() {
+ return branch;
}
public static Builder builder() {
}
public static class Builder {
- private String component;
private List<String> keys = new ArrayList<>();
+ private String component;
+ private String branch;
private Builder() {
// enforce factory method use
}
- public Builder setComponent(@Nullable String component) {
- this.component = component;
- return this;
- }
-
public Builder setKeys(List<String> keys) {
this.keys = requireNonNull(keys);
return this;
return setKeys(asList(keys));
}
+ public Builder setComponent(@Nullable String component) {
+ this.component = component;
+ return this;
+ }
+
+ public Builder setBranch(@Nullable String branch) {
+ this.branch = branch;
+ return this;
+ }
+
public ValuesRequest build() {
return new ValuesRequest(this);
}
underTest.values(ValuesRequest.builder()
.setKeys("sonar.debt,sonar.issue")
.setComponent("KEY")
+ .setBranch("BRANCH")
.build());
GetRequest getRequest = serviceTester.getGetRequest();
serviceTester.assertThat(getRequest)
.hasParam(PARAM_KEYS, "sonar.debt,sonar.issue")
.hasParam(PARAM_COMPONENT, "KEY")
+ .hasParam(PARAM_BRANCH, "BRANCH")
.andNoOtherParam();
}
public void create_request_with_no_component() {
ValuesRequest result = underTest.setKeys("sonar.debt").build();
- assertThat(result.getComponent()).isNull();
assertThat(result.getKeys()).containsOnly("sonar.debt");
+ assertThat(result.getComponent()).isNull();
+ assertThat(result.getBranch()).isNull();
}
@Test
public void create_request_with_no_keys() {
ValuesRequest result = underTest.build();
- assertThat(result.getComponent()).isNull();
assertThat(result.getKeys()).isEmpty();
+ assertThat(result.getComponent()).isNull();
+ assertThat(result.getBranch()).isNull();
}
@Test
public void create_request_with_component() {
ValuesRequest result = underTest.setKeys("sonar.debt").setComponent("projectKey").build();
+ assertThat(result.getKeys()).containsOnly("sonar.debt");
assertThat(result.getComponent()).isEqualTo("projectKey");
+ assertThat(result.getBranch()).isNull();
+ }
+
+ @Test
+ public void create_request_with_component_and_branch() {
+ ValuesRequest result = underTest.setKeys("sonar.debt").setComponent("projectKey").setBranch("branch").build();
+
assertThat(result.getKeys()).containsOnly("sonar.debt");
+ assertThat(result.getComponent()).isEqualTo("projectKey");
+ assertThat(result.getBranch()).isEqualTo("branch");
}
}