import com.sonar.orchestrator.Orchestrator;
import it.Category6Suite;
+import java.util.function.Predicate;
+import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
+import org.sonarqube.ws.QualityProfiles;
import org.sonarqube.ws.QualityProfiles.SearchWsResponse;
import org.sonarqube.ws.QualityProfiles.SearchWsResponse.QualityProfile;
+import org.sonarqube.ws.client.HttpException;
import org.sonarqube.ws.client.WsClient;
import org.sonarqube.ws.client.organization.CreateWsRequest;
+import org.sonarqube.ws.client.qualityprofile.ActivateRuleWsRequest;
+import org.sonarqube.ws.client.qualityprofile.CopyRequest;
+import org.sonarqube.ws.client.qualityprofile.DeleteRequest;
import org.sonarqube.ws.client.qualityprofile.SearchWsRequest;
+import org.sonarqube.ws.client.qualityprofile.SetDefaultRequest;
import static it.Category6Suite.enableOrganizationsSupport;
+import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
+import static org.apache.commons.lang.RandomStringUtils.randomAscii;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
+import static org.junit.Assert.fail;
import static util.ItUtils.newAdminWsClient;
import static util.ItUtils.newOrganizationKey;
public class QualityProfilesBuiltInTest {
- private static final String ANOTHER_ORGANIZATION = newOrganizationKey();
+ private static final String ORGANIZATION = newOrganizationKey();
+ private static final String RULE_ONE_BUG_PER_LINE = "xoo:OneBugIssuePerLine";
+
@ClassRule
public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR;
+
private static WsClient adminWsClient;
@BeforeClass
public static void setUp() {
enableOrganizationsSupport();
adminWsClient = newAdminWsClient(orchestrator);
+ adminWsClient.organizations().create(new CreateWsRequest.Builder()
+ .setKey(ORGANIZATION)
+ .setName(ORGANIZATION).build());
+ }
+
+ @AfterClass
+ public static void tearDown() {
+ adminWsClient.organizations().delete(ORGANIZATION);
+ }
+
+ @Test
+ public void built_in_profiles_provided_copied_to_new_organization() {
+ SearchWsResponse result = adminWsClient.qualityProfiles().search(new SearchWsRequest().setOrganizationKey(ORGANIZATION));
+
+ assertThat(result.getProfilesList())
+ .extracting(QualityProfile::getName, QualityProfile::getLanguage, QualityProfile::getIsBuiltIn, QualityProfile::getIsDefault)
+ .containsExactlyInAnyOrder(
+ tuple("Basic", "xoo", true, true),
+ tuple("empty", "xoo", true, false),
+ tuple("Basic", "xoo2", true, true));
}
@Test
- public void xoo_profiles_provided() {
- SearchWsResponse result = adminWsClient.qualityProfiles().search(new SearchWsRequest());
+ public void built_in_profiles_provided_for_default_organization() {
+ SearchWsResponse result = adminWsClient.qualityProfiles().search(new SearchWsRequest().setOrganizationKey("default-organization"));
assertThat(result.getProfilesList())
.extracting(QualityProfile::getOrganization, QualityProfile::getName, QualityProfile::getLanguage, QualityProfile::getIsBuiltIn, QualityProfile::getIsDefault)
}
@Test
- public void xoo_profiles_provided_copied_to_new_organization() {
- adminWsClient.organizations().create(new CreateWsRequest.Builder()
- .setKey(ANOTHER_ORGANIZATION)
- .setName(ANOTHER_ORGANIZATION).build());
- SearchWsResponse result = adminWsClient.qualityProfiles().search(new SearchWsRequest()
- .setOrganizationKey(ANOTHER_ORGANIZATION));
+ public void cannot_delete_built_in_profile_even_when_non_default() {
+ QualityProfile defaultBuiltInProfile = getProfile(p -> p.getIsBuiltIn() && p.getIsDefault() && "Basic".equals(p.getName()) && "xoo".equals(p.getLanguage()));
- assertThat(result.getProfilesList())
- .extracting(QualityProfile::getOrganization, QualityProfile::getName, QualityProfile::getLanguage, QualityProfile::getIsBuiltIn, QualityProfile::getIsDefault)
- .containsExactlyInAnyOrder(
- tuple(ANOTHER_ORGANIZATION, "Basic", "xoo", true, true),
- tuple(ANOTHER_ORGANIZATION, "empty", "xoo", true, false),
- tuple(ANOTHER_ORGANIZATION, "Basic", "xoo2", true, true));
+ QualityProfiles.CopyWsResponse copiedProfile = adminWsClient.qualityProfiles().copy(new CopyRequest(defaultBuiltInProfile.getKey(), randomAscii(20)));
+ adminWsClient.qualityProfiles().setDefault(new SetDefaultRequest(copiedProfile.getKey()));
+
+ try {
+ adminWsClient.qualityProfiles().delete(new DeleteRequest(defaultBuiltInProfile.getKey()));
+ fail();
+ } catch (HttpException e) {
+ assertThat(e.code()).isEqualTo(400);
+ assertThat(e.content()).contains("Operation forbidden for built-in Quality Profile 'Basic' with language 'xoo'");
+ } finally {
+ adminWsClient.qualityProfiles().setDefault(new SetDefaultRequest(defaultBuiltInProfile.getKey()));
+ adminWsClient.qualityProfiles().delete(new DeleteRequest(copiedProfile.getKey()));
+ }
+ }
+
+ @Test
+ public void fail_to_modify_built_in_quality_profile() {
+ QualityProfile profile = getProfile(p -> p.getIsBuiltIn() && "Basic".equals(p.getName()) && "xoo".equals(p.getLanguage()));
+ assertThat(profile.getIsBuiltIn()).isTrue();
+
+ try {
+ adminWsClient.qualityProfiles().activateRule(ActivateRuleWsRequest.builder()
+ .setOrganization(ORGANIZATION)
+ .setProfileKey(profile.getKey())
+ .setRuleKey(RULE_ONE_BUG_PER_LINE)
+ .build());
+ fail();
+ } catch (HttpException e) {
+ assertThat(e.code()).isEqualTo(HTTP_BAD_REQUEST);
+ assertThat(e.content()).contains("Operation forbidden for built-in Quality Profile 'Basic' with language 'xoo'");
+ }
+ }
+
+ private QualityProfile getProfile(Predicate<QualityProfile> filter) {
+ return adminWsClient.qualityProfiles().search(new SearchWsRequest()
+ .setOrganizationKey(ORGANIZATION)).getProfilesList()
+ .stream()
+ .filter(filter)
+ .findAny().orElseThrow(IllegalStateException::new);
}
}
import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.server.qualityprofile.QProfileCopier;
import org.sonar.server.user.UserSession;
+import org.sonarqube.ws.QualityProfiles;
+
+import static org.sonar.core.util.Protobuf.setNullable;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_COPY;
public class CopyAction implements QProfileWsAction {
- private static final String PARAM_PROFILE_NAME = "toName";
- private static final String PARAM_PROFILE_KEY = "fromKey";
+ private static final String PARAM_TO_NAME = "toName";
+ private static final String PARAM_FROM_KEY = "fromKey";
private final DbClient dbClient;
private final QProfileCopier profileCopier;
@Override
public void define(WebService.NewController controller) {
- NewAction action = controller.createAction("copy")
- .setSince("5.2")
- .setDescription("Copy a quality profile. Require Administer Quality Profiles permission.")
- .setPost(true)
- .setHandler(this);
-
- action.createParam(PARAM_PROFILE_NAME)
- .setDescription("The name for the new quality profile.")
- .setExampleValue("My Sonar way")
- .setRequired(true);
-
- action.createParam(PARAM_PROFILE_KEY)
- .setDescription("The key of a quality profile.")
- .setExampleValue(Uuids.UUID_EXAMPLE_01)
- .setRequired(true);
+ NewAction action = controller.createAction(ACTION_COPY)
+ .setSince("5.2")
+ .setDescription("Copy a quality profile. Require Administer Quality Profiles permission.")
+ .setPost(true)
+ .setHandler(this);
+
+ action.createParam(PARAM_TO_NAME)
+ .setDescription("The name for the new quality profile.")
+ .setExampleValue("My Sonar way")
+ .setRequired(true);
+
+ action.createParam(PARAM_FROM_KEY)
+ .setDescription("The key of a quality profile.")
+ .setExampleValue(Uuids.UUID_EXAMPLE_01)
+ .setRequired(true);
}
@Override
public void handle(Request request, Response response) throws Exception {
userSession.checkLoggedIn();
- String newName = request.mandatoryParam(PARAM_PROFILE_NAME);
- String profileKey = request.mandatoryParam(PARAM_PROFILE_KEY);
+ String newName = request.mandatoryParam(PARAM_TO_NAME);
+ String profileKey = request.mandatoryParam(PARAM_FROM_KEY);
try (DbSession dbSession = dbClient.openSession(false)) {
QProfileDto sourceProfile = wsSupport.getProfile(dbSession, QProfileReference.fromKey(profileKey));
String languageKey = copiedProfile.getLanguage();
Language language = languages.get(copiedProfile.getLanguage());
String parentKey = copiedProfile.getParentKee();
- response.newJsonWriter()
- .beginObject()
- .prop("key", copiedProfile.getKee())
- .prop("name", copiedProfile.getName())
- .prop("language", languageKey)
- .prop("languageName", language == null ? null : language.getName())
- .prop("isDefault", isDefault)
- .prop("isInherited", parentKey != null)
- .prop("parentKey", parentKey)
- .endObject().close();
+
+ QualityProfiles.CopyWsResponse.Builder wsResponse = QualityProfiles.CopyWsResponse.newBuilder();
+
+ wsResponse.setKey(copiedProfile.getKee());
+ wsResponse.setName(copiedProfile.getName());
+ wsResponse.setLanguage(languageKey);
+ setNullable(language, l -> wsResponse.setLanguageName(l.getName()));
+ wsResponse.setIsDefault(isDefault);
+ wsResponse.setIsInherited(parentKey != null);
+ setNullable(parentKey, wsResponse::setParentKey);
+
+ writeProtobuf(wsResponse.build(), request, response);
}
}
}
import static java.lang.String.format;
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_SET_DEFAULT;
public class SetDefaultAction implements QProfileWsAction {
@Override
public void define(WebService.NewController controller) {
- NewAction setDefault = controller.createAction("set_default")
+ NewAction setDefault = controller.createAction(ACTION_SET_DEFAULT)
.setSince("5.2")
.setDescription("Select the default profile for a given language. Require Administer Quality Profiles permission.")
.setPost(true)
.setHandler(this);
- QProfileWsSupport.createOrganizationParam(setDefault)
- .setSince("6.4");
-
+ QProfileWsSupport.createOrganizationParam(setDefault).setSince("6.4");
QProfileReference.defineParams(setDefault, languages);
}
private Builder() {
}
- public void setOrganization(@Nullable String organization) {
+ public Builder setOrganization(@Nullable String organization) {
this.organization = Optional.ofNullable(organization);
+ return this;
}
public Builder setParams(@Nullable String params) {
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.qualityprofile;
+
+import static java.util.Objects.requireNonNull;
+
+public class CopyRequest {
+ private final String fromKey;
+ private final String toName;
+
+ public CopyRequest(String fromKey, String toName) {
+ this.fromKey = requireNonNull(fromKey);
+ this.toName = requireNonNull(toName);
+ }
+
+ public String getFromKey() {
+ return fromKey;
+ }
+
+ public String getToName() {
+ return toName;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.qualityprofile;
+
+public class DeleteRequest {
+ private final String profileKey;
+
+ public DeleteRequest(String profileKey) {
+ this.profileKey = profileKey;
+ }
+
+ public String getProfileKey() {
+ return profileKey;
+ }
+}
public static final String ACTION_ADD_PROJECT = "add_project";
public static final String ACTION_REMOVE_PROJECT = "remove_project";
public static final String ACTION_CREATE = "create";
+ public static final String ACTION_COPY = "copy";
+ public static final String ACTION_SET_DEFAULT = "set_default";
+ public static final String ACTION_DELETE = "delete";
public static final String PARAM_ORGANIZATION = "organization";
public static final String PARAM_DEFAULTS = "defaults";
public static final String PARAM_PROFILE_KEY = "profileKey";
public static final String PARAM_PROJECT_KEY = "projectKey";
public static final String PARAM_PROJECT_UUID = "projectUuid";
+ public static final String PARAM_FROM_KEY = "fromKey";
+ public static final String PARAM_TO_NAME = "toName";
private QualityProfileWsParameters() {
// Only static stuff
package org.sonarqube.ws.client.qualityprofile;
import org.sonarqube.ws.MediaTypes;
+import org.sonarqube.ws.QualityProfiles.CopyWsResponse;
import org.sonarqube.ws.QualityProfiles.CreateWsResponse;
import org.sonarqube.ws.QualityProfiles.SearchWsResponse;
import org.sonarqube.ws.client.BaseService;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_ACTIVATE_RULE;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_ADD_PROJECT;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_COPY;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_CREATE;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_DELETE;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_REMOVE_PROJECT;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_RESTORE;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_SEARCH;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_SET_DEFAULT;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ActivateActionParameters;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.CONTROLLER_QUALITY_PROFILES;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_DEFAULTS;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_FROM_KEY;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_ORGANIZATION;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_KEY;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_NAME;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROJECT_KEY;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROJECT_UUID;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_TO_NAME;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.RestoreActionParameters.PARAM_BACKUP;
public class QualityProfilesService extends BaseService {
.setParam(PARAM_PROFILE_NAME, request.getProfileName());
return call(postRequest, CreateWsResponse.parser());
}
+
+ public CopyWsResponse copy(CopyRequest request) {
+ PostRequest postRequest = new PostRequest(path(ACTION_COPY))
+ .setParam(PARAM_FROM_KEY, request.getFromKey())
+ .setParam(PARAM_TO_NAME, request.getToName());
+
+ return call(postRequest, CopyWsResponse.parser());
+ }
+
+ public void setDefault(SetDefaultRequest request) {
+ PostRequest postRequest = new PostRequest(path(ACTION_SET_DEFAULT))
+ .setParam(PARAM_PROFILE_KEY, request.getProfileKey());
+
+ call(postRequest);
+ }
+
+ public void delete(DeleteRequest request) {
+ PostRequest postRequest = new PostRequest(path(ACTION_DELETE))
+ .setParam(PARAM_PROFILE_KEY, request.getProfileKey());
+
+ call(postRequest);
+ }
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.qualityprofile;
+
+public class SetDefaultRequest {
+ private final String profileKey;
+
+ public SetDefaultRequest(String profileKey) {
+ this.profileKey = profileKey;
+ }
+
+ public String getProfileKey() {
+ return profileKey;
+ }
+}
optional bool isBuiltIn = 6;
}
}
+
+// WS api/qualityprofiles/copy
+message CopyWsResponse {
+ optional string key = 1;
+ optional string name = 2;
+ optional string language = 3;
+ optional string languageName = 4;
+ optional bool isDefault = 5;
+ optional bool isInherited = 6;
+ optional string parentKey = 7;
+}
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_DEFAULTS;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_FROM_KEY;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_KEY;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_NAME;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROJECT_KEY;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_TO_NAME;
public class QualityProfilesServiceTest {
assertThat(serviceTester.getGetParser()).isSameAs(QualityProfiles.SearchWsResponse.parser());
serviceTester.assertThat(getRequest)
+ .hasPath("search")
.hasParam(PARAM_DEFAULTS, true)
.hasParam(PARAM_PROJECT_KEY, "project")
.hasParam(PARAM_LANGUAGE, "language")
.build());
serviceTester.assertThat(serviceTester.getPostRequest())
+ .hasPath("add_project")
.hasParam(PARAM_LANGUAGE, "xoo")
.hasParam(PARAM_PROFILE_NAME, "Sonar Way")
.hasParam(PARAM_PROJECT_KEY, "sample")
.build());
serviceTester.assertThat(serviceTester.getPostRequest())
+ .hasPath("remove_project")
.hasParam(PARAM_LANGUAGE, "xoo")
.hasParam(PARAM_PROFILE_NAME, "Sonar Way")
.hasParam(PARAM_PROJECT_KEY, "sample")
}
@Test
- public void create_project() throws Exception {
+ public void create() throws Exception {
underTest.create(CreateRequest.builder()
.setLanguage("xoo")
.setProfileName("Sonar Way")
.build());
serviceTester.assertThat(serviceTester.getPostRequest())
+ .hasPath("create")
.hasParam(PARAM_LANGUAGE, "xoo")
.hasParam(PARAM_PROFILE_NAME, "Sonar Way")
.andNoOtherParam();
}
+
+ @Test
+ public void copy() throws Exception {
+ underTest.copy(new CopyRequest("fromKey", "My Sonar Way"));
+
+ serviceTester.assertThat(serviceTester.getPostRequest())
+ .hasPath("copy")
+ .hasParam(PARAM_FROM_KEY, "fromKey")
+ .hasParam(PARAM_TO_NAME, "My Sonar Way")
+ .andNoOtherParam();
+ }
+
+ @Test
+ public void set_default() {
+ underTest.setDefault(new SetDefaultRequest("sample"));
+
+ serviceTester.assertThat(serviceTester.getPostRequest())
+ .hasPath("set_default")
+ .hasParam(PARAM_PROFILE_KEY, "sample")
+ .andNoOtherParam();
+ }
+
+ @Test
+ public void delete() {
+ underTest.delete(new DeleteRequest("sample"));
+
+ serviceTester.assertThat(serviceTester.getPostRequest())
+ .hasPath("delete")
+ .hasParam(PARAM_PROFILE_KEY, "sample")
+ .andNoOtherParam();
+ }
}