aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2016-08-16 17:34:13 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2016-08-18 11:46:41 +0200
commit3a4fb4b364f2c04411adbb4d26d1952f94d8934e (patch)
treeaa220a38326ae1dc0b699b38c0e1216907a58696 /server
parentcc95453e800ca4b1537e8e1aa9a58fab8c4a1f03 (diff)
downloadsonarqube-3a4fb4b364f2c04411adbb4d26d1952f94d8934e.tar.gz
sonarqube-3a4fb4b364f2c04411adbb4d26d1952f94d8934e.zip
SONAR-7968 Create /api/settings/list_definitions WS
Diffstat (limited to 'server')
-rw-r--r--server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryImpl.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/settings/ProjectSettingsFactory.java (renamed from server/sonar-server/src/main/java/org/sonar/server/properties/ProjectSettingsFactory.java)2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/settings/package-info.java (renamed from server/sonar-server/src/main/java/org/sonar/server/properties/package-info.java)2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/settings/ws/ListDefinitionsAction.java167
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWs.java42
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWsAction.java26
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWsModule.java31
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/settings/ws/package-info.java23
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/settings/ws/list_definitions-example.json70
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryTest.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/settings/ProjectSettingsFactoryTest.java (renamed from server/sonar-server/src/test/java/org/sonar/server/properties/ProjectSettingsFactoryTest.java)2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/settings/ws/ListDefinitionsActionTest.java408
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/settings/ws/SettingsWsModuleTest.java34
15 files changed, 811 insertions, 8 deletions
diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
index 0af579d220b..84c62415f17 100644
--- a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
+++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
@@ -113,7 +113,6 @@ import org.sonar.server.plugins.InstalledPluginReferentialFactory;
import org.sonar.server.plugins.ServerExtensionInstaller;
import org.sonar.server.plugins.privileged.PrivilegedPluginsBootstraper;
import org.sonar.server.plugins.privileged.PrivilegedPluginsStopper;
-import org.sonar.server.properties.ProjectSettingsFactory;
import org.sonar.server.qualityprofile.BuiltInProfiles;
import org.sonar.server.qualityprofile.QProfileComparison;
import org.sonar.server.qualityprofile.QProfileLookup;
@@ -129,6 +128,7 @@ import org.sonar.server.rule.RuleRepositories;
import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.rule.index.RuleIndexer;
import org.sonar.server.search.EsSearchModule;
+import org.sonar.server.settings.ProjectSettingsFactory;
import org.sonar.server.startup.LogServerId;
import org.sonar.server.test.index.TestIndexer;
import org.sonar.server.user.DefaultUserFinder;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryImpl.java
index 19f5f5939f3..ec0829d5983 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryImpl.java
@@ -22,7 +22,7 @@ package org.sonar.server.computation.task.projectanalysis.component;
import java.util.Collection;
import java.util.Map;
import org.sonar.api.config.Settings;
-import org.sonar.server.properties.ProjectSettingsFactory;
+import org.sonar.server.settings.ProjectSettingsFactory;
import org.sonar.server.util.cache.CacheLoader;
import org.sonar.server.util.cache.MemoryCache;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
index 015abc77720..e92fc98886d 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
@@ -176,7 +176,6 @@ import org.sonar.server.plugins.ws.UninstallAction;
import org.sonar.server.plugins.ws.UpdatesAction;
import org.sonar.server.project.ws.ProjectsWsModule;
import org.sonar.server.projectlink.ws.ProjectLinksModule;
-import org.sonar.server.properties.ProjectSettingsFactory;
import org.sonar.server.qualitygate.QualityGateModule;
import org.sonar.server.qualityprofile.BuiltInProfiles;
import org.sonar.server.qualityprofile.QProfileBackuper;
@@ -235,6 +234,8 @@ import org.sonar.server.rule.ws.RuleMapper;
import org.sonar.server.rule.ws.RuleQueryFactory;
import org.sonar.server.rule.ws.RulesWs;
import org.sonar.server.rule.ws.TagsAction;
+import org.sonar.server.settings.ProjectSettingsFactory;
+import org.sonar.server.settings.ws.SettingsWsModule;
import org.sonar.server.source.HtmlSourceDecorator;
import org.sonar.server.source.SourceService;
import org.sonar.server.source.ws.HashAction;
@@ -580,8 +581,9 @@ public class PlatformLevel4 extends PlatformLevel {
TestIndex.class,
TestIndexer.class,
- // Properties
+ // Settings
PropertiesWs.class,
+ SettingsWsModule.class,
TypeValidationModule.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/properties/ProjectSettingsFactory.java b/server/sonar-server/src/main/java/org/sonar/server/settings/ProjectSettingsFactory.java
index 5bb613c80c1..fe9c4e60c53 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/properties/ProjectSettingsFactory.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/settings/ProjectSettingsFactory.java
@@ -17,7 +17,7 @@
* 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.properties;
+package org.sonar.server.settings;
import java.util.List;
import org.sonar.api.ce.ComputeEngineSide;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/properties/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/settings/package-info.java
index 3bedb52cb00..f24dcdd32dc 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/properties/package-info.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/settings/package-info.java
@@ -18,6 +18,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@ParametersAreNonnullByDefault
-package org.sonar.server.properties;
+package org.sonar.server.settings;
import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/settings/ws/ListDefinitionsAction.java b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/ListDefinitionsAction.java
new file mode 100644
index 00000000000..1475d0ab153
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/ListDefinitionsAction.java
@@ -0,0 +1,167 @@
+/*
+ * 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.settings.ws;
+
+import java.util.List;
+import javax.annotation.CheckForNull;
+import org.sonar.api.PropertyType;
+import org.sonar.api.config.PropertyDefinition;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.PropertyFieldDefinition;
+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.web.UserRole;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.user.UserSession;
+import org.sonarqube.ws.Settings;
+import org.sonarqube.ws.Settings.ListDefinitionsWsResponse;
+
+import static org.elasticsearch.common.Strings.isNullOrEmpty;
+import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
+
+public class ListDefinitionsAction implements SettingsWsAction {
+
+ private static final String PARAM_COMPONENT_ID = "componentId";
+ private static final String PARAM_COMPONENT_KEY = "componentKey";
+
+ private final DbClient dbClient;
+ private final ComponentFinder componentFinder;
+ private final UserSession userSession;
+ private final PropertyDefinitions propertyDefinitions;
+
+ public ListDefinitionsAction(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, PropertyDefinitions propertyDefinitions) {
+ this.dbClient = dbClient;
+ this.componentFinder = componentFinder;
+ this.userSession = userSession;
+ this.propertyDefinitions = propertyDefinitions;
+ }
+
+ @Override
+ public void define(WebService.NewController context) {
+ WebService.NewAction action = context.createAction("list_definitions")
+ .setDescription(String.format("Returns definitions of properties.<br>" +
+ "Either '%s' or '%s' could be provided, not both.<br> " +
+ "Requires one of the following permissions: " +
+ "<ul>" +
+ "<li>'Administer System'</li>" +
+ "<li>'Administer' rights on the specified component</li>" +
+ "</ul>", PARAM_COMPONENT_ID, PARAM_COMPONENT_KEY))
+ .setResponseExample(getClass().getResource("list_definitions-example.json"))
+ .setSince("6.1")
+ .setHandler(this);
+
+ action.createParam(PARAM_COMPONENT_ID)
+ .setDescription("Component id")
+ .setExampleValue(UUID_EXAMPLE_01);
+
+ action.createParam(PARAM_COMPONENT_KEY)
+ .setDescription("Component key")
+ .setExampleValue("my_component_key");
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ writeProtobuf(doHandle(request), request, response);
+ }
+
+ private ListDefinitionsWsResponse doHandle(Request request) {
+ String qualifier = getQualifier(request);
+ ListDefinitionsWsResponse.Builder wsResponse = ListDefinitionsWsResponse.newBuilder();
+
+ propertyDefinitions.getAll().stream()
+ .filter(definition -> qualifier == null ? definition.global() : definition.qualifiers().contains(qualifier))
+ .filter(definition -> !definition.type().equals(PropertyType.LICENSE))
+ .forEach(definition -> addDefinition(definition, wsResponse));
+ return wsResponse.build();
+ }
+
+ private void addDefinition(PropertyDefinition definition, ListDefinitionsWsResponse.Builder wsResponse) {
+ String key = definition.key();
+ Settings.Definition.Builder builder = wsResponse.addDefinitionsBuilder()
+ .setKey(key)
+ .setType(Settings.Type.valueOf(definition.type().name()))
+ .setMultiValues(definition.multiValues());
+ String name = definition.name();
+ if (!isNullOrEmpty(name)) {
+ builder.setName(name);
+ }
+ String description = definition.description();
+ if (!isNullOrEmpty(description)) {
+ builder.setDescription(description);
+ }
+ String category = propertyDefinitions.getCategory(key);
+ if (!isNullOrEmpty(category)) {
+ builder.setCategory(category);
+ }
+ String subCategory = propertyDefinitions.getSubCategory(key);
+ if (!isNullOrEmpty(subCategory)) {
+ builder.setSubCategory(subCategory);
+ }
+ String defaultValue = definition.defaultValue();
+ if (!isNullOrEmpty(defaultValue)) {
+ builder.setDefaultValue(defaultValue);
+ }
+ List<String> options = definition.options();
+ if (!options.isEmpty()) {
+ builder.addAllOptions(options);
+ }
+ List<PropertyFieldDefinition> fields = definition.fields();
+ if (!fields.isEmpty()) {
+ fields.stream()
+ .filter(fieldDefinition -> !fieldDefinition.type().equals(PropertyType.LICENSE))
+ .forEach(fieldDefinition -> addField(fieldDefinition, builder));
+ }
+ }
+
+ private static void addField(PropertyFieldDefinition fieldDefinition, Settings.Definition.Builder builder) {
+ builder.addFieldsBuilder()
+ .setKey(fieldDefinition.key())
+ .setName(fieldDefinition.name())
+ .setType(Settings.Type.valueOf(fieldDefinition.type().name()))
+ .setIndicativeSize(fieldDefinition.indicativeSize())
+ .addAllOptions(fieldDefinition.options())
+ .build();
+ }
+
+ @CheckForNull
+ private String getQualifier(Request request) {
+ DbSession dbSession = dbClient.openSession(false);
+ try {
+ if (request.hasParam(PARAM_COMPONENT_ID) || request.hasParam(PARAM_COMPONENT_KEY)) {
+ ComponentDto component = componentFinder.getByUuidOrKey(dbSession, request.param(PARAM_COMPONENT_ID), request.param(PARAM_COMPONENT_KEY),
+ ComponentFinder.ParamNames.ID_AND_KEY);
+ userSession.checkComponentUuidPermission(UserRole.ADMIN, component.uuid());
+ return component.qualifier();
+ } else {
+ userSession.checkPermission(GlobalPermissions.SYSTEM_ADMIN);
+ return null;
+ }
+ } finally {
+ dbClient.closeSession(dbSession);
+ }
+ }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWs.java b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWs.java
new file mode 100644
index 00000000000..6ed340e0884
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWs.java
@@ -0,0 +1,42 @@
+/*
+ * 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.settings.ws;
+
+import org.sonar.api.server.ws.WebService;
+
+public class SettingsWs implements WebService {
+
+ private final SettingsWsAction[] actions;
+
+ public SettingsWs(SettingsWsAction... actions) {
+ this.actions = actions;
+ }
+
+ @Override
+ public void define(Context context) {
+ NewController controller = context.createController("api/settings")
+ .setDescription("Manage settings.")
+ .setSince("6.1");
+ for (SettingsWsAction action : actions) {
+ action.define(controller);
+ }
+ controller.done();
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWsAction.java
new file mode 100644
index 00000000000..63b8724eded
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWsAction.java
@@ -0,0 +1,26 @@
+/*
+ * 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.settings.ws;
+
+import org.sonar.server.ws.WsAction;
+
+public interface SettingsWsAction extends WsAction {
+ // marker interface
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWsModule.java
new file mode 100644
index 00000000000..fb0e42953f7
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWsModule.java
@@ -0,0 +1,31 @@
+/*
+ * 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.settings.ws;
+
+import org.sonar.core.platform.Module;
+
+public class SettingsWsModule extends Module {
+ @Override
+ protected void configureModule() {
+ add(
+ SettingsWs.class,
+ ListDefinitionsAction.class);
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/settings/ws/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/package-info.java
new file mode 100644
index 00000000000..c144acaebf8
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.settings.ws;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/settings/ws/list_definitions-example.json b/server/sonar-server/src/main/resources/org/sonar/server/settings/ws/list_definitions-example.json
new file mode 100644
index 00000000000..79b4e317ebd
--- /dev/null
+++ b/server/sonar-server/src/main/resources/org/sonar/server/settings/ws/list_definitions-example.json
@@ -0,0 +1,70 @@
+{
+ "definitions": [
+ {
+ "key": "sonar.string",
+ "name": "String",
+ "description": "String property",
+ "type": "STRING",
+ "category": "general",
+ "subCategory": "test",
+ "multiValues": false,
+ "defaultValue": "123",
+ "options": [],
+ "fields": []
+ },
+ {
+ "key": "sonar.list",
+ "name": "List",
+ "description": "List property",
+ "type": "SINGLE_SELECT_LIST",
+ "category": "general",
+ "subCategory": "general",
+ "multiValues": false,
+ "options": [
+ "a",
+ "b"
+ ],
+ "fields": []
+ },
+ {
+ "key": "sonar.multiValues",
+ "name": "Multi values",
+ "description": "Multi values property",
+ "type": "STRING",
+ "category": "general",
+ "subCategory": "general",
+ "multiValues": true,
+ "options": [],
+ "fields": []
+ },
+ {
+ "key": "sonar.propertySet",
+ "name": "Property Set",
+ "description": "Property Set property",
+ "type": "PROPERTY_SET",
+ "category": "property",
+ "subCategory": "set",
+ "multiValues": false,
+ "options": [],
+ "fields": [
+ {
+ "key": "text",
+ "name": "Text",
+ "type": "TEXT",
+ "indicativeSize": 10,
+ "options": []
+ },
+ {
+ "key": "list",
+ "name": "List",
+ "type": "SINGLE_SELECT_LIST",
+ "indicativeSize": 20,
+ "options": [
+ "value1",
+ "value2"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryTest.java
index 173cebac3dc..7ac0c490f36 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryTest.java
@@ -32,7 +32,7 @@ import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.property.PropertiesDao;
import org.sonar.db.property.PropertyDto;
-import org.sonar.server.properties.ProjectSettingsFactory;
+import org.sonar.server.settings.ProjectSettingsFactory;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/properties/ProjectSettingsFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/settings/ProjectSettingsFactoryTest.java
index 30dc66bb638..7f6fed937eb 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/properties/ProjectSettingsFactoryTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/settings/ProjectSettingsFactoryTest.java
@@ -17,7 +17,7 @@
* 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.properties;
+package org.sonar.server.settings;
import org.junit.Test;
import org.sonar.api.config.Settings;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/settings/ws/ListDefinitionsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/settings/ws/ListDefinitionsActionTest.java
new file mode 100644
index 00000000000..2365b157c6b
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/settings/ws/ListDefinitionsActionTest.java
@@ -0,0 +1,408 @@
+/*
+ * 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.settings.ws;
+
+import java.io.IOException;
+import javax.annotation.Nullable;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.PropertyType;
+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.utils.System2;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.WsActionTester;
+import org.sonar.test.JsonAssert;
+import org.sonarqube.ws.MediaTypes;
+import org.sonarqube.ws.Settings;
+import org.sonarqube.ws.Settings.ListDefinitionsWsResponse;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.resources.Qualifiers.MODULE;
+import static org.sonar.api.resources.Qualifiers.PROJECT;
+import static org.sonar.api.web.UserRole.ADMIN;
+import static org.sonar.api.web.UserRole.USER;
+import static org.sonar.core.permission.GlobalPermissions.DASHBOARD_SHARING;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+import static org.sonar.db.component.ComponentTesting.newProjectDto;
+import static org.sonarqube.ws.Settings.Type.BOOLEAN;
+import static org.sonarqube.ws.Settings.Type.PROPERTY_SET;
+import static org.sonarqube.ws.Settings.Type.SINGLE_SELECT_LIST;
+import static org.sonarqube.ws.Settings.Type.STRING;
+import static org.sonarqube.ws.Settings.Type.TEXT;
+
+public class ListDefinitionsActionTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
+
+ @Rule
+ public DbTester db = DbTester.create(System2.INSTANCE);
+
+ DbClient dbClient = db.getDbClient();
+ ComponentDbTester componentDb = new ComponentDbTester(db);
+
+ ComponentDto project;
+
+ PropertyDefinitions propertyDefinitions = new PropertyDefinitions();
+
+ WsActionTester ws = new WsActionTester(new ListDefinitionsAction(dbClient, new ComponentFinder(dbClient), userSession, propertyDefinitions));
+
+ @Before
+ public void setUp() throws Exception {
+ project = insertProject();
+ }
+
+ @Test
+ public void return_settings_definitions() {
+ setUserAsSystemAdmin();
+ propertyDefinitions.addComponent(PropertyDefinition
+ .builder("foo")
+ .name("Foo")
+ .description("desc")
+ .category("cat")
+ .subCategory("subCat")
+ .type(PropertyType.TEXT)
+ .defaultValue("default")
+ .multiValues(true)
+ .build());
+
+ ListDefinitionsWsResponse result = newRequest();
+ assertThat(result.getDefinitionsList()).hasSize(1);
+
+ Settings.Definition definition = result.getDefinitions(0);
+ assertThat(definition.getKey()).isEqualTo("foo");
+ assertThat(definition.getName()).isEqualTo("Foo");
+ assertThat(definition.getDescription()).isEqualTo("desc");
+ assertThat(definition.getCategory()).isEqualTo("cat");
+ assertThat(definition.getSubCategory()).isEqualTo("subCat");
+ assertThat(definition.getType()).isEqualTo(TEXT);
+ assertThat(definition.getDefaultValue()).isEqualTo("default");
+ assertThat(definition.getMultiValues()).isTrue();
+ }
+
+ @Test
+ public void return_settings_definitions_with_minimum_fields() {
+ setUserAsSystemAdmin();
+ propertyDefinitions.addComponent(PropertyDefinition
+ .builder("foo")
+ .build());
+
+ ListDefinitionsWsResponse result = newRequest();
+ assertThat(result.getDefinitionsList()).hasSize(1);
+
+ Settings.Definition definition = result.getDefinitions(0);
+ assertThat(definition.getKey()).isEqualTo("foo");
+ assertThat(definition.getType()).isEqualTo(STRING);
+ assertThat(definition.hasName()).isFalse();
+ assertThat(definition.hasCategory()).isFalse();
+ assertThat(definition.hasSubCategory()).isFalse();
+ assertThat(definition.hasDefaultValue()).isFalse();
+ assertThat(definition.getMultiValues()).isFalse();
+ assertThat(definition.getOptionsCount()).isZero();
+ assertThat(definition.getFieldsCount()).isZero();
+ }
+
+ @Test
+ public void return_default_category() throws Exception {
+ setUserAsSystemAdmin();
+ propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build(), "default");
+ propertyDefinitions.addComponent(PropertyDefinition.builder("foo").category("").build(), "default");
+
+ ListDefinitionsWsResponse result = newRequest();
+ assertThat(result.getDefinitionsList()).hasSize(1);
+ assertThat(result.getDefinitions(0).getCategory()).isEqualTo("default");
+ assertThat(result.getDefinitions(0).getSubCategory()).isEqualTo("default");
+ }
+
+ @Test
+ public void return_single_select_list_property() throws Exception {
+ setUserAsSystemAdmin();
+ propertyDefinitions.addComponent(PropertyDefinition
+ .builder("foo")
+ .type(PropertyType.SINGLE_SELECT_LIST)
+ .options("one", "two")
+ .build());
+
+ ListDefinitionsWsResponse result = newRequest();
+ assertThat(result.getDefinitionsList()).hasSize(1);
+
+ Settings.Definition definition = result.getDefinitions(0);
+ assertThat(definition.getType()).isEqualTo(SINGLE_SELECT_LIST);
+ assertThat(definition.getOptionsList()).containsExactly("one", "two");
+ }
+
+ @Test
+ public void return_property_set() throws Exception {
+ setUserAsSystemAdmin();
+ propertyDefinitions.addComponent(PropertyDefinition
+ .builder("foo")
+ .type(PropertyType.PROPERTY_SET)
+ .fields(
+ PropertyFieldDefinition.build("boolean").name("Boolean").type(PropertyType.BOOLEAN).indicativeSize(15).build(),
+ PropertyFieldDefinition.build("list").name("List").type(PropertyType.SINGLE_SELECT_LIST).options("one", "two").build())
+ .build());
+
+ ListDefinitionsWsResponse result = newRequest();
+ assertThat(result.getDefinitionsList()).hasSize(1);
+
+ Settings.Definition definition = result.getDefinitions(0);
+ assertThat(definition.getType()).isEqualTo(PROPERTY_SET);
+ assertThat(definition.getFieldsList()).hasSize(2);
+
+ assertThat(definition.getFields(0).getKey()).isEqualTo("boolean");
+ assertThat(definition.getFields(0).getName()).isEqualTo("Boolean");
+ assertThat(definition.getFields(0).getType()).isEqualTo(BOOLEAN);
+ assertThat(definition.getFields(0).getOptionsCount()).isZero();
+ assertThat(definition.getFields(0).getIndicativeSize()).isEqualTo(15);
+
+ assertThat(definition.getFields(1).getKey()).isEqualTo("list");
+ assertThat(definition.getFields(1).getName()).isEqualTo("List");
+ assertThat(definition.getFields(1).getType()).isEqualTo(SINGLE_SELECT_LIST);
+ assertThat(definition.getFields(1).getOptionsList()).containsExactly("one", "two");
+ // 20 is the default value
+ assertThat(definition.getFields(1).getIndicativeSize()).isEqualTo(20);
+ }
+
+ @Test
+ public void does_not_return_license_type_property_set() throws Exception {
+ setUserAsSystemAdmin();
+ propertyDefinitions.addComponent(PropertyDefinition
+ .builder("foo")
+ .type(PropertyType.PROPERTY_SET)
+ .fields(PropertyFieldDefinition.build("license").name("License").type(PropertyType.LICENSE).build())
+ .build());
+
+ ListDefinitionsWsResponse result = newRequest();
+ assertThat(result.getDefinitionsList()).hasSize(1);
+ assertThat(result.getDefinitions(0).getFieldsList()).isEmpty();
+ }
+
+ @Test
+ public void return_global_settings_definitions() {
+ setUserAsSystemAdmin();
+ propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build());
+
+ ListDefinitionsWsResponse result = newRequest();
+ assertThat(result.getDefinitionsList()).hasSize(1);
+ }
+
+ @Test
+ public void return_project_settings_def_by_project_key() {
+ setUserAsProjectAdmin();
+ propertyDefinitions.addComponent(PropertyDefinition
+ .builder("foo")
+ .onQualifiers(PROJECT)
+ .build());
+
+ ListDefinitionsWsResponse result = newRequest(null, project.key());
+ assertThat(result.getDefinitionsList()).hasSize(1);
+ }
+
+ @Test
+ public void return_project_settings_def_by_project_id() {
+ setUserAsProjectAdmin();
+ propertyDefinitions.addComponent(PropertyDefinition
+ .builder("foo")
+ .onQualifiers(PROJECT)
+ .build());
+
+ ListDefinitionsWsResponse result = newRequest(project.uuid(), null);
+ assertThat(result.getDefinitionsList()).hasSize(1);
+ }
+
+ @Test
+ public void return_only_global_properties_when_no_component_parameter() throws Exception {
+ setUserAsSystemAdmin();
+ propertyDefinitions.addComponents(asList(
+ PropertyDefinition.builder("global").build(),
+ PropertyDefinition.builder("global-and-project").onQualifiers(PROJECT).build(),
+ PropertyDefinition.builder("only-on-project").onlyOnQualifiers(PROJECT).build(),
+ PropertyDefinition.builder("only-on-module").onlyOnQualifiers(MODULE).build()));
+
+ ListDefinitionsWsResponse result = newRequest();
+ assertThat(result.getDefinitionsList()).extracting("key").containsOnly("global", "global-and-project");
+ }
+
+ @Test
+ public void return_only_properties_available_for_component_qualifier() throws Exception {
+ setUserAsProjectAdmin();
+ propertyDefinitions.addComponents(asList(
+ PropertyDefinition.builder("global").build(),
+ PropertyDefinition.builder("global-and-project").onQualifiers(PROJECT).build(),
+ PropertyDefinition.builder("only-on-project").onlyOnQualifiers(PROJECT).build(),
+ PropertyDefinition.builder("only-on-module").onlyOnQualifiers(MODULE).build()));
+
+ ListDefinitionsWsResponse result = newRequest(project.uuid(), null);
+ assertThat(result.getDefinitionsList()).extracting("key").containsOnly("global-and-project", "only-on-project");
+ }
+
+ @Test
+ public void does_not_return_hidden_properties() throws Exception {
+ setUserAsSystemAdmin();
+ propertyDefinitions.addComponent(PropertyDefinition.builder("foo").hidden().build());
+
+ ListDefinitionsWsResponse result = newRequest();
+ assertThat(result.getDefinitionsList()).isEmpty();
+ }
+
+ @Test
+ public void does_not_return_license_type() throws Exception {
+ setUserAsSystemAdmin();
+ propertyDefinitions.addComponent(PropertyDefinition.builder("license").type(PropertyType.LICENSE).build());
+
+ ListDefinitionsWsResponse result = newRequest();
+ assertThat(result.getDefinitionsList()).isEmpty();
+ }
+
+ @Test
+ public void fail_when_id_and_key_are_set() throws Exception {
+ setUserAsProjectAdmin();
+
+ expectedException.expect(IllegalArgumentException.class);
+ newRequest(project.uuid(), project.key());
+ }
+
+ @Test
+ public void fail_when_not_system_admin() throws Exception {
+ userSession.login("not-admin").setGlobalPermissions(DASHBOARD_SHARING);
+ propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build());
+
+ expectedException.expect(ForbiddenException.class);
+ newRequest();
+ }
+
+ @Test
+ public void fail_when_not_project_admin() throws Exception {
+ userSession.login("project-admin").addProjectUuidPermissions(USER, project.uuid());
+ propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build());
+
+ expectedException.expect(ForbiddenException.class);
+ newRequest(project.uuid(), null);
+ }
+
+ @Test
+ public void test_ws_definition() {
+ WebService.Action action = ws.getDef();
+ assertThat(action).isNotNull();
+ assertThat(action.isInternal()).isFalse();
+ assertThat(action.isPost()).isFalse();
+ assertThat(action.responseExampleAsString()).isNotEmpty();
+ assertThat(action.params()).hasSize(2);
+ }
+
+ @Test
+ public void test_example_json_response() {
+ setUserAsSystemAdmin();
+ propertyDefinitions.addComponents(asList(
+ PropertyDefinition.builder("sonar.string")
+ .name("String")
+ .description("String property")
+ .type(PropertyType.STRING)
+ .category("general")
+ .subCategory("test")
+ .defaultValue("123")
+ .build(),
+ PropertyDefinition.builder("sonar.list")
+ .name("List")
+ .description("List property")
+ .type(PropertyType.SINGLE_SELECT_LIST)
+ .category("general")
+ .options("a", "b")
+ .build(),
+ PropertyDefinition.builder("sonar.multiValues")
+ .name("Multi values")
+ .description("Multi values property")
+ .type(PropertyType.STRING)
+ .category("general")
+ .multiValues(true)
+ .build(),
+ PropertyDefinition.builder("sonar.propertySet")
+ .name("Property Set")
+ .description("Property Set property")
+ .type(PropertyType.PROPERTY_SET)
+ .category("property")
+ .subCategory("set")
+ .fields(
+ PropertyFieldDefinition.build("text")
+ .name("Text")
+ .type(PropertyType.TEXT)
+ .indicativeSize(10)
+ .build(),
+ PropertyFieldDefinition.build("list")
+ .name("List")
+ .type(PropertyType.SINGLE_SELECT_LIST)
+ .options("value1", "value2")
+ .build())
+ .build()));
+
+ String result = ws.newRequest().setMediaType(MediaTypes.JSON).execute().getInput();
+ JsonAssert.assertJson(ws.getDef().responseExampleAsString()).isSimilarTo(result);
+ }
+
+ private ComponentDto insertProject() {
+ return componentDb.insertComponent(newProjectDto());
+ }
+
+ private ListDefinitionsWsResponse newRequest() {
+ return newRequest(null, null);
+ }
+
+ private ListDefinitionsWsResponse newRequest(@Nullable String id, @Nullable String key) {
+ TestRequest request = ws.newRequest()
+ .setMediaType(MediaTypes.PROTOBUF);
+ if (id != null) {
+ request.setParam("componentId", id);
+ }
+ if (key != null) {
+ request.setParam("componentKey", key);
+ }
+ try {
+ return ListDefinitionsWsResponse.parseFrom(request.execute().getInputStream());
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private void setUserAsSystemAdmin() {
+ userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
+ }
+
+ private void setUserAsProjectAdmin() {
+ userSession.login("project-admin").addProjectUuidPermissions(ADMIN, project.uuid());
+ }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/settings/ws/SettingsWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/settings/ws/SettingsWsModuleTest.java
new file mode 100644
index 00000000000..e37e98e1523
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/settings/ws/SettingsWsModuleTest.java
@@ -0,0 +1,34 @@
+/*
+ * 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.settings.ws;
+
+import org.junit.Test;
+import org.sonar.core.platform.ComponentContainer;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SettingsWsModuleTest {
+ @Test
+ public void verify_count_of_added_components() {
+ ComponentContainer container = new ComponentContainer();
+ new SettingsWsModule().configure(container);
+ assertThat(container.size()).isEqualTo(2 + 2);
+ }
+}