aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/CreateAction.java101
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CreateActionMediumTest.java113
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CreateActionTest.java126
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java4
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/CreateActionMediumTest/create-nominal.json9
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/CreateActionTest/test_json.json (renamed from server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/CreateActionTest/create-no-importer.json)0
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/CreateRequest.java72
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfileWsParameters.java1
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesService.java9
-rw-r--r--sonar-ws/src/main/protobuf/ws-qualityprofiles.proto24
-rw-r--r--sonar-ws/src/test/java/org/sonarqube/ws/client/qualityprofile/CreateRequestTest.java59
-rw-r--r--sonar-ws/src/test/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesServiceTest.java13
12 files changed, 328 insertions, 203 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/CreateAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/CreateAction.java
index c0088d45fe4..0e88a06abd1 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/CreateAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/CreateAction.java
@@ -20,15 +20,12 @@
package org.sonar.server.qualityprofile.ws;
import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
import org.sonar.api.profiles.ProfileImporter;
import org.sonar.api.resources.Languages;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.NewAction;
-import org.sonar.api.utils.text.JsonWriter;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
@@ -37,13 +34,20 @@ import org.sonar.server.qualityprofile.QProfileExporters;
import org.sonar.server.qualityprofile.QProfileFactory;
import org.sonar.server.qualityprofile.QProfileName;
import org.sonar.server.qualityprofile.QProfileResult;
+import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.user.UserSession;
import org.sonar.server.util.LanguageParamUtils;
+import org.sonarqube.ws.QualityProfiles.CreateWsResponse;
+import org.sonarqube.ws.client.qualityprofile.CreateRequest;
+
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_CREATE;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_NAME;
public class CreateAction implements QProfileWsAction {
- private static final String PARAM_PROFILE_NAME = "name";
- private static final String PARAM_LANGUAGE = "language";
+ private static final String DEPRECATED_PARAM_PROFILE_NAME = "name";
private static final String PARAM_BACKUP_FORMAT = "backup_%s";
private final DbClient dbClient;
@@ -58,7 +62,7 @@ public class CreateAction implements QProfileWsAction {
private final UserSession userSession;
public CreateAction(DbClient dbClient, QProfileFactory profileFactory, QProfileExporters exporters,
- Languages languages, ProfileImporter[] importers, UserSession userSession) {
+ Languages languages, ProfileImporter[] importers, UserSession userSession) {
this.dbClient = dbClient;
this.profileFactory = profileFactory;
this.exporters = exporters;
@@ -73,16 +77,18 @@ public class CreateAction implements QProfileWsAction {
@Override
public void define(WebService.NewController controller) {
- NewAction create = controller.createAction("create")
+ NewAction create = controller.createAction(ACTION_CREATE)
.setSince("5.2")
- .setDescription("Create a quality profile. Require Administer Quality Profiles permission.")
+ .setDescription("Create a quality profile.<br/>" +
+ "Require Administer Quality Profiles permission.")
.setPost(true)
.setResponseExample(getClass().getResource("example-create.json"))
.setHandler(this);
create.createParam(PARAM_PROFILE_NAME)
- .setDescription("The name for the new quality profile.")
+ .setDescription("The name for the new quality profile. Since 6.1, this parameter has been renamed from '%s' to '%s'", DEPRECATED_PARAM_PROFILE_NAME, PARAM_PROFILE_NAME)
.setExampleValue("My Sonar way")
+ .setDeprecatedKey(DEPRECATED_PARAM_PROFILE_NAME)
.setRequired(true);
create.createParam(PARAM_LANGUAGE)
@@ -100,60 +106,53 @@ public class CreateAction implements QProfileWsAction {
@Override
public void handle(Request request, Response response) throws Exception {
userSession.checkLoggedIn().checkPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN);
-
- String name = request.mandatoryParam(PARAM_PROFILE_NAME);
- String language = request.mandatoryParam(PARAM_LANGUAGE);
-
+ CreateRequest createRequest = toRequest(request);
DbSession dbSession = dbClient.openSession(false);
-
try {
- QProfileResult result = new QProfileResult();
- QualityProfileDto profile = profileFactory.create(dbSession, QProfileName.createFor(language, name));
- result.setProfile(profile);
- for (ProfileImporter importer : importers) {
- InputStream contentToImport = request.paramAsInputStream(getBackupParamName(importer.getKey()));
- if (contentToImport != null) {
- result.add(exporters.importXml(profile, importer.getKey(), contentToImport, dbSession));
- }
- }
- dbSession.commit();
-
- response.stream().setMediaType(request.getMediaType());
- JsonWriter jsonWriter = JsonWriter.of(new OutputStreamWriter(response.stream().output(), StandardCharsets.UTF_8));
- writeResult(jsonWriter, result);
+ writeProtobuf(doHandle(dbSession, createRequest, request), request, response);
} finally {
dbSession.close();
}
}
- private void writeResult(JsonWriter json, QProfileResult result) {
- String language = result.profile().getLanguage();
- json.beginObject().name("profile").beginObject()
- .prop("key", result.profile().getKey())
- .prop("name", result.profile().getName())
- .prop("language", language)
- .prop("languageName", languages.get(result.profile().getLanguage()).getName())
- .prop("isDefault", false)
- .prop("isInherited", false)
- .endObject();
-
- if (!result.infos().isEmpty()) {
- json.name("infos").beginArray();
- for (String info : result.infos()) {
- json.value(info);
+ private CreateWsResponse doHandle(DbSession dbSession, CreateRequest createRequest, Request request) {
+ QProfileResult result = new QProfileResult();
+ QualityProfileDto profile = profileFactory.create(dbSession, QProfileName.createFor(createRequest.getLanguage(), createRequest.getProfileName()));
+ result.setProfile(profile);
+ for (ProfileImporter importer : importers) {
+ String importerKey = importer.getKey();
+ InputStream contentToImport = request.paramAsInputStream(getBackupParamName(importerKey));
+ if (contentToImport != null) {
+ result.add(exporters.importXml(profile, importerKey, contentToImport, dbSession));
}
- json.endArray();
}
+ dbSession.commit();
+ return buildResponse(result);
+ }
+ private static CreateRequest toRequest(Request request) {
+ CreateRequest.Builder builder = CreateRequest.builder()
+ .setLanguage(request.mandatoryParam(PARAM_LANGUAGE))
+ .setProfileName(request.mandatoryParam(PARAM_PROFILE_NAME));
+ return builder.build();
+ }
+
+ private CreateWsResponse buildResponse(QProfileResult result) {
+ String language = result.profile().getLanguage();
+ CreateWsResponse.QualityProfile.Builder builder = CreateWsResponse.QualityProfile.newBuilder()
+ .setKey(result.profile().getKey())
+ .setName(result.profile().getName())
+ .setLanguage(language)
+ .setLanguageName(languages.get(result.profile().getLanguage()).getName())
+ .setIsDefault(false)
+ .setIsInherited(false);
+ if (!result.infos().isEmpty()) {
+ builder.getInfosBuilder().addAllInfos(result.infos());
+ }
if (!result.warnings().isEmpty()) {
- json.name("warnings").beginArray();
- for (String warning : result.warnings()) {
- json.value(warning);
- }
- json.endArray();
+ builder.getWarningsBuilder().addAllWarnings(result.warnings());
}
-
- json.endObject().close();
+ return CreateWsResponse.newBuilder().setProfile(builder.build()).build();
}
private static String getBackupParamName(String importerKey) {
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CreateActionMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CreateActionMediumTest.java
deleted file mode 100644
index 9141b17ede0..00000000000
--- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CreateActionMediumTest.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.sonar.server.qualityprofile.ws;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.server.exceptions.BadRequestException;
-import org.sonar.server.qualityprofile.QProfileExporters;
-import org.sonar.server.qualityprofile.QProfileExportersTest.StandardExporter;
-import org.sonar.server.qualityprofile.QProfileExportersTest.XooExporter;
-import org.sonar.server.qualityprofile.QProfileExportersTest.XooProfileDefinition;
-import org.sonar.server.qualityprofile.QProfileExportersTest.XooProfileImporter;
-import org.sonar.server.qualityprofile.QProfileExportersTest.XooProfileImporterWithError;
-import org.sonar.server.qualityprofile.QProfileExportersTest.XooProfileImporterWithMessages;
-import org.sonar.server.qualityprofile.QProfileExportersTest.XooRulesDefinition;
-import org.sonar.server.qualityprofile.QProfileLoader;
-import org.sonar.server.tester.ServerTester;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.ws.WsTester;
-
-public class CreateActionMediumTest {
-
- // TODO Replace with simpler test with DbTester / EsTester after removal of DaoV2
- @ClassRule
- public static ServerTester tester = new ServerTester()
- .withEsIndexes()
- .withStartupTasks()
- .addXoo()
- .addComponents(
- XooRulesDefinition.class, XooProfileDefinition.class,
- XooExporter.class, StandardExporter.class,
- XooProfileImporter.class, XooProfileImporterWithMessages.class, XooProfileImporterWithError.class);
- @Rule
- public UserSessionRule userSessionRule = UserSessionRule.forServerTester(tester);
-
- DbClient db;
- DbSession dbSession;
- QProfileExporters exporters;
- QProfileLoader loader;
- WsTester wsTester;
-
- @Before
- public void before() {
- db = tester.get(DbClient.class);
- dbSession = db.openSession(false);
- exporters = tester.get(QProfileExporters.class);
- loader = tester.get(QProfileLoader.class);
- wsTester = new WsTester(tester.get(QProfilesWs.class));
- }
-
- @After
- public void after() {
- dbSession.close();
- }
-
- @Test
- public void create_nominal() throws Exception {
- userSessionRule.login("obiwan").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
-
- wsTester.newPostRequest("api/qualityprofiles", "create")
- .setParam("backup_XooProfileImporter", "a value for xoo importer")
- .setParam("language", "xoo")
- .setParam("name", "My New Profile")
- .execute().assertJson(this.getClass(), "create-nominal.json");
- }
-
- @Test
- public void create_with_messages() throws Exception {
- userSessionRule.login("obiwan").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
-
- wsTester.newPostRequest("api/qualityprofiles", "create")
- .setParam("backup_XooProfileImporter", "a value for xoo importer")
- .setParam("backup_XooProfileImporterWithMessages", "this will generate some messages")
- .setParam("language", "xoo")
- .setParam("name", "My Other Profile")
- .execute().assertJson(this.getClass(), "create-with-messages.json");
- }
-
- @Test(expected = BadRequestException.class)
- public void fail_on_error_from_importer() throws Exception {
- userSessionRule.login("obiwan").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
-
- wsTester.newPostRequest("api/qualityprofiles", "create")
- .setParam("backup_XooProfileImporter", "a value for xoo importer")
- .setParam("backup_XooProfileImporterWithError", "this will fail")
- .setParam("language", "xoo")
- .setParam("name", "Error In Importer")
- .execute();
- }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CreateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CreateActionTest.java
index 99827de0149..035496e1645 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CreateActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/CreateActionTest.java
@@ -20,11 +20,13 @@
package org.sonar.server.qualityprofile.ws;
import com.google.common.collect.ImmutableMap;
+import java.io.IOException;
import java.io.Reader;
import java.util.Collections;
import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.sonar.api.config.MapSettings;
import org.sonar.api.profiles.ProfileImporter;
import org.sonar.api.profiles.RulesProfile;
@@ -38,6 +40,7 @@ import org.sonar.db.qualityprofile.QualityProfileDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleTesting;
import org.sonar.server.es.EsTester;
+import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.qualityprofile.QProfileExporters;
import org.sonar.server.qualityprofile.QProfileFactory;
import org.sonar.server.qualityprofile.QProfileLoader;
@@ -59,6 +62,9 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.sonar.core.permission.GlobalPermissions.QUALITY_PROFILE_ADMIN;
import static org.sonar.server.language.LanguageTesting.newLanguages;
+import static org.sonarqube.ws.QualityProfiles.CreateWsResponse;
+import static org.sonarqube.ws.QualityProfiles.CreateWsResponse.QualityProfile;
+import static org.sonarqube.ws.QualityProfiles.CreateWsResponse.parseFrom;
public class CreateActionTest {
@@ -67,6 +73,9 @@ public class CreateActionTest {
static final RuleDto RULE = RuleTesting.newXooX1().setSeverity("MINOR").setLanguage(XOO_LANGUAGE);
@Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Rule
public DbTester dbTester = DbTester.create(System2.INSTANCE);
@Rule
@@ -98,16 +107,58 @@ public class CreateActionTest {
public void create_profile() {
setUserAsQualityProfileAdmin();
- executeRequest("New Profile", XOO_LANGUAGE);
+ CreateWsResponse response = executeRequest("New Profile", XOO_LANGUAGE);
- QualityProfileDto profile = dbClient.qualityProfileDao().selectByNameAndLanguage("New Profile", XOO_LANGUAGE, dbSession);
- assertThat(profile.getKey()).isNotNull();
- assertThat(profile.getLanguage()).isEqualTo(XOO_LANGUAGE);
+ QualityProfileDto dto = dbClient.qualityProfileDao().selectByNameAndLanguage("New Profile", XOO_LANGUAGE, dbSession);
+ assertThat(dto.getKey()).isNotNull();
+ assertThat(dto.getLanguage()).isEqualTo(XOO_LANGUAGE);
+ assertThat(dto.getName()).isEqualTo("New Profile");
+
+ QualityProfile profile = response.getProfile();
+ assertThat(profile.getKey()).isEqualTo(dto.getKey());
assertThat(profile.getName()).isEqualTo("New Profile");
+ assertThat(profile.getLanguage()).isEqualTo(XOO_LANGUAGE);
+ assertThat(profile.getIsInherited()).isFalse();
+ assertThat(profile.getIsDefault()).isFalse();
+ assertThat(profile.hasInfos()).isFalse();
+ assertThat(profile.hasWarnings()).isFalse();
+ }
+
+ @Test
+ public void create_profile_from_backup_xml() {
+ setUserAsQualityProfileAdmin();
+ insertRule(RULE);
+
+ executeRequest("New Profile", XOO_LANGUAGE, ImmutableMap.of("xoo_lint", "<xml/>"));
+
+ QualityProfileDto dto = dbClient.qualityProfileDao().selectByNameAndLanguage("New Profile", XOO_LANGUAGE, dbSession);
+ assertThat(dto.getKey()).isNotNull();
+ assertThat(dbClient.activeRuleDao().selectByProfileKey(dbSession, dto.getKey())).hasSize(1);
+ // FIXME
+ // assertThat(ruleIndex.searchAll(new RuleQuery().setQProfileKey(profile.getKey()).setActivation(true))).hasSize(1);
+ }
+
+ @Test
+ public void create_profile_with_messages() {
+ setUserAsQualityProfileAdmin();
+
+ CreateWsResponse response = executeRequest("Profile with messages", XOO_LANGUAGE, ImmutableMap.of("with_messages", "<xml/>"));
+
+ QualityProfile profile = response.getProfile();
+ assertThat(profile.getInfos().getInfosList()).containsOnly("an info");
+ assertThat(profile.getWarnings().getWarningsList()).containsOnly("a warning");
}
@Test
- public void return_created_profile_in_json() throws Exception {
+ public void fail_if_import_generate_error() {
+ setUserAsQualityProfileAdmin();
+
+ expectedException.expect(BadRequestException.class);
+ executeRequest("Profile with errors", XOO_LANGUAGE, ImmutableMap.of("with_errors", "<xml/>"));
+ }
+
+ @Test
+ public void test_json() throws Exception {
setUserAsQualityProfileAdmin();
TestResponse response = wsTester.newRequest()
@@ -117,35 +168,21 @@ public class CreateActionTest {
.setParam("name", "Yeehaw!")
.execute();
- JsonAssert.assertJson(response.getInput()).isSimilarTo(getClass().getResource("CreateActionTest/create-no-importer.json"));
+ JsonAssert.assertJson(response.getInput()).isSimilarTo(getClass().getResource("CreateActionTest/test_json.json"));
assertThat(response.getMediaType()).isEqualTo(MediaTypes.JSON);
}
- @Test
- public void create_profile_from_xml() {
- setUserAsQualityProfileAdmin();
- insertRule(RULE);
-
- executeRequest("New Profile", XOO_LANGUAGE, ImmutableMap.of("xoo_lint", "<xml/>"));
-
- QualityProfileDto profile = dbClient.qualityProfileDao().selectByNameAndLanguage("New Profile", XOO_LANGUAGE, dbSession);
- assertThat(profile.getKey()).isNotNull();
- assertThat(dbClient.activeRuleDao().selectByProfileKey(dbSession, profile.getKey())).hasSize(1);
- // FIXME
- // assertThat(ruleIndex.searchAll(new RuleQuery().setQProfileKey(profile.getKey()).setActivation(true))).hasSize(1);
- }
-
private void insertRule(RuleDto ruleDto) {
dbClient.ruleDao().insert(dbSession, ruleDto);
dbSession.commit();
ruleIndexer.index();
}
- private void executeRequest(String name, String language) {
- executeRequest(name, language, Collections.emptyMap());
+ private CreateWsResponse executeRequest(String name, String language) {
+ return executeRequest(name, language, Collections.emptyMap());
}
- private void executeRequest(String name, String language, Map<String, String> xmls) {
+ private CreateWsResponse executeRequest(String name, String language, Map<String, String> xmls) {
TestRequest request = wsTester.newRequest()
.setMediaType(MediaTypes.PROTOBUF)
.setParam("name", name)
@@ -153,7 +190,11 @@ public class CreateActionTest {
for (Map.Entry<String, String> entry : xmls.entrySet()) {
request.setParam("backup_" + entry.getKey(), entry.getValue());
}
- request.execute();
+ try {
+ return parseFrom(request.execute().getInputStream());
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
}
private void setUserAsQualityProfileAdmin() {
@@ -162,9 +203,9 @@ public class CreateActionTest {
private ProfileImporter[] createImporters() {
class DefaultProfileImporter extends ProfileImporter {
- private DefaultProfileImporter(String key, String name, String... languages) {
- super(key, name);
- setSupportedLanguages(languages);
+ private DefaultProfileImporter() {
+ super("xoo_lint", "Xoo Lint");
+ setSupportedLanguages(XOO_LANGUAGE);
}
@Override
@@ -173,10 +214,39 @@ public class CreateActionTest {
rulesProfile.activateRule(org.sonar.api.rules.Rule.create(RULE.getRepositoryKey(), RULE.getRuleKey()), RulePriority.BLOCKER);
return rulesProfile;
}
+ }
+ class ProfileImporterGeneratingMessages extends ProfileImporter {
+ private ProfileImporterGeneratingMessages() {
+ super("with_messages", "With messages");
+ setSupportedLanguages(XOO_LANGUAGE);
+ }
+
+ @Override
+ public RulesProfile importProfile(Reader reader, ValidationMessages messages) {
+ RulesProfile rulesProfile = RulesProfile.create();
+ messages.addWarningText("a warning");
+ messages.addInfoText("an info");
+ return rulesProfile;
+ }
}
+
+ class ProfileImporterGeneratingErrors extends ProfileImporter {
+ private ProfileImporterGeneratingErrors() {
+ super("with_errors", "With errors");
+ setSupportedLanguages(XOO_LANGUAGE);
+ }
+
+ @Override
+ public RulesProfile importProfile(Reader reader, ValidationMessages messages) {
+ RulesProfile rulesProfile = RulesProfile.create();
+ messages.addErrorText("error!");
+ return rulesProfile;
+ }
+ }
+
return new ProfileImporter[] {
- new DefaultProfileImporter("xoo_lint", "Xoo Lint", XOO_LANGUAGE)
+ new DefaultProfileImporter(), new ProfileImporterGeneratingMessages(), new ProfileImporterGeneratingErrors()
};
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java
index 4acd2d1ad60..44571cc9cde 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java
@@ -213,8 +213,8 @@ public class QProfilesWsTest {
assertThat(create).isNotNull();
assertThat(create.isPost()).isTrue();
assertThat(create.params()).hasSize(4);
- assertThat(create.param("name")).isNotNull();
- assertThat(create.param("name").isRequired()).isTrue();
+ assertThat(create.param("profileName")).isNotNull();
+ assertThat(create.param("profileName").isRequired()).isTrue();
assertThat(create.param("language").possibleValues()).containsOnly(xoo1Key, xoo2Key);
assertThat(create.param("language").isRequired()).isTrue();
assertThat(create.param("backup_" + xoo1Key)).isNotNull();
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/CreateActionMediumTest/create-nominal.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/CreateActionMediumTest/create-nominal.json
deleted file mode 100644
index a00e1eb1acc..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/CreateActionMediumTest/create-nominal.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "profile": {
- "name": "My New Profile",
- "language": "xoo",
- "languageName": "Xoo",
- "isDefault": false,
- "isInherited": false
- }
-} \ No newline at end of file
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/CreateActionTest/create-no-importer.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/CreateActionTest/test_json.json
index 367abddd246..367abddd246 100644
--- a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/CreateActionTest/create-no-importer.json
+++ b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/CreateActionTest/test_json.json
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/CreateRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/CreateRequest.java
new file mode 100644
index 00000000000..9b7bfd9b12a
--- /dev/null
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/CreateRequest.java
@@ -0,0 +1,72 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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 javax.annotation.Nullable;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public class CreateRequest {
+
+ private final String profileName;
+ private final String language;
+
+ private CreateRequest(Builder builder) {
+ this.profileName = builder.profileName;
+ this.language = builder.language;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public String getProfileName() {
+ return profileName;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private String language;
+ private String profileName;
+
+ private Builder() {
+ // enforce factory method use
+ }
+
+ public Builder setLanguage(@Nullable String language) {
+ this.language = language;
+ return this;
+ }
+
+ public Builder setProfileName(@Nullable String profileName) {
+ this.profileName = profileName;
+ return this;
+ }
+
+ public CreateRequest build() {
+ checkArgument(language != null && !language.isEmpty(), "Language is mandatory and must not be empty.");
+ checkArgument(profileName != null && !profileName.isEmpty(), "Profile name is mandatory and must not be empty.");
+ return new CreateRequest(this);
+ }
+ }
+}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfileWsParameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfileWsParameters.java
index 8d75d163c4d..3b73744eab3 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfileWsParameters.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfileWsParameters.java
@@ -26,6 +26,7 @@ public class QualityProfileWsParameters {
public static final String ACTION_SEARCH = "search";
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 PARAM_DEFAULTS = "defaults";
public static final String PARAM_LANGUAGE = "language";
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesService.java
index f9256557011..94475a1ea46 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesService.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesService.java
@@ -19,6 +19,7 @@
*/
package org.sonarqube.ws.client.qualityprofile;
+import org.sonarqube.ws.QualityProfiles.CreateWsResponse;
import org.sonarqube.ws.QualityProfiles.SearchWsResponse;
import org.sonarqube.ws.client.BaseService;
import org.sonarqube.ws.client.GetRequest;
@@ -26,6 +27,7 @@ import org.sonarqube.ws.client.PostRequest;
import org.sonarqube.ws.client.WsConnector;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_ADD_PROJECT;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_CREATE;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_REMOVE_PROJECT;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_SEARCH;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.CONTROLLER_QUALITY_PROFILES;
@@ -70,4 +72,11 @@ public class QualityProfilesService extends BaseService {
.setParam(PARAM_PROJECT_UUID, request.getProjectUuid()));
}
+ public CreateWsResponse create(CreateRequest request) {
+ PostRequest postRequest = new PostRequest(path(ACTION_CREATE))
+ .setParam(PARAM_LANGUAGE, request.getLanguage())
+ .setParam(PARAM_PROFILE_NAME, request.getProfileName());
+ return call(postRequest, CreateWsResponse.parser());
+ }
+
}
diff --git a/sonar-ws/src/main/protobuf/ws-qualityprofiles.proto b/sonar-ws/src/main/protobuf/ws-qualityprofiles.proto
index 0829180d46d..d131d02714c 100644
--- a/sonar-ws/src/main/protobuf/ws-qualityprofiles.proto
+++ b/sonar-ws/src/main/protobuf/ws-qualityprofiles.proto
@@ -45,3 +45,27 @@ message SearchWsResponse {
optional string userUpdatedAt = 14;
}
}
+
+// WS api/qualityprofiles/create
+message CreateWsResponse {
+ optional QualityProfile profile = 1;
+
+ message QualityProfile {
+ optional string key = 1;
+ optional string name = 2;
+ optional string language = 3;
+ optional string languageName = 4;
+ optional bool isInherited = 5;
+ optional bool isDefault = 6;
+ optional Infos infos = 7;
+ optional Warnings warnings = 8;
+
+ message Infos {
+ repeated string infos = 1;
+ }
+
+ message Warnings {
+ repeated string warnings = 1;
+ }
+ }
+}
diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/qualityprofile/CreateRequestTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/qualityprofile/CreateRequestTest.java
new file mode 100644
index 00000000000..768f3a68cda
--- /dev/null
+++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/qualityprofile/CreateRequestTest.java
@@ -0,0 +1,59 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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 org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CreateRequestTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ CreateRequest.Builder underTest = CreateRequest.builder();
+
+ @Test
+ public void create_set_request() {
+ CreateRequest result = underTest
+ .setLanguage("java")
+ .setProfileName("Sonar way")
+ .build();
+
+ assertThat(result.getLanguage()).isEqualTo("java");
+ assertThat(result.getProfileName()).isEqualTo("Sonar way");
+ }
+
+ @Test
+ public void fail_when_no_language() {
+ expectedException.expect(IllegalArgumentException.class);
+ underTest.setProfileName("Sonar way").build();
+ }
+
+ @Test
+ public void fail_when_no_profile_name() {
+ expectedException.expect(IllegalArgumentException.class);
+ underTest.setLanguage("java").build();
+ }
+
+}
diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesServiceTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesServiceTest.java
index 91ddb86ef69..0867a1542f3 100644
--- a/sonar-ws/src/test/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesServiceTest.java
+++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesServiceTest.java
@@ -87,4 +87,17 @@ public class QualityProfilesServiceTest {
.hasParam(PARAM_PROJECT_KEY, "sample")
.andNoOtherParam();
}
+
+ @Test
+ public void create_project() throws Exception {
+ underTest.create(CreateRequest.builder()
+ .setLanguage("xoo")
+ .setProfileName("Sonar Way")
+ .build());
+
+ serviceTester.assertThat(serviceTester.getPostRequest())
+ .hasParam(PARAM_LANGUAGE, "xoo")
+ .hasParam(PARAM_PROFILE_NAME, "Sonar Way")
+ .andNoOtherParam();
+ }
}