@@ -21,6 +21,7 @@ package org.sonar.plugins.checkstyle; | |||
import org.sonar.api.Properties; | |||
import org.sonar.api.Property; | |||
import org.sonar.api.PropertyType; | |||
import org.sonar.api.SonarPlugin; | |||
import java.util.Arrays; | |||
@@ -35,7 +36,7 @@ import java.util.List; | |||
+ " See <a href='http://checkstyle.sourceforge.net/config.html'>Checkstyle configuration page</a> to get more information on those filters.", | |||
project = false, | |||
global = true, | |||
type = Property.Type.TEXT)}) | |||
type = PropertyType.TEXT)}) | |||
public final class CheckstylePlugin extends SonarPlugin { | |||
public List getExtensions() { |
@@ -20,11 +20,9 @@ | |||
package org.sonar.plugins.core; | |||
import com.google.common.collect.Lists; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.Properties; | |||
import org.sonar.api.Property; | |||
import org.sonar.api.SonarPlugin; | |||
import org.sonar.api.*; | |||
import org.sonar.api.checks.NoSonarFilter; | |||
import org.sonar.api.PropertyType; | |||
import org.sonar.api.resources.Java; | |||
import org.sonar.plugins.core.batch.ExcludedResourceFilter; | |||
import org.sonar.plugins.core.batch.IndexProjectPostJob; | |||
@@ -50,177 +48,177 @@ import org.sonar.plugins.core.widgets.reviews.*; | |||
import java.util.List; | |||
@Properties({ | |||
@Property( | |||
key = CoreProperties.SERVER_BASE_URL, | |||
defaultValue = CoreProperties.SERVER_BASE_URL_DEFAULT_VALUE, | |||
name = "Server base URL", | |||
description = "HTTP URL of this Sonar server, such as <i>http://yourhost.yourdomain/sonar</i>. This value is used i.e. to create links in emails.", | |||
project = false, | |||
global = true, | |||
category = CoreProperties.CATEGORY_GENERAL), | |||
@Property( | |||
key = CoreProperties.CORE_COVERAGE_PLUGIN_PROPERTY, | |||
defaultValue = "cobertura", | |||
name = "Code coverage plugin", | |||
description = "Key of the code coverage plugin to use.", | |||
project = true, | |||
global = true, | |||
category = CoreProperties.CATEGORY_CODE_COVERAGE), | |||
@Property( | |||
key = CoreProperties.CORE_IMPORT_SOURCES_PROPERTY, | |||
defaultValue = "" + CoreProperties.CORE_IMPORT_SOURCES_DEFAULT_VALUE, | |||
name = "Import sources", | |||
description = "Set to false if sources should not be displayed, e.g. for security reasons.", | |||
project = true, | |||
module = true, | |||
global = true, | |||
category = CoreProperties.CATEGORY_SECURITY, | |||
type = Property.Type.BOOLEAN), | |||
@Property( | |||
key = CoreProperties.CORE_TENDENCY_DEPTH_PROPERTY, | |||
defaultValue = "" + CoreProperties.CORE_TENDENCY_DEPTH_DEFAULT_VALUE, | |||
name = "Tendency period", | |||
description = TendencyDecorator.PROP_DAYS_DESCRIPTION, | |||
project = false, | |||
global = true, | |||
category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS, | |||
type = Property.Type.INTEGER), | |||
@Property( | |||
key = CoreProperties.SKIP_TENDENCIES_PROPERTY, | |||
defaultValue = "" + CoreProperties.SKIP_TENDENCIES_DEFAULT_VALUE, | |||
name = "Skip tendencies", | |||
description = "Skip calculation of measure tendencies", | |||
project = true, | |||
module = false, | |||
global = true, | |||
category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS, | |||
type = Property.Type.BOOLEAN), | |||
@Property( | |||
key = CoreProperties.CORE_SKIPPED_MODULES_PROPERTY, | |||
name = "Exclude modules", | |||
description = "Maven artifact ids of modules to exclude (comma-separated).", | |||
project = true, | |||
global = false, | |||
category = CoreProperties.CATEGORY_GENERAL), | |||
@Property( | |||
key = CoreProperties.CORE_FORCE_AUTHENTICATION_PROPERTY, | |||
defaultValue = "" + CoreProperties.CORE_FORCE_AUTHENTICATION_DEFAULT_VALUE, | |||
name = "Force user authentication", | |||
description = "Forcing user authentication stops un-logged users to access Sonar.", | |||
project = false, | |||
global = true, | |||
category = CoreProperties.CATEGORY_SECURITY, | |||
type = Property.Type.BOOLEAN), | |||
@Property( | |||
key = CoreProperties.CORE_ALLOW_USERS_TO_SIGNUP_PROPERTY, | |||
defaultValue = "" + CoreProperties.CORE_ALLOW_USERS_TO_SIGNUP_DEAULT_VALUE, | |||
name = "Allow users to sign up online", | |||
description = "Users can sign up online.", | |||
project = false, | |||
global = true, | |||
category = CoreProperties.CATEGORY_SECURITY, | |||
type = Property.Type.BOOLEAN), | |||
@Property( | |||
key = CoreProperties.CORE_DEFAULT_GROUP, | |||
defaultValue = CoreProperties.CORE_DEFAULT_GROUP_DEFAULT_VALUE, | |||
name = "Default user group", | |||
description = "Any new users will automatically join this group.", | |||
project = false, | |||
global = true, | |||
category = CoreProperties.CATEGORY_SECURITY), | |||
@Property( | |||
key = CoreProperties.CORE_VIOLATION_LOCALE_PROPERTY, | |||
defaultValue = "en", | |||
name = "Locale used for violation messages", | |||
description = "Locale to be used when generating violation messages. It's up to each rule engine to support this global internationalization property", | |||
project = true, | |||
global = true, | |||
category = CoreProperties.CATEGORY_L10N), | |||
@Property( | |||
key = "sonar.timemachine.period1", | |||
name = "Period 1", | |||
description = "Period used to compare measures and track new violations. Values are : <ul class='bullet'><li>Number of days before " + | |||
"analysis, for example 5.</li><li>A custom date. Format is yyyy-MM-dd, for example 2010-12-25</li><li>'previous_analysis' to " + | |||
"compare to previous analysis</li></ul>" + | |||
"Changing this property only take effect after subsequent project inspections.", | |||
project = false, | |||
global = true, | |||
defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_1, | |||
category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), | |||
@Property( | |||
key = "sonar.timemachine.period2", | |||
name = "Period 2", | |||
description = "See the property 'Period 1'", | |||
project = false, | |||
global = true, | |||
defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_2, | |||
category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), | |||
@Property( | |||
key = "sonar.timemachine.period3", | |||
name = "Period 3", | |||
description = "See the property 'Period 1'", | |||
project = false, | |||
global = true, | |||
defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_3, | |||
category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), | |||
@Property( | |||
key = "sonar.timemachine.period4", | |||
name = "Period 4", | |||
description = "Period used to compare measures and track new violations. This property is specific to the project. Values are : " + | |||
"<ul class='bullet'><li>Number of days before analysis, for example 5.</li><li>A custom date. Format is yyyy-MM-dd, " + | |||
"for example 2010-12-25</li><li>'previous_analysis' to compare to previous analysis</li><li>A version, for example 1.2</li></ul>" + | |||
"Changing this property only take effect after subsequent project inspection.", | |||
project = true, | |||
global = false, | |||
defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_4, | |||
category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), | |||
@Property( | |||
key = "sonar.timemachine.period5", | |||
name = "Period 5", | |||
description = "See the property 'Period 4'", | |||
project = true, | |||
global = false, | |||
defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_5, | |||
category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), | |||
@Property( | |||
key = CoreProperties.SERVER_BASE_URL, | |||
defaultValue = CoreProperties.SERVER_BASE_URL_DEFAULT_VALUE, | |||
name = "Server base URL", | |||
description = "HTTP URL of this Sonar server, such as <i>http://yourhost.yourdomain/sonar</i>. This value is used i.e. to create links in emails.", | |||
project = false, | |||
global = true, | |||
category = CoreProperties.CATEGORY_GENERAL), | |||
@Property( | |||
key = CoreProperties.CORE_COVERAGE_PLUGIN_PROPERTY, | |||
defaultValue = "cobertura", | |||
name = "Code coverage plugin", | |||
description = "Key of the code coverage plugin to use.", | |||
project = true, | |||
global = true, | |||
category = CoreProperties.CATEGORY_CODE_COVERAGE), | |||
@Property( | |||
key = CoreProperties.CORE_IMPORT_SOURCES_PROPERTY, | |||
defaultValue = "" + CoreProperties.CORE_IMPORT_SOURCES_DEFAULT_VALUE, | |||
name = "Import sources", | |||
description = "Set to false if sources should not be displayed, e.g. for security reasons.", | |||
project = true, | |||
module = true, | |||
global = true, | |||
category = CoreProperties.CATEGORY_SECURITY, | |||
type = PropertyType.BOOLEAN), | |||
@Property( | |||
key = CoreProperties.CORE_TENDENCY_DEPTH_PROPERTY, | |||
defaultValue = "" + CoreProperties.CORE_TENDENCY_DEPTH_DEFAULT_VALUE, | |||
name = "Tendency period", | |||
description = TendencyDecorator.PROP_DAYS_DESCRIPTION, | |||
project = false, | |||
global = true, | |||
category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS, | |||
type = PropertyType.INTEGER), | |||
@Property( | |||
key = CoreProperties.SKIP_TENDENCIES_PROPERTY, | |||
defaultValue = "" + CoreProperties.SKIP_TENDENCIES_DEFAULT_VALUE, | |||
name = "Skip tendencies", | |||
description = "Skip calculation of measure tendencies", | |||
project = true, | |||
module = false, | |||
global = true, | |||
category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS, | |||
type = PropertyType.BOOLEAN), | |||
@Property( | |||
key = CoreProperties.CORE_SKIPPED_MODULES_PROPERTY, | |||
name = "Exclude modules", | |||
description = "Maven artifact ids of modules to exclude (comma-separated).", | |||
project = true, | |||
global = false, | |||
category = CoreProperties.CATEGORY_GENERAL), | |||
@Property( | |||
key = CoreProperties.CORE_FORCE_AUTHENTICATION_PROPERTY, | |||
defaultValue = "" + CoreProperties.CORE_FORCE_AUTHENTICATION_DEFAULT_VALUE, | |||
name = "Force user authentication", | |||
description = "Forcing user authentication stops un-logged users to access Sonar.", | |||
project = false, | |||
global = true, | |||
category = CoreProperties.CATEGORY_SECURITY, | |||
type = PropertyType.BOOLEAN), | |||
@Property( | |||
key = CoreProperties.CORE_ALLOW_USERS_TO_SIGNUP_PROPERTY, | |||
defaultValue = "" + CoreProperties.CORE_ALLOW_USERS_TO_SIGNUP_DEAULT_VALUE, | |||
name = "Allow users to sign up online", | |||
description = "Users can sign up online.", | |||
project = false, | |||
global = true, | |||
category = CoreProperties.CATEGORY_SECURITY, | |||
type = PropertyType.BOOLEAN), | |||
@Property( | |||
key = CoreProperties.CORE_DEFAULT_GROUP, | |||
defaultValue = CoreProperties.CORE_DEFAULT_GROUP_DEFAULT_VALUE, | |||
name = "Default user group", | |||
description = "Any new users will automatically join this group.", | |||
project = false, | |||
global = true, | |||
category = CoreProperties.CATEGORY_SECURITY), | |||
@Property( | |||
key = CoreProperties.CORE_VIOLATION_LOCALE_PROPERTY, | |||
defaultValue = "en", | |||
name = "Locale used for violation messages", | |||
description = "Locale to be used when generating violation messages. It's up to each rule engine to support this global internationalization property", | |||
project = true, | |||
global = true, | |||
category = CoreProperties.CATEGORY_L10N), | |||
@Property( | |||
key = "sonar.timemachine.period1", | |||
name = "Period 1", | |||
description = "Period used to compare measures and track new violations. Values are : <ul class='bullet'><li>Number of days before " + | |||
"analysis, for example 5.</li><li>A custom date. Format is yyyy-MM-dd, for example 2010-12-25</li><li>'previous_analysis' to " + | |||
"compare to previous analysis</li></ul>" + | |||
"Changing this property only take effect after subsequent project inspections.", | |||
project = false, | |||
global = true, | |||
defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_1, | |||
category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), | |||
@Property( | |||
key = "sonar.timemachine.period2", | |||
name = "Period 2", | |||
description = "See the property 'Period 1'", | |||
project = false, | |||
global = true, | |||
defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_2, | |||
category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), | |||
@Property( | |||
key = "sonar.timemachine.period3", | |||
name = "Period 3", | |||
description = "See the property 'Period 1'", | |||
project = false, | |||
global = true, | |||
defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_3, | |||
category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), | |||
@Property( | |||
key = "sonar.timemachine.period4", | |||
name = "Period 4", | |||
description = "Period used to compare measures and track new violations. This property is specific to the project. Values are : " + | |||
"<ul class='bullet'><li>Number of days before analysis, for example 5.</li><li>A custom date. Format is yyyy-MM-dd, " + | |||
"for example 2010-12-25</li><li>'previous_analysis' to compare to previous analysis</li><li>A version, for example 1.2</li></ul>" + | |||
"Changing this property only take effect after subsequent project inspection.", | |||
project = true, | |||
global = false, | |||
defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_4, | |||
category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), | |||
@Property( | |||
key = "sonar.timemachine.period5", | |||
name = "Period 5", | |||
description = "See the property 'Period 4'", | |||
project = true, | |||
global = false, | |||
defaultValue = CoreProperties.TIMEMACHINE_DEFAULT_PERIOD_5, | |||
category = CoreProperties.CATEGORY_DIFFERENTIAL_VIEWS), | |||
// SERVER-SIDE TECHNICAL PROPERTIES | |||
// SERVER-SIDE TECHNICAL PROPERTIES | |||
@Property( | |||
key = "sonar.security.realm", | |||
name = "Security Realm", | |||
project = false, | |||
global = false | |||
), | |||
@Property( | |||
key = "sonar.security.savePassword", | |||
name = "Save external password", | |||
project = false, | |||
global = false | |||
), | |||
@Property( | |||
key = "sonar.authenticator.downcase", | |||
name = "Downcase login", | |||
description = "Downcase login during user authentication, typically for Active Directory", | |||
project = false, | |||
global = false, | |||
defaultValue = "false", | |||
type = Property.Type.BOOLEAN), | |||
@Property( | |||
key = CoreProperties.CORE_AUTHENTICATOR_CREATE_USERS, | |||
name = "Create user accounts", | |||
description = "Create accounts when authenticating users via an external system", | |||
project = false, | |||
global = false, | |||
defaultValue = "true", | |||
type = Property.Type.BOOLEAN), | |||
@Property( | |||
key = CoreProperties.CORE_AUTHENTICATOR_IGNORE_STARTUP_FAILURE, | |||
name = "Ignore failures during authenticator startup", | |||
defaultValue = "false", | |||
project = false, | |||
global = false, | |||
type = Property.Type.BOOLEAN) | |||
@Property( | |||
key = "sonar.security.realm", | |||
name = "Security Realm", | |||
project = false, | |||
global = false | |||
), | |||
@Property( | |||
key = "sonar.security.savePassword", | |||
name = "Save external password", | |||
project = false, | |||
global = false | |||
), | |||
@Property( | |||
key = "sonar.authenticator.downcase", | |||
name = "Downcase login", | |||
description = "Downcase login during user authentication, typically for Active Directory", | |||
project = false, | |||
global = false, | |||
defaultValue = "false", | |||
type = PropertyType.BOOLEAN), | |||
@Property( | |||
key = CoreProperties.CORE_AUTHENTICATOR_CREATE_USERS, | |||
name = "Create user accounts", | |||
description = "Create accounts when authenticating users via an external system", | |||
project = false, | |||
global = false, | |||
defaultValue = "true", | |||
type = PropertyType.BOOLEAN), | |||
@Property( | |||
key = CoreProperties.CORE_AUTHENTICATOR_IGNORE_STARTUP_FAILURE, | |||
name = "Ignore failures during authenticator startup", | |||
defaultValue = "false", | |||
project = false, | |||
global = false, | |||
type = PropertyType.BOOLEAN) | |||
}) | |||
public final class CorePlugin extends SonarPlugin { | |||
@@ -19,10 +19,8 @@ | |||
*/ | |||
package org.sonar.plugins.cpd; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.Properties; | |||
import org.sonar.api.Property; | |||
import org.sonar.api.SonarPlugin; | |||
import org.sonar.api.*; | |||
import org.sonar.api.PropertyType; | |||
import org.sonar.plugins.cpd.decorators.DuplicationDensityDecorator; | |||
import org.sonar.plugins.cpd.decorators.SumDuplicationsDecorator; | |||
import org.sonar.plugins.cpd.index.IndexFactory; | |||
@@ -43,7 +41,7 @@ import java.util.List; | |||
module = true, | |||
global = true, | |||
category = CoreProperties.CATEGORY_DUPLICATIONS, | |||
type = Property.Type.SINGLE_SELECT_LIST, | |||
type = PropertyType.SINGLE_SELECT_LIST, | |||
options = {"sonar", "pmd"}), | |||
@Property( | |||
key = CoreProperties.CPD_CROSS_RPOJECT, | |||
@@ -56,7 +54,7 @@ import java.util.List; | |||
module = true, | |||
global = true, | |||
category = CoreProperties.CATEGORY_DUPLICATIONS, | |||
type = Property.Type.BOOLEAN), | |||
type = PropertyType.BOOLEAN), | |||
@Property( | |||
key = CoreProperties.CPD_MINIMUM_TOKENS_PROPERTY, | |||
defaultValue = CoreProperties.CPD_MINIMUM_TOKENS_DEFAULT_VALUE + "", | |||
@@ -67,7 +65,7 @@ import java.util.List; | |||
module = true, | |||
global = true, | |||
category = CoreProperties.CATEGORY_DUPLICATIONS, | |||
type = Property.Type.INTEGER), | |||
type = PropertyType.INTEGER), | |||
@Property( | |||
key = CoreProperties.CPD_IGNORE_LITERALS_PROPERTY, | |||
defaultValue = CoreProperties.CPD_IGNORE_LITERALS_DEFAULT_VALUE + "", | |||
@@ -79,7 +77,7 @@ import java.util.List; | |||
module = true, | |||
global = true, | |||
category = CoreProperties.CATEGORY_DUPLICATIONS, | |||
type = Property.Type.BOOLEAN), | |||
type = PropertyType.BOOLEAN), | |||
@Property( | |||
key = CoreProperties.CPD_IGNORE_IDENTIFIERS_PROPERTY, | |||
defaultValue = CoreProperties.CPD_IGNORE_IDENTIFIERS_DEFAULT_VALUE + "", | |||
@@ -90,7 +88,7 @@ import java.util.List; | |||
module = true, | |||
global = true, | |||
category = CoreProperties.CATEGORY_DUPLICATIONS, | |||
type = Property.Type.BOOLEAN) | |||
type = PropertyType.BOOLEAN) | |||
}) | |||
public final class CpdPlugin extends SonarPlugin { | |||
@@ -21,6 +21,7 @@ package org.sonar.plugins.dbcleaner; | |||
import org.sonar.api.Properties; | |||
import org.sonar.api.Property; | |||
import org.sonar.api.PropertyType; | |||
import org.sonar.api.SonarPlugin; | |||
import org.sonar.plugins.dbcleaner.api.DbCleanerConstants; | |||
import org.sonar.plugins.dbcleaner.period.DefaultPeriodCleaner; | |||
@@ -35,20 +36,20 @@ import java.util.List; | |||
+ "the DbCleaner keeps the first one and fully delete the other ones.", | |||
global = true, | |||
project = true, | |||
type = Property.Type.INTEGER), | |||
type = PropertyType.INTEGER), | |||
@Property(key = DbCleanerConstants.WEEKS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_MONTH, defaultValue = "52", | |||
name = "Number of weeks before starting to keep only one snapshot by month", | |||
description = "After this number of weeks, if there are several snapshots during the same month, " | |||
+ "the DbCleaner keeps the first one and fully delete the other ones.", | |||
global = true, | |||
project = true, | |||
type = Property.Type.INTEGER), | |||
type = PropertyType.INTEGER), | |||
@Property(key = DbCleanerConstants.WEEKS_BEFORE_DELETING_ALL_SNAPSHOTS, defaultValue = "260", | |||
name = "Number of weeks before starting to delete all remaining snapshots", | |||
description = "After this number of weeks, all snapshots are fully deleted.", | |||
global = true, | |||
project = true, | |||
type = Property.Type.INTEGER) | |||
type = PropertyType.INTEGER) | |||
} | |||
) | |||
public final class DbCleanerPlugin extends SonarPlugin { |
@@ -23,6 +23,7 @@ import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.Properties; | |||
import org.sonar.api.Property; | |||
import org.sonar.api.PropertyType; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.resources.Scopes; | |||
import org.sonar.core.purge.PurgeDao; | |||
@@ -41,7 +42,7 @@ import org.sonar.plugins.dbcleaner.period.DefaultPeriodCleaner; | |||
global = true, | |||
project = true, | |||
module = false, | |||
type = Property.Type.BOOLEAN) | |||
type = PropertyType.BOOLEAN) | |||
}) | |||
public class DefaultPurgeTask implements PurgeTask { | |||
private static final Logger LOG = LoggerFactory.getLogger(DefaultPurgeTask.class); |
@@ -20,6 +20,7 @@ | |||
package org.sonar.plugins.findbugs; | |||
import org.sonar.api.*; | |||
import org.sonar.api.PropertyType; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
@@ -43,7 +44,7 @@ import java.util.List; | |||
project = true, | |||
module = true, | |||
global = true, | |||
type = Property.Type.INTEGER), | |||
type = PropertyType.INTEGER), | |||
@Property( | |||
key = FindbugsConstants.EXCLUDES_FILTERS_PROPERTY, | |||
name = "Excludes Filters", |
@@ -549,6 +549,12 @@ property.category.duplications=Duplications | |||
property.category.localization=Localization | |||
property.category.server_id=Server ID | |||
property.error.notBoolean=Valid options are "true" and "false" | |||
property.error.notInteger=Only digits are allowed | |||
property.error.notFloat=Not a floating point number | |||
property.error.notInOptions=Not a valid option | |||
#------------------------------------------------------------------------------ | |||
# |
@@ -19,10 +19,8 @@ | |||
*/ | |||
package org.sonar.plugins.squid; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.Properties; | |||
import org.sonar.api.Property; | |||
import org.sonar.api.SonarPlugin; | |||
import org.sonar.api.*; | |||
import org.sonar.api.PropertyType; | |||
import org.sonar.plugins.squid.decorators.*; | |||
import java.util.Arrays; | |||
@@ -37,7 +35,7 @@ import java.util.List; | |||
project = true, | |||
global = true, | |||
category = CoreProperties.CATEGORY_JAVA, | |||
type = Property.Type.BOOLEAN), | |||
type = PropertyType.BOOLEAN), | |||
@Property(key = SquidPluginProperties.FIELDS_TO_EXCLUDE_FROM_LCOM4_COMPUTATION, | |||
defaultValue = SquidPluginProperties.FIELDS_TO_EXCLUDE_FROM_LCOM4_COMPUTATION_DEFAULT_VALUE, | |||
name = "List of fields to exclude from LCOM4 computation", | |||
@@ -55,7 +53,7 @@ import java.util.List; | |||
project = true, | |||
global = true, | |||
category = CoreProperties.CATEGORY_JAVA, | |||
type = Property.Type.BOOLEAN) | |||
type = PropertyType.BOOLEAN) | |||
}) | |||
public final class SquidPlugin extends SonarPlugin { | |||
@@ -45,13 +45,6 @@ import java.lang.annotation.Target; | |||
@Target(ElementType.TYPE) | |||
public @interface Property { | |||
/** | |||
* @since 2.15 | |||
*/ | |||
public static enum Type { | |||
STRING, TEXT, PASSWORD, BOOLEAN, INTEGER, FLOAT, SINGLE_SELECT_LIST | |||
} | |||
/** | |||
* Unique key within all plugins. It's recommended to prefix the key by 'sonar.' and the plugin name. Examples : | |||
* 'sonar.cobertura.reportPath' and 'sonar.cpd.minimumTokens'. | |||
@@ -87,7 +80,7 @@ public @interface Property { | |||
/** | |||
* @since 2.15 | |||
*/ | |||
Type type() default Type.STRING; | |||
PropertyType type() default PropertyType.STRING; | |||
/** | |||
* Options for *_LIST types |
@@ -0,0 +1,24 @@ | |||
/* | |||
* Sonar, open source software quality management tool. | |||
* Copyright (C) 2008-2012 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* Sonar 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. | |||
* | |||
* Sonar 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 Sonar; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||
*/ | |||
package org.sonar.api; | |||
public enum PropertyType { | |||
STRING, TEXT, PASSWORD, BOOLEAN, INTEGER, FLOAT, SINGLE_SELECT_LIST | |||
} |
@@ -27,6 +27,7 @@ import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.CoreProperties; | |||
import javax.annotation.Nullable; | |||
import javax.crypto.KeyGenerator; | |||
import javax.crypto.SecretKey; | |||
import javax.crypto.spec.SecretKeySpec; | |||
@@ -92,7 +93,7 @@ final class AesCipher extends Cipher { | |||
} | |||
@VisibleForTesting | |||
Key loadSecretFileFromFile(String path) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, InvalidKeyException { | |||
Key loadSecretFileFromFile(@Nullable String path) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, InvalidKeyException { | |||
if (StringUtils.isBlank(path)) { | |||
throw new IllegalStateException("Secret key not found. Please set the property " + CoreProperties.ENCRYPTION_SECRET_KEY_FILE); | |||
} |
@@ -0,0 +1,158 @@ | |||
/* | |||
* Sonar, open source software quality management tool. | |||
* Copyright (C) 2008-2012 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* Sonar 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. | |||
* | |||
* Sonar 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 Sonar; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||
*/ | |||
package org.sonar.api.config; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import org.apache.commons.lang.ArrayUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.apache.commons.lang.math.NumberUtils; | |||
import org.sonar.api.Property; | |||
import org.sonar.api.PropertyType; | |||
import javax.annotation.Nullable; | |||
/** | |||
* @since 2.15 | |||
*/ | |||
public final class PropertyDefinition { | |||
public static final class Result { | |||
private static final Result SUCCESS = new Result(null); | |||
private String errorKey = null; | |||
private static Result newError(String key) { | |||
return new Result(key); | |||
} | |||
private Result(String errorKey) { | |||
this.errorKey = errorKey; | |||
} | |||
public boolean isValid() { | |||
return StringUtils.isBlank(errorKey); | |||
} | |||
public @Nullable String getErrorKey() { | |||
return errorKey; | |||
} | |||
} | |||
private String key; | |||
private String defaultValue; | |||
private String name; | |||
private PropertyType type = PropertyType.STRING; | |||
private String[] options; | |||
private String description; | |||
private String category; | |||
private boolean onProject = false; | |||
private boolean onModule = false; | |||
private boolean isGlobal = true; | |||
private PropertyDefinition(Property annotation) { | |||
this.key = annotation.key(); | |||
this.name = annotation.name(); | |||
this.defaultValue = annotation.defaultValue(); | |||
this.description = annotation.description(); | |||
this.isGlobal = annotation.global(); | |||
this.onProject = annotation.project(); | |||
this.onModule = annotation.module(); | |||
this.category = annotation.category(); | |||
this.type = annotation.type(); | |||
this.options = annotation.options(); | |||
} | |||
@VisibleForTesting | |||
PropertyDefinition(PropertyType type, String[] options) { | |||
this.type = type; | |||
this.options = options; | |||
} | |||
public static PropertyDefinition create(Property annotation) { | |||
return new PropertyDefinition(annotation); | |||
} | |||
public Result validate(@Nullable String value) { | |||
// TODO REFACTORING REQUIRED HERE | |||
Result result = Result.SUCCESS; | |||
if (StringUtils.isNotBlank(value)) { | |||
if (type == PropertyType.BOOLEAN) { | |||
if (!StringUtils.equalsIgnoreCase(value, "true") && !StringUtils.equalsIgnoreCase(value, "false")) { | |||
result = Result.newError("notBoolean"); | |||
} | |||
} else if (type == PropertyType.INTEGER) { | |||
if (!NumberUtils.isDigits(value)) { | |||
result = Result.newError("notInteger"); | |||
} | |||
} else if (type == PropertyType.FLOAT) { | |||
try { | |||
Double.parseDouble(value); | |||
} catch (NumberFormatException e) { | |||
result = Result.newError("notFloat"); | |||
} | |||
} else if (type == PropertyType.SINGLE_SELECT_LIST) { | |||
if (!ArrayUtils.contains(options, value)) { | |||
result = Result.newError("notInOptions"); | |||
} | |||
} | |||
} | |||
return result; | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
public String getDefaultValue() { | |||
return defaultValue; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
public PropertyType getType() { | |||
return type; | |||
} | |||
public String[] getOptions() { | |||
return options; | |||
} | |||
public String getDescription() { | |||
return description; | |||
} | |||
public String getCategory() { | |||
return category; | |||
} | |||
public boolean isOnProject() { | |||
return onProject; | |||
} | |||
public boolean isOnModule() { | |||
return onModule; | |||
} | |||
public boolean isGlobal() { | |||
return isGlobal; | |||
} | |||
} |
@@ -38,7 +38,7 @@ import java.util.Map; | |||
*/ | |||
public final class PropertyDefinitions implements BatchComponent, ServerComponent { | |||
private Map<String, Property> properties = Maps.newHashMap(); | |||
private Map<String, PropertyDefinition> definitions = Maps.newHashMap(); | |||
private Map<String, String> categories = Maps.newHashMap(); | |||
public PropertyDefinitions(Object... components) { | |||
@@ -76,30 +76,31 @@ public final class PropertyDefinitions implements BatchComponent, ServerComponen | |||
return this; | |||
} | |||
PropertyDefinitions addProperty(Property property) { | |||
return addProperty(property, ""); | |||
private PropertyDefinitions addProperty(Property property, String defaultCategory) { | |||
PropertyDefinition definition = PropertyDefinition.create(property); | |||
return add(definition, defaultCategory); | |||
} | |||
PropertyDefinitions addProperty(Property property, String defaultCategory) { | |||
if (!properties.containsKey(property.key())) { | |||
properties.put(property.key(), property); | |||
categories.put(property.key(), StringUtils.defaultIfBlank(property.category(), defaultCategory)); | |||
private PropertyDefinitions add(PropertyDefinition definition, String defaultCategory) { | |||
if (!definitions.containsKey(definition.getKey())) { | |||
definitions.put(definition.getKey(), definition); | |||
categories.put(definition.getKey(), StringUtils.defaultIfBlank(definition.getCategory(), defaultCategory)); | |||
} | |||
return this; | |||
} | |||
public Property getProperty(String key) { | |||
return properties.get(key); | |||
public PropertyDefinition get(String key) { | |||
return definitions.get(key); | |||
} | |||
public Collection<Property> getProperties() { | |||
return properties.values(); | |||
public Collection<PropertyDefinition> getAll() { | |||
return definitions.values(); | |||
} | |||
public String getDefaultValue(String key) { | |||
Property prop = getProperty(key); | |||
if (prop != null) { | |||
return StringUtils.defaultIfEmpty(prop.defaultValue(), null); | |||
PropertyDefinition def = get(key); | |||
if (def != null) { | |||
return StringUtils.defaultIfEmpty(def.getDefaultValue(), null); | |||
} | |||
return null; | |||
} |
@@ -0,0 +1,23 @@ | |||
/* | |||
* Sonar, open source software quality management tool. | |||
* Copyright (C) 2008-2012 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* Sonar 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. | |||
* | |||
* Sonar 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 Sonar; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||
*/ | |||
@ParametersAreNonnullByDefault | |||
package org.sonar.api.config; | |||
import javax.annotation.ParametersAreNonnullByDefault; |
@@ -22,15 +22,8 @@ package org.sonar.api.rules; | |||
import org.apache.commons.lang.builder.EqualsBuilder; | |||
import org.apache.commons.lang.builder.HashCodeBuilder; | |||
import org.apache.commons.lang.builder.ToStringBuilder; | |||
import org.hibernate.annotations.Cache; | |||
import org.hibernate.annotations.CacheConcurrencyStrategy; | |||
import org.hibernate.annotations.Immutable; | |||
import org.sonar.api.database.BaseIdentifiable; | |||
import javax.persistence.Column; | |||
import javax.persistence.Entity; | |||
import javax.persistence.Table; | |||
/** | |||
* @deprecated since 2.5 See http://jira.codehaus.org/browse/SONAR-2007 | |||
*/ |
@@ -0,0 +1,153 @@ | |||
/* | |||
* Sonar, open source software quality management tool. | |||
* Copyright (C) 2008-2012 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* Sonar 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. | |||
* | |||
* Sonar 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 Sonar; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||
*/ | |||
package org.sonar.api.config; | |||
import org.hamcrest.core.Is; | |||
import org.junit.Test; | |||
import org.sonar.api.Properties; | |||
import org.sonar.api.Property; | |||
import org.sonar.api.PropertyType; | |||
import org.sonar.api.utils.AnnotationUtils; | |||
import java.util.Arrays; | |||
import static org.hamcrest.core.Is.is; | |||
import static org.junit.Assert.assertThat; | |||
import static org.junit.matchers.JUnitMatchers.hasItems; | |||
public class PropertyDefinitionTest { | |||
@Test | |||
public void createFromAnnotation() { | |||
Properties props = AnnotationUtils.getClassAnnotation(Init.class, Properties.class); | |||
Property prop = props.value()[0]; | |||
PropertyDefinition def = PropertyDefinition.create(prop); | |||
assertThat(def.getKey(), Is.is("hello")); | |||
assertThat(def.getName(), Is.is("Hello")); | |||
assertThat(def.getDefaultValue(), Is.is("world")); | |||
assertThat(def.getCategory(), Is.is("categ")); | |||
assertThat(def.getOptions().length, Is.is(2)); | |||
assertThat(Arrays.asList(def.getOptions()), hasItems("de", "en")); | |||
assertThat(def.getDescription(), Is.is("desc")); | |||
assertThat(def.getType(), Is.is(PropertyType.FLOAT)); | |||
assertThat(def.isGlobal(), Is.is(false)); | |||
assertThat(def.isOnProject(), Is.is(true)); | |||
assertThat(def.isOnModule(), Is.is(true)); | |||
} | |||
@Properties({ | |||
@Property(key = "hello", name = "Hello", defaultValue = "world", description = "desc", | |||
options = {"de", "en"}, category = "categ", type = PropertyType.FLOAT, global = false, project = true, module = true) | |||
}) | |||
static class Init { | |||
} | |||
@Test | |||
public void createFromAnnotation_default_values() { | |||
Properties props = AnnotationUtils.getClassAnnotation(DefaultValues.class, Properties.class); | |||
Property prop = props.value()[0]; | |||
PropertyDefinition def = PropertyDefinition.create(prop); | |||
assertThat(def.getKey(), Is.is("hello")); | |||
assertThat(def.getName(), Is.is("Hello")); | |||
assertThat(def.getDefaultValue(), Is.is("")); | |||
assertThat(def.getCategory(), Is.is("")); | |||
assertThat(def.getOptions().length, Is.is(0)); | |||
assertThat(def.getDescription(), Is.is("")); | |||
assertThat(def.getType(), Is.is(PropertyType.STRING)); | |||
assertThat(def.isGlobal(), Is.is(true)); | |||
assertThat(def.isOnProject(), Is.is(false)); | |||
assertThat(def.isOnModule(), Is.is(false)); | |||
} | |||
@Properties({ | |||
@Property(key = "hello", name = "Hello") | |||
}) | |||
static class DefaultValues { | |||
} | |||
@Test | |||
public void validate_string() { | |||
PropertyDefinition def = new PropertyDefinition(PropertyType.STRING, new String[0]); | |||
assertThat(def.validate(null).isValid(), is(true)); | |||
assertThat(def.validate("").isValid(), is(true)); | |||
assertThat(def.validate(" ").isValid(), is(true)); | |||
assertThat(def.validate("foo").isValid(), is(true)); | |||
} | |||
@Test | |||
public void validate_boolean() { | |||
PropertyDefinition def = new PropertyDefinition(PropertyType.BOOLEAN, new String[0]); | |||
assertThat(def.validate(null).isValid(), is(true)); | |||
assertThat(def.validate("").isValid(), is(true)); | |||
assertThat(def.validate(" ").isValid(), is(true)); | |||
assertThat(def.validate("true").isValid(), is(true)); | |||
assertThat(def.validate("false").isValid(), is(true)); | |||
assertThat(def.validate("foo").isValid(), is(false)); | |||
assertThat(def.validate("foo").getErrorKey(), is("notBoolean")); | |||
} | |||
@Test | |||
public void validate_integer() { | |||
PropertyDefinition def = new PropertyDefinition(PropertyType.INTEGER, new String[0]); | |||
assertThat(def.validate(null).isValid(), is(true)); | |||
assertThat(def.validate("").isValid(), is(true)); | |||
assertThat(def.validate(" ").isValid(), is(true)); | |||
assertThat(def.validate("123456").isValid(), is(true)); | |||
assertThat(def.validate("foo").isValid(), is(false)); | |||
assertThat(def.validate("foo").getErrorKey(), is("notInteger")); | |||
} | |||
@Test | |||
public void validate_float() { | |||
PropertyDefinition def = new PropertyDefinition(PropertyType.FLOAT, new String[0]); | |||
assertThat(def.validate(null).isValid(), is(true)); | |||
assertThat(def.validate("").isValid(), is(true)); | |||
assertThat(def.validate(" ").isValid(), is(true)); | |||
assertThat(def.validate("123456").isValid(), is(true)); | |||
assertThat(def.validate("3.14").isValid(), is(true)); | |||
assertThat(def.validate("foo").isValid(), is(false)); | |||
assertThat(def.validate("foo").getErrorKey(), is("notFloat")); | |||
} | |||
@Test | |||
public void validate_single_select_list() { | |||
PropertyDefinition def = new PropertyDefinition(PropertyType.SINGLE_SELECT_LIST, new String[]{"de", "en"}); | |||
assertThat(def.validate(null).isValid(), is(true)); | |||
assertThat(def.validate("").isValid(), is(true)); | |||
assertThat(def.validate(" ").isValid(), is(true)); | |||
assertThat(def.validate("de").isValid(), is(true)); | |||
assertThat(def.validate("en").isValid(), is(true)); | |||
assertThat(def.validate("fr").isValid(), is(false)); | |||
assertThat(def.validate("fr").getErrorKey(), is("notInOptions")); | |||
} | |||
} |
@@ -43,16 +43,16 @@ public class PropertyDefinitionsTest { | |||
assertProperties(def); | |||
} | |||
private void assertProperties(PropertyDefinitions def) { | |||
assertThat(def.getProperty("foo").name(), is("Foo")); | |||
assertThat(def.getProperty("one").name(), is("One")); | |||
assertThat(def.getProperty("two").name(), is("Two")); | |||
assertThat(def.getProperty("unknown"), nullValue()); | |||
private void assertProperties(PropertyDefinitions definitions) { | |||
assertThat(definitions.get("foo").getName(), is("Foo")); | |||
assertThat(definitions.get("one").getName(), is("One")); | |||
assertThat(definitions.get("two").getName(), is("Two")); | |||
assertThat(definitions.get("unknown"), nullValue()); | |||
assertThat(def.getDefaultValue("foo"), nullValue()); | |||
assertThat(def.getDefaultValue("two"), is("2")); | |||
assertThat(definitions.getDefaultValue("foo"), nullValue()); | |||
assertThat(definitions.getDefaultValue("two"), is("2")); | |||
assertThat(def.getProperties().size(), is(3)); | |||
assertThat(definitions.getAll().size(), is(3)); | |||
} | |||
@Property(key = "foo", name = "Foo") |
@@ -23,34 +23,32 @@ import com.google.common.collect.ImmutableMap; | |||
import org.hamcrest.CoreMatchers; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.sonar.api.Properties; | |||
import org.sonar.api.Property; | |||
import static org.hamcrest.CoreMatchers.is; | |||
import static org.hamcrest.CoreMatchers.nullValue; | |||
import static org.junit.Assert.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
public class SettingsTest { | |||
private PropertyDefinitions definitions; | |||
@Properties({ | |||
@Property(key = "hello", name = "Hello", defaultValue = "world"), | |||
@Property(key = "date", name = "Date", defaultValue = "2010-05-18"), | |||
@Property(key = "boolean", name = "Boolean", defaultValue = "true"), | |||
@Property(key = "falseboolean", name = "False Boolean", defaultValue = "false"), | |||
@Property(key = "integer", name = "Integer", defaultValue = "12345"), | |||
@Property(key = "array", name = "Array", defaultValue = "one,two,three") | |||
}) | |||
static class Init { | |||
} | |||
@Before | |||
public void initDefinitions() { | |||
definitions = new PropertyDefinitions(); | |||
definitions.addProperty(newProperty("hello", "world")); | |||
definitions.addProperty(newProperty("date", "2010-05-18")); | |||
definitions.addProperty(newProperty("boolean", "true")); | |||
definitions.addProperty(newProperty("falseboolean", "false")); | |||
definitions.addProperty(newProperty("integer", "12345")); | |||
definitions.addProperty(newProperty("array", "one,two,three")); | |||
} | |||
private Property newProperty(String key, String defaultValue) { | |||
Property prop = mock(Property.class); | |||
when(prop.key()).thenReturn(key); | |||
when(prop.defaultValue()).thenReturn(defaultValue); | |||
return prop; | |||
definitions.addComponent(Init.class); | |||
} | |||
@Test |
@@ -102,8 +102,8 @@ public class ComponentContainerTest { | |||
container.addSingleton(ComponentWithProperty.class); | |||
PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class); | |||
assertThat(propertyDefinitions.getProperty("foo"), notNullValue()); | |||
assertThat(propertyDefinitions.getProperty("foo").defaultValue(), is("bar")); | |||
assertThat(propertyDefinitions.get("foo"), notNullValue()); | |||
assertThat(propertyDefinitions.get("foo").getDefaultValue(), is("bar")); | |||
} | |||
@Test | |||
@@ -113,7 +113,7 @@ public class ComponentContainerTest { | |||
container.declareExtension(plugin, ComponentWithProperty.class); | |||
PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class); | |||
assertThat(propertyDefinitions.getProperty("foo"), notNullValue()); | |||
assertThat(propertyDefinitions.get("foo"), notNullValue()); | |||
assertThat(container.getComponentByType(ComponentWithProperty.class), nullValue()); | |||
} | |||
@@ -124,7 +124,7 @@ public class ComponentContainerTest { | |||
container.addExtension(plugin, ComponentWithProperty.class); | |||
PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class); | |||
assertThat(propertyDefinitions.getProperty("foo"), notNullValue()); | |||
assertThat(propertyDefinitions.get("foo"), notNullValue()); | |||
assertThat(container.getComponentByType(ComponentWithProperty.class), notNullValue()); | |||
} | |||
@@ -23,6 +23,7 @@ import org.apache.commons.io.IOUtils; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.Properties; | |||
import org.sonar.api.Property; | |||
import org.sonar.api.PropertyType; | |||
import org.sonar.api.ServerComponent; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.utils.HttpDownloader; | |||
@@ -49,7 +50,7 @@ import java.util.Date; | |||
project = false, | |||
global = false, // hidden from UI | |||
category = "Update Center", | |||
type = Property.Type.BOOLEAN), | |||
type = PropertyType.BOOLEAN), | |||
@Property( | |||
key = UpdateCenterClient.URL_PROPERTY, | |||
defaultValue = "http://update.sonarsource.org/update-center.properties", |
@@ -126,13 +126,13 @@ class ProjectController < ApplicationController | |||
end | |||
@category=params[:category] ||= 'general' | |||
@properties_per_category={} | |||
@definitions_per_category={} | |||
definitions = java_facade.getPropertyDefinitions() | |||
properties = definitions.getProperties().select { |property| (@project.module? && property.module()) || (@project.project? && property.project()) } | |||
properties = definitions.getAll().select { |property| (@project.module? && property.isOnModule()) || (@project.project? && property.isOnProject()) } | |||
properties.each do |property| | |||
category = definitions.getCategory(property.key()) | |||
@properties_per_category[category]||=[] | |||
@properties_per_category[category]<<property | |||
category = definitions.getCategory(property.getKey()) | |||
@definitions_per_category[category]||=[] | |||
@definitions_per_category[category]<<property | |||
end | |||
end | |||
@@ -20,7 +20,7 @@ | |||
class SettingsController < ApplicationController | |||
SECTION=Navigation::SECTION_CONFIGURATION | |||
SPECIAL_CATEGORIES=['email', 'encryption', 'server_id'] | |||
verify :method => :post, :only => ['update'], :redirect_to => {:action => :index} | |||
@@ -32,39 +32,39 @@ class SettingsController < ApplicationController | |||
end | |||
def update | |||
project=nil | |||
@project=nil | |||
if params[:resource_id] | |||
project=Project.by_key(params[:resource_id]) | |||
access_denied unless (project && is_admin?(project)) | |||
@project=Project.by_key(params[:resource_id]) | |||
access_denied unless (@project && is_admin?(@project)) | |||
else | |||
access_denied unless is_admin? | |||
end | |||
load_properties(project) | |||
load_properties(@project) | |||
@persisted_properties_per_key={} | |||
if @category && @definitions_per_category[@category] | |||
@definitions_per_category[@category].each do |property| | |||
value=params[property.getKey()] | |||
if @category && @properties_per_category[@category] | |||
@properties_per_category[@category].each do |property| | |||
value=params[property.key()] | |||
persisted_property = Property.find(:first, :conditions => {:prop_key=> property.key(), :resource_id => (project ? project.id : nil), :user_id => nil}) | |||
persisted_property = Property.find(:first, :conditions => {:prop_key=> property.key(), :resource_id => (@project ? @project.id : nil), :user_id => nil}) | |||
if persisted_property | |||
if value.empty? | |||
Property.delete_all('prop_key' => property.key(), 'resource_id' => (project ? project.id : nil), 'user_id' => nil) | |||
Property.delete_all('prop_key' => property.key(), 'resource_id' => (@project ? @project.id : nil), 'user_id' => nil) | |||
elsif persisted_property.text_value != value.to_s | |||
persisted_property.text_value = value.to_s | |||
persisted_property.save! | |||
persisted_property.save | |||
@persisted_properties_per_key[persisted_property.key]=persisted_property | |||
end | |||
elsif !value.blank? | |||
Property.create(:prop_key => property.key(), :text_value => value.to_s, :resource_id => (project ? project.id : nil)) | |||
persisted_property=Property.create(:prop_key => property.key(), :text_value => value.to_s, :resource_id => (@project ? @project.id : nil)) | |||
@persisted_properties_per_key[persisted_property.key]=persisted_property | |||
end | |||
end | |||
java_facade.reloadConfiguration() | |||
flash[:notice] = 'Parameters updated' | |||
end | |||
if project | |||
redirect_to :controller => 'project', :action => 'settings', :id => project.id, :category => @category | |||
else | |||
redirect_to :controller => 'settings', :action => 'index', :category => @category | |||
params[:layout]='false' | |||
render :partial => 'settings/properties' | |||
end | |||
end | |||
@@ -72,18 +72,18 @@ class SettingsController < ApplicationController | |||
def load_properties(project) | |||
@category=params[:category] | |||
@properties_per_category={} | |||
@definitions_per_category={} | |||
definitions = java_facade.getPropertyDefinitions() | |||
definitions.getProperties().select {|property| | |||
(project.nil? && property.global) || (project && project.module? && property.module()) || (project && project.project? && property.project()) | |||
}.each do |property| | |||
category = definitions.getCategory(property.key()) | |||
@properties_per_category[category]||=[] | |||
@properties_per_category[category]<<property | |||
definitions.getAll().select { |property_definition| | |||
(project.nil? && property_definition.isGlobal()) || (project && project.module? && property_definition.isOnModule()) || (project && project.project? && property_definition.isOnProject()) | |||
}.each do |property_definition| | |||
category = definitions.getCategory(property_definition.getKey()) | |||
@definitions_per_category[category]||=[] | |||
@definitions_per_category[category]<<property_definition | |||
end | |||
SPECIAL_CATEGORIES.each do |category| | |||
@properties_per_category[category]=[] | |||
@definitions_per_category[category]=[] | |||
end | |||
end | |||
end |
@@ -18,6 +18,7 @@ | |||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||
# | |||
class Property < ActiveRecord::Base | |||
validates_presence_of :prop_key | |||
def key | |||
prop_key | |||
@@ -87,8 +88,22 @@ class Property < ActiveRecord::Base | |||
xml | |||
end | |||
def java_definition | |||
@java_definition ||= | |||
begin | |||
Java::OrgSonarServerUi::JRubyFacade.getInstance().getPropertyDefinitions().get(key) | |||
end | |||
end | |||
private | |||
def validate | |||
if java_definition | |||
validation_result=java_definition.validate(text_value) | |||
errors.add_to_base(validation_result.getErrorKey()) unless validation_result.isValid() | |||
end | |||
end | |||
def self.reload_java_configuration | |||
Java::OrgSonarServerUi::JRubyFacade.getInstance().reloadConfiguration() | |||
end |
@@ -3,7 +3,7 @@ | |||
<h1 class="marginbottom10">Settings</h1> | |||
<div class="yui-g widget" id="widget_plugins"> | |||
<%= render :partial => 'settings/plugins', :locals => {:project=>@project} %> | |||
<%= render :partial => 'settings/settings', :locals => {:project=>@project} %> | |||
</div> | |||
</div> |
@@ -1,128 +0,0 @@ | |||
<style type="text/css"> | |||
#plugins .plugin { | |||
padding: 5px; | |||
border: 1px solid #ddd; | |||
background-color: #fff; | |||
} | |||
#plugins .plugin h2 { | |||
margin-left: 10px; | |||
font-size: 122%; | |||
color: #333; | |||
} | |||
#plugins .plugin h3 { | |||
margin-left: 5px; | |||
} | |||
#plugins .plugin p { | |||
padding: 5px 5px; | |||
} | |||
#plugins .plugin img { | |||
padding: 5px 0 0 5px; | |||
} | |||
</style> | |||
<script type="text/javascript"> | |||
function enlargeTextInput(propertyKey) { | |||
var eltId = 'input_' + propertyKey; | |||
var textValue = $F(eltId); | |||
var textArea = '<textarea class="width100" id="' + propertyKey + '" name="' + propertyKey + '" rows="10" id="input_' + propertyKey + '">' + textValue + '</textarea>'; | |||
$(eltId).parentNode.replace(textArea); | |||
} | |||
</script> | |||
<div id="plugins"> | |||
<table width="100%"> | |||
<tr> | |||
<td width="1%" nowrap class="column first"> | |||
<table class="data selector"> | |||
<thead> | |||
<tr> | |||
<th> | |||
<span>Category</span> | |||
</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<% | |||
@properties_per_category.keys.sort_by { |category| message("property.category.#{category}", :default => category).upcase }.each do |category| | |||
if !@properties_per_category[category].empty? || SettingsController::SPECIAL_CATEGORIES.include?(category) | |||
%> | |||
<tr class="select <%= cycle('even', 'odd', :name => 'category') -%> <%= 'selected' if @category==category -%>" id="select_<%= category -%>"> | |||
<td><%= link_to message("property.category.#{category}", :default => category), :overwrite_params => {:category => category} -%></td> | |||
</tr> | |||
<% end | |||
end | |||
%> | |||
</tbody> | |||
</table> | |||
<br/> | |||
</td> | |||
<td class="column"> | |||
<% if @category && @properties_per_category[@category] | |||
category_name = message("property.category.#{@category}", :default => @category) | |||
if SettingsController::SPECIAL_CATEGORIES.include?(@category) | |||
%> | |||
<%= render :partial => 'special', :locals => {:url => url_for(:controller => "#{@category}_configuration")} -%> | |||
<% | |||
elsif !@properties_per_category[@category].empty? | |||
%> | |||
<% form_tag :controller => :settings, :action => :update do %> | |||
<%= hidden_field_tag('category', @category) -%> | |||
<% if @project %> | |||
<input type="hidden" name="resource_id" value="<%= @project.id -%>"/> | |||
<% end %> | |||
<table class="data marginbottom10"> | |||
<thead> | |||
<tr> | |||
<th> | |||
<span><%= h(category_name) -%></span> | |||
</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<% | |||
if @properties_per_category[@category] | |||
@properties_per_category[@category].each do |property| | |||
value = Property.value(property.key(), (@project ? @project.id : nil), '') | |||
# for backward-compatibility with properties that do not define the type TEXT | |||
property_type = value.include?("\n") ? 'TEXT' : property.type | |||
%> | |||
<tr class="<%= cycle('even', 'odd', :name => 'properties') -%>"> | |||
<td style="padding: 10px"> | |||
<h3> | |||
<%= message("property.#{property.key()}.name", :default => property.name()) -%> | |||
<br/><span class="note"><%= property.key() -%></span> | |||
</h3> | |||
<% | |||
desc=message("property.#{property.key()}.description", :default => property.description()) | |||
if desc.present? %> | |||
<p class="marginbottom10"><%= desc -%></p> | |||
<% end %> | |||
<div><%= render :partial => "settings/type_#{property_type}", :locals => {:property => property, :value => value} -%></div> | |||
<p> | |||
<% | |||
default_prop_value = (@project ? Property.value(property.key(), nil, property.defaultValue()) : property.defaultValue()) | |||
unless default_prop_value.blank? %> | |||
<span class="note">Default : <%= h default_prop_value -%></span> | |||
<% end %> | |||
</p> | |||
</td> | |||
</tr> | |||
<% end | |||
end | |||
%> | |||
</tbody> | |||
</table> | |||
<% save_message=message('settings.save_category', :params => [category_name]) %> | |||
<%= submit_tag(save_message, :disable_with => save_message, :id => 'save') -%> | |||
<% end %> | |||
<% end | |||
end | |||
%> | |||
</td> | |||
</tr> | |||
</table> | |||
</div> |
@@ -0,0 +1,85 @@ | |||
<% if @category && @definitions_per_category[@category] | |||
category_name = message("property.category.#{@category}", :default => @category) | |||
if SettingsController::SPECIAL_CATEGORIES.include?(@category) | |||
%> | |||
<%= render :partial => 'special', :locals => {:url => url_for(:controller => "#{@category}_configuration")} -%> | |||
<% | |||
elsif !@definitions_per_category[@category].empty? | |||
%> | |||
<% form_remote_tag :url => {:controller => 'settings', :action => 'update', :category => @category, :resource_id => @project ? @project.id : nil}, | |||
:method => :post, | |||
:before => "$('submit_settings').hide();$('loading_settings').show()", | |||
:update => 'properties' do -%> | |||
<table class="data marginbottom10"> | |||
<thead> | |||
<tr> | |||
<th> | |||
<span><%= h(category_name) -%></span> | |||
</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<% | |||
if @definitions_per_category[@category] | |||
@definitions_per_category[@category].each do |property| | |||
value = nil | |||
# set when form has been submitted but some errors have been raised | |||
if @persisted_properties_per_key | |||
p = @persisted_properties_per_key[property.key] | |||
if p | |||
value = p.text_value | |||
end | |||
end | |||
# if fresh form or no error, get the current value | |||
value = Property.value(property.getKey(), (@project ? @project.id : nil), '') unless value | |||
# for backward-compatibility with properties that do not define the type TEXT | |||
property_type = value.include?("\n") ? 'TEXT' : property.getType() | |||
%> | |||
<tr class="<%= cycle('even', 'odd', :name => 'properties') -%>"> | |||
<td style="padding: 10px" id="foo_<%= property.getKey() -%>"> | |||
<h3> | |||
<%= message("property.#{property.key()}.name", :default => property.name()) -%> | |||
<br/><span class="note"><%= property.getKey() -%></span> | |||
</h3> | |||
<% | |||
desc=message("property.#{property.key()}.description", :default => property.description()) | |||
if desc.present? %> | |||
<p class="marginbottom10"><%= desc -%></p> | |||
<% end %> | |||
<div><%= render :partial => "settings/type_#{property_type}", :locals => {:property => property, :value => value} -%></div> | |||
<% | |||
if p | |||
p.errors.each_full do |error| | |||
%> | |||
<div class="error"><%= message("property.error.#{error}") -%></div> | |||
<% | |||
end | |||
end | |||
%> | |||
<p> | |||
<% | |||
default_prop_value = (@project ? Property.value(property.key(), nil, property.defaultValue()) : property.defaultValue()) | |||
unless default_prop_value.blank? %> | |||
<span class="note">Default : <%= h default_prop_value -%></span> | |||
<% end %> | |||
</p> | |||
</td> | |||
</tr> | |||
<% end | |||
end | |||
%> | |||
</tbody> | |||
</table> | |||
<div> | |||
<%= submit_tag(message('settings.save_category', :params => [category_name]), :id => 'submit_settings') -%> | |||
<img src="<%= ApplicationController.root_context -%>/images/loading.gif" id="loading_settings" style="display:none"> | |||
</div> | |||
<% end %> | |||
<% end | |||
end | |||
%> |
@@ -0,0 +1,69 @@ | |||
<style type="text/css"> | |||
#plugins .plugin { | |||
padding: 5px; | |||
border: 1px solid #ddd; | |||
background-color: #fff; | |||
} | |||
#plugins .plugin h2 { | |||
margin-left: 10px; | |||
font-size: 122%; | |||
color: #333; | |||
} | |||
#plugins .plugin h3 { | |||
margin-left: 5px; | |||
} | |||
#plugins .plugin p { | |||
padding: 5px 5px; | |||
} | |||
#plugins .plugin img { | |||
padding: 5px 0 0 5px; | |||
} | |||
</style> | |||
<script type="text/javascript"> | |||
function enlargeTextInput(propertyKey) { | |||
var eltId = 'input_' + propertyKey; | |||
var textValue = $F(eltId); | |||
var textArea = '<textarea class="width100" id="' + propertyKey + '" name="' + propertyKey + '" rows="10" id="input_' + propertyKey + '">' + textValue + '</textarea>'; | |||
$(eltId).parentNode.replace(textArea); | |||
} | |||
</script> | |||
<div id="plugins"> | |||
<table width="100%"> | |||
<tr> | |||
<td width="1%" nowrap class="column first"> | |||
<table class="data selector"> | |||
<thead> | |||
<tr> | |||
<th> | |||
<span>Category</span> | |||
</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<% | |||
@definitions_per_category.keys.sort_by { |category| message("property.category.#{category}", :default => category).upcase }.each do |category| | |||
if !@definitions_per_category[category].empty? || SettingsController::SPECIAL_CATEGORIES.include?(category) | |||
%> | |||
<tr class="select <%= cycle('even', 'odd', :name => 'category') -%> <%= 'selected' if @category==category -%>" id="select_<%= category -%>"> | |||
<td><%= link_to message("property.category.#{category}", :default => category), :overwrite_params => {:category => category} -%></td> | |||
</tr> | |||
<% end | |||
end | |||
%> | |||
</tbody> | |||
</table> | |||
<br/> | |||
</td> | |||
<td class="column"> | |||
<div id="properties"> | |||
<%= render :partial => 'settings/properties' -%> | |||
</div> | |||
</td> | |||
</tr> | |||
</table> | |||
</div> |
@@ -1,6 +1,6 @@ | |||
<select name="<%= h property.key -%>" id="input_<%= h property.key-%>"> | |||
<option value=""><%= message('default') -%></option> | |||
<% property.options.each do |option| %> | |||
<option value="<%= h option -%>"><%= h option -%></option> | |||
<option value="<%= h option -%>" <%= 'selected' if value && value==option -%>><%= h option -%></option> | |||
<% end %> | |||
</select> |
@@ -1 +1 @@ | |||
<%= render :partial => 'plugins', :locals => {:project=>nil} %> | |||
<%= render :partial => 'settings', :locals => {:project=>nil} %> |