underTest
.start(new Props(properties));
-
MutablePicoContainer picoContainer = underTest.getComponentContainer().getPicoContainer();
assertThat(picoContainer.getComponentAdapters())
.hasSize(
CREATE TABLE "RULES" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "PLUGIN_KEY" VARCHAR(200),
"PLUGIN_RULE_KEY" VARCHAR(200) NOT NULL,
"PLUGIN_NAME" VARCHAR(255) NOT NULL,
"DESCRIPTION" VARCHAR(16777215),
private RuleKey key;
+ private String pluginKey;
+
private long createdAt;
private long updatedAt;
return this;
}
+ public String getPluginKey() {
+ return pluginKey;
+ }
+
+ public RuleDefinitionDto setPluginKey(String pluginKey) {
+ this.pluginKey = pluginKey;
+ return this;
+ }
+
@Override
public boolean equals(Object obj) {
if (!(obj instanceof RuleDto)) {
return this;
}
+ public String getPluginKey() {
+ return definition.getPluginKey();
+ }
+
+ public RuleDto setPluginKey(String s) {
+ definition.setPluginKey(s);
+ return this;
+ }
+
public String getDescription() {
return definition.getDescription();
}
r.gap_description as "gapDescription",
r.system_tags as "systemTagsField",
r.rule_type as "type",
+ r.plugin_key as "pluginKey",
</sql>
<sql id="selectRuleTableColumns">
<insert id="insertDefinition" parameterType="org.sonar.db.rule.RuleDefinitionDto" keyColumn="id" useGeneratedKeys="true" keyProperty="id">
insert into rules (
+ plugin_key,
plugin_rule_key,
plugin_name,
description,
updated_at
)
values (
+ #{pluginKey,jdbcType=VARCHAR},
#{ruleKey,jdbcType=VARCHAR},
#{repositoryKey,jdbcType=VARCHAR},
#{description,jdbcType=VARCHAR},
<update id="updateDefinition" parameterType="org.sonar.db.rule.RuleDefinitionDto">
update rules set
+ plugin_key=#{pluginKey,jdbcType=VARCHAR},
plugin_rule_key=#{ruleKey,jdbcType=VARCHAR},
plugin_name=#{repositoryKey,jdbcType=VARCHAR},
description=#{description,jdbcType=VARCHAR},
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.platform.db.migration.version.v66;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder;
+
+public class AddPluginKeyToRules extends DdlChange {
+
+ public AddPluginKeyToRules(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ context.execute(new AddColumnsBuilder(getDialect(), "rules")
+ .addColumn(newVarcharColumnDefBuilder()
+ .setColumnName("plugin_key")
+ .setLimit(200)
+ .setIsNullable(true)
+ .build())
+ .build());
+ }
+}
.add(1801, "Create table CE task characteristics", CreateTableCeTaskCharacteristics.class)
.add(1802, "Delete leak settings on views", DeleteLeakSettingsOnViews.class)
.add(1803, "Fix empty USERS.EXTERNAL_IDENTITY and USERS.EXTERNAL_IDENTITY_PROVIDER", FixEmptyIdentityProviderInUsers.class)
- ;
+ .add(1804, "Add rules.plugin_key", AddPluginKeyToRules.class);
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v66;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.db.CoreDbTester;
+
+public class AddPluginKeyToRulesTest {
+ @Rule
+ public final CoreDbTester dbTester = CoreDbTester.createForSchema(AddPluginKeyToRulesTest.class, "rules_6_5.sql");
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private AddPluginKeyToRules underTest = new AddPluginKeyToRules(dbTester.database());
+
+ @Test
+ public void column_is_added_to_table() throws SQLException {
+ underTest.execute();
+
+ dbTester.assertColumnDefinition("rules", "plugin_key", java.sql.Types.VARCHAR, 200, true);
+ }
+
+ @Test
+ public void migration_is_not_reentrant() throws SQLException {
+ underTest.execute();
+
+ expectedException.expect(IllegalStateException.class);
+
+ underTest.execute();
+ }
+
+}
* 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.platform.db.migration.version.v66;
import org.junit.Test;
@Test
public void verify_migration_count() {
- verifyMigrationCount(underTest, 4);
+ verifyMigrationCount(underTest, 5);
}
}
--- /dev/null
+CREATE TABLE "RULES" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "PLUGIN_RULE_KEY" VARCHAR(200) NOT NULL,
+ "PLUGIN_NAME" VARCHAR(255) NOT NULL,
+ "DESCRIPTION" VARCHAR(16777215),
+ "DESCRIPTION_FORMAT" VARCHAR(20),
+ "PRIORITY" INTEGER,
+ "IS_TEMPLATE" BOOLEAN DEFAULT FALSE,
+ "TEMPLATE_ID" INTEGER,
+ "PLUGIN_CONFIG_KEY" VARCHAR(200),
+ "NAME" VARCHAR(200),
+ "STATUS" VARCHAR(40),
+ "LANGUAGE" VARCHAR(20),
+ "DEF_REMEDIATION_FUNCTION" VARCHAR(20),
+ "DEF_REMEDIATION_GAP_MULT" VARCHAR(20),
+ "DEF_REMEDIATION_BASE_EFFORT" VARCHAR(20),
+ "GAP_DESCRIPTION" VARCHAR(4000),
+ "SYSTEM_TAGS" VARCHAR(4000),
+ "RULE_TYPE" TINYINT,
+ "CREATED_AT" BIGINT,
+ "UPDATED_AT" BIGINT
+);
+CREATE UNIQUE INDEX "RULES_REPO_KEY" ON "RULES" ("PLUGIN_NAME", "PLUGIN_RULE_KEY");
\ No newline at end of file
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import org.apache.commons.io.FileUtils;
import org.picocontainer.Startable;
// following fields are available after startup
private final Map<String, PluginInfo> pluginInfosByKeys = new HashMap<>();
private final Map<String, Plugin> pluginInstancesByKeys = new HashMap<>();
+ private final Map<ClassLoader, String> keysByClassLoader = new HashMap<>();
public ServerPluginRepository(SonarRuntime runtime, ServerUpgradeStatus upgradeStatus,
ServerFileSystem fs, PluginLoader loader) {
loader.unload(pluginInstancesByKeys.values());
pluginInstancesByKeys.clear();
pluginInfosByKeys.clear();
+ keysByClassLoader.clear();
started.set(true);
}
+ /**
+ * Return the key of the plugin the extension (in the sense of {@link Plugin.Context#addExtension(Object)} is coming from.
+ */
+ @CheckForNull
+ public String getPluginKey(Object extension) {
+ return keysByClassLoader.get(extension.getClass().getClassLoader());
+ }
+
/**
* Load the plugins that are located in extensions/plugins. Blacklisted plugins are
* deleted.
private void loadInstances() {
pluginInstancesByKeys.putAll(loader.load(pluginInfosByKeys));
+
+ for (Map.Entry<String, Plugin> e : pluginInstancesByKeys.entrySet()) {
+ keysByClassLoader.put(e.getValue().getClass().getClassLoader(), e.getKey());
+ }
}
/**
import javax.annotation.Nullable;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
+import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rules.RuleParam;
import org.sonar.api.rules.RuleRepository;
-import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.server.ServerSide;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.server.debt.DebtModelXMLExporter;
import org.sonar.server.debt.DebtModelXMLExporter.RuleDebt;
import org.sonar.server.debt.DebtRulesXMLImporter;
+import org.sonar.server.plugins.ServerPluginRepository;
import static com.google.common.collect.Lists.newArrayList;
private final DebtModelPluginRepository languageModelFinder;
private final DebtRulesXMLImporter importer;
+ private final ServerPluginRepository serverPluginRepository;
- public DeprecatedRulesDefinitionLoader(RuleI18nManager i18n, DebtModelPluginRepository languageModelFinder, DebtRulesXMLImporter importer, RuleRepository[] repositories) {
+ public DeprecatedRulesDefinitionLoader(RuleI18nManager i18n, DebtModelPluginRepository languageModelFinder, DebtRulesXMLImporter importer,
+ ServerPluginRepository serverPluginRepository, RuleRepository[] repositories) {
this.i18n = i18n;
+ this.serverPluginRepository = serverPluginRepository;
this.repositories = repositories;
this.languageModelFinder = languageModelFinder;
this.importer = importer;
/**
* Used when no deprecated repositories
*/
- public DeprecatedRulesDefinitionLoader(RuleI18nManager i18n, DebtModelPluginRepository languageModelFinder, DebtRulesXMLImporter importer) {
- this(i18n, languageModelFinder, importer, new RuleRepository[0]);
+ public DeprecatedRulesDefinitionLoader(RuleI18nManager i18n, DebtModelPluginRepository languageModelFinder, DebtRulesXMLImporter importer,
+ ServerPluginRepository serverPluginRepository) {
+ this(i18n, languageModelFinder, importer, serverPluginRepository, new RuleRepository[0]);
}
void complete(RulesDefinition.Context context) {
List<RuleDebt> ruleDebts = loadRuleDebtList();
for (RuleRepository repository : repositories) {
+ context.setCurrentPluginKey(serverPluginRepository.getPluginKey(repository));
// RuleRepository API does not handle difference between new and extended repositories,
RulesDefinition.NewRepository newRepository;
if (context.repository(repository.getKey()) == null) {
ruleDebt.coefficient(),
ruleDebt.offset(),
newRule.debtRemediationFunctions(),
- repoKey, ruleKey
- ));
+ repoKey, ruleKey));
}
}
private String paramDescription(String repositoryKey, String ruleKey, RuleParam param) {
String desc = StringUtils.defaultIfEmpty(
i18n.getParamDescription(repositoryKey, ruleKey, param.getKey()),
- param.getDescription()
- );
+ param.getDescription());
return StringUtils.defaultIfBlank(desc, null);
}
private RuleDefinitionDto createRuleDto(RulesDefinition.Rule ruleDef, DbSession session) {
RuleDefinitionDto ruleDto = new RuleDefinitionDto()
.setRuleKey(RuleKey.of(ruleDef.repository().key(), ruleDef.key()))
+ .setPluginKey(ruleDef.pluginKey())
.setIsTemplate(ruleDef.template())
.setConfigKey(ruleDef.internalKey())
.setLanguage(ruleDef.repository().language())
if (mergeDescription(def, dto)) {
changed = true;
}
+ if (!StringUtils.equals(dto.getPluginKey(), def.pluginKey())) {
+ dto.setPluginKey(def.pluginKey());
+ changed = true;
+ }
if (!StringUtils.equals(dto.getConfigKey(), def.internalKey())) {
dto.setConfigKey(def.internalKey());
changed = true;
customRule.setConfigKey(templateRule.getConfigKey());
changed = true;
}
+ if (!StringUtils.equals(customRule.getPluginKey(), templateRule.getPluginKey())) {
+ customRule.setPluginKey(templateRule.getPluginKey());
+ changed = true;
+ }
if (!StringUtils.equals(customRule.getDefRemediationFunction(), templateRule.getDefRemediationFunction())) {
customRule.setDefRemediationFunction(templateRule.getDefRemediationFunction());
changed = true;
private RuleKey createCustomRule(RuleKey ruleKey, NewCustomRule newRule, RuleDto templateRuleDto, DbSession dbSession) {
RuleDefinitionDto ruleDefinition = new RuleDefinitionDto()
.setRuleKey(ruleKey)
+ .setPluginKey(templateRuleDto.getPluginKey())
.setTemplateId(templateRuleDto.getId())
.setConfigKey(templateRuleDto.getConfigKey())
.setName(newRule.name())
package org.sonar.server.rule;
import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.server.plugins.ServerPluginRepository;
/**
* Loads all instances of {@link RulesDefinition}. Used during server startup
private final DeprecatedRulesDefinitionLoader deprecatedDefConverter;
private final CommonRuleDefinitions coreCommonDefs;
private final RulesDefinition[] pluginDefs;
+ private final ServerPluginRepository serverPluginRepository;
public RuleDefinitionsLoader(DeprecatedRulesDefinitionLoader deprecatedDefConverter,
- CommonRuleDefinitions coreCommonDefs, RulesDefinition[] pluginDefs) {
+ CommonRuleDefinitions coreCommonDefs, ServerPluginRepository serverPluginRepository, RulesDefinition[] pluginDefs) {
this.deprecatedDefConverter = deprecatedDefConverter;
this.coreCommonDefs = coreCommonDefs;
+ this.serverPluginRepository = serverPluginRepository;
this.pluginDefs = pluginDefs;
}
* Used when no definitions at all.
*/
public RuleDefinitionsLoader(DeprecatedRulesDefinitionLoader converter,
- CommonRuleDefinitions coreCommonDefs) {
- this(converter, coreCommonDefs, new RulesDefinition[0]);
+ CommonRuleDefinitions coreCommonDefs, ServerPluginRepository serverPluginRepository) {
+ this(converter, coreCommonDefs, serverPluginRepository, new RulesDefinition[0]);
}
public RulesDefinition.Context load() {
RulesDefinition.Context context = new RulesDefinition.Context();
for (RulesDefinition pluginDefinition : pluginDefs) {
+ context.setCurrentPluginKey(serverPluginRepository.getPluginKey(pluginDefinition));
pluginDefinition.define(context);
}
deprecatedDefConverter.complete(context);
+ context.setCurrentPluginKey(null);
coreCommonDefs.define(context);
return context;
}
import org.sonar.server.debt.DebtModelPluginRepository;
import org.sonar.server.debt.DebtModelXMLExporter;
import org.sonar.server.debt.DebtRulesXMLImporter;
+import org.sonar.server.plugins.ServerPluginRepository;
import static com.google.common.collect.Lists.newArrayList;
import static org.assertj.core.api.Assertions.assertThat;
@Mock
DebtRulesXMLImporter importer;
+ @Mock
+ ServerPluginRepository pluginRepository;
+
static class CheckstyleRules extends RuleRepository {
public CheckstyleRules() {
super("checkstyle", "java");
@Test
public void wrap_deprecated_rule_repositories() {
RulesDefinition.Context context = new RulesDefinition.Context();
- new DeprecatedRulesDefinitionLoader(i18n, debtModelRepository, importer, new RuleRepository[] {new CheckstyleRules()}).complete(context);
+ CheckstyleRules checkstyleRules = new CheckstyleRules();
+ when(pluginRepository.getPluginKey(checkstyleRules)).thenReturn("unittest");
+ new DeprecatedRulesDefinitionLoader(i18n, debtModelRepository, importer, pluginRepository, new RuleRepository[] {checkstyleRules}).complete(context);
assertThat(context.repositories()).hasSize(1);
RulesDefinition.Repository checkstyle = context.repository("checkstyle");
RulesDefinition.Rule rule = checkstyle.rule("ConstantName");
assertThat(rule).isNotNull();
assertThat(rule.key()).isEqualTo("ConstantName");
+ assertThat(rule.pluginKey()).isEqualTo("unittest");
assertThat(rule.name()).isEqualTo("Constant Name");
assertThat(rule.htmlDescription()).isEqualTo("Checks that constant names conform to the specified format");
assertThat(rule.severity()).isEqualTo(Severity.BLOCKER);
RulesDefinition.Context context = new RulesDefinition.Context();
// no more RuleRepository !
- new DeprecatedRulesDefinitionLoader(i18n, debtModelRepository, importer);
+ new DeprecatedRulesDefinitionLoader(i18n, debtModelRepository, importer, pluginRepository);
assertThat(context.repositories()).isEmpty();
}
when(i18n.getDescription("checkstyle", "ConstantName")).thenReturn("Checks that constant names conform to the specified format");
when(i18n.getParamDescription("checkstyle", "ConstantName", "format")).thenReturn("Regular expression");
- new DeprecatedRulesDefinitionLoader(i18n, debtModelRepository, importer, new RuleRepository[] {new UseBundles()}).complete(context);
+ new DeprecatedRulesDefinitionLoader(i18n, debtModelRepository, importer, pluginRepository, new RuleRepository[] {new UseBundles()}).complete(context);
RulesDefinition.Repository checkstyle = context.repository("checkstyle");
RulesDefinition.Rule rule = checkstyle.rule("ConstantName");
.setRuleKey(RuleKey.of("checkstyle", "ConstantName"))
.setFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name())
.setCoefficient("1d")
- .setOffset("10min")
- );
+ .setOffset("10min"));
Reader javaModelReader = mock(Reader.class);
when(debtModelRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
when(debtModelRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
when(importer.importXML(eq(javaModelReader), any(ValidationMessages.class))).thenReturn(ruleDebts);
- new DeprecatedRulesDefinitionLoader(i18n, debtModelRepository, importer, new RuleRepository[] {new CheckstyleRules()}).complete(context);
+ new DeprecatedRulesDefinitionLoader(i18n, debtModelRepository, importer, pluginRepository, new RuleRepository[] {new CheckstyleRules()}).complete(context);
assertThat(context.repositories()).hasSize(1);
RulesDefinition.Repository checkstyle = context.repository("checkstyle");
new DebtModelXMLExporter.RuleDebt()
.setRuleKey(RuleKey.of("checkstyle", "ConstantName"))
.setFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name())
- .setCoefficient("1d")
- );
+ .setCoefficient("1d"));
Reader javaModelReader = mock(Reader.class);
when(debtModelRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
when(importer.importXML(eq(javaModelReader), any(ValidationMessages.class))).thenReturn(ruleDebts);
try {
- new DeprecatedRulesDefinitionLoader(i18n, debtModelRepository, importer, new RuleRepository[] {new CheckstyleRules()}).complete(context);
+ new DeprecatedRulesDefinitionLoader(i18n, debtModelRepository, importer, pluginRepository, new RuleRepository[] {new CheckstyleRules()}).complete(context);
fail();
} catch (Exception e) {
assertThat(e).isInstanceOf(IllegalArgumentException.class);
import org.sonar.server.es.SearchOptions;
import org.sonar.server.organization.OrganizationFlags;
import org.sonar.server.organization.TestOrganizationFlags;
+import org.sonar.server.plugins.ServerPluginRepository;
import org.sonar.server.qualityprofile.RuleActivator;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.rule.index.RuleIndex;
import static java.util.Collections.singletonList;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
public class RegisterRulesTest {
+ private static final String FAKE_PLUGIN_KEY = "unittest";
private static final Date DATE1 = DateUtils.parseDateTime("2014-01-01T19:10:03+0100");
private static final Date DATE2 = DateUtils.parseDateTime("2014-02-01T12:10:03+0100");
private static final Date DATE3 = DateUtils.parseDateTime("2014-03-01T12:10:03+0100");
assertThat(rule1.getDefRemediationGapMultiplier()).isEqualTo("5d");
assertThat(rule1.getDefRemediationBaseEffort()).isEqualTo("10h");
assertThat(rule1.getType()).isEqualTo(RuleType.CODE_SMELL.getDbConstant());
+ assertThat(rule1.getPluginKey()).isEqualTo(FAKE_PLUGIN_KEY);
List<RuleParamDto> params = dbClient.ruleDao().selectRuleParamsByRuleKey(dbTester.getSession(), RULE_KEY1);
assertThat(params).hasSize(2);
}
private void execute(RulesDefinition... defs) {
- RuleDefinitionsLoader loader = new RuleDefinitionsLoader(mock(DeprecatedRulesDefinitionLoader.class), mock(CommonRuleDefinitionsImpl.class), defs);
+ ServerPluginRepository pluginRepository = mock(ServerPluginRepository.class);
+ when(pluginRepository.getPluginKey(any(RulesDefinition.class))).thenReturn(FAKE_PLUGIN_KEY);
+ RuleDefinitionsLoader loader = new RuleDefinitionsLoader(mock(DeprecatedRulesDefinitionLoader.class), mock(CommonRuleDefinitionsImpl.class), pluginRepository,
+ defs);
Languages languages = mock(Languages.class);
when(languages.get("java")).thenReturn(mock(Language.class));
reset(webServerRuleFinder);
RuleDto rule = dbTester.getDbClient().ruleDao().selectOrFailByKey(dbSession, dbTester.getDefaultOrganization(), customRuleKey);
assertThat(rule).isNotNull();
assertThat(rule.getKey()).isEqualTo(RuleKey.of("java", "CUSTOM_RULE"));
+ assertThat(rule.getPluginKey()).isEqualTo("sonarjava");
assertThat(rule.getTemplateId()).isEqualTo(templateRule.getId());
assertThat(rule.getName()).isEqualTo("My custom");
assertThat(rule.getDescription()).isEqualTo("Some description");
RuleDto templateRule = RuleTesting.newDto(RuleKey.of("java", "S001"), dbTester.getDefaultOrganization())
.setIsTemplate(true)
.setLanguage("java")
+ .setPluginKey("sonarjava")
.setConfigKey("S001")
.setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name())
.setDefRemediationGapMultiplier("1h")
.setCreatedAt(new Date().getTime())
.setUpdatedAt(new Date().getTime());
dbTester.rules().insert(templateRule);
- dbTester.rules().insertRuleParam(templateRule, param -> param.setName("myIntegers").setType("INTEGER,multiple=true,values=1;2;3").setDescription("My Integers").setDefaultValue("1"));
+ dbTester.rules().insertRuleParam(templateRule,
+ param -> param.setName("myIntegers").setType("INTEGER,multiple=true,values=1;2;3").setDescription("My Integers").setDefaultValue("1"));
ruleIndexer.commitAndIndex(dbTester.getSession(), templateRule.getKey());
return templateRule;
}
import org.junit.Test;
import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.server.plugins.ServerPluginRepository;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@Test
public void no_definitions() {
CommonRuleDefinitions commonRulesDefinitions = mock(CommonRuleDefinitions.class);
- RulesDefinition.Context context = new RuleDefinitionsLoader(mock(DeprecatedRulesDefinitionLoader.class), commonRulesDefinitions).load();
+ RulesDefinition.Context context = new RuleDefinitionsLoader(mock(DeprecatedRulesDefinitionLoader.class), commonRulesDefinitions, mock(ServerPluginRepository.class)).load();
assertThat(context.repositories()).isEmpty();
}
@Test
public void load_definitions() {
CommonRuleDefinitions commonRulesDefinitions = mock(CommonRuleDefinitions.class);
- RulesDefinition.Context context = new RuleDefinitionsLoader(mock(DeprecatedRulesDefinitionLoader.class), commonRulesDefinitions, new RulesDefinition[] {
- new FindbugsDefinitions(), new SquidDefinitions()
- }).load();
+ RulesDefinition.Context context = new RuleDefinitionsLoader(mock(DeprecatedRulesDefinitionLoader.class), commonRulesDefinitions, mock(ServerPluginRepository.class),
+ new RulesDefinition[] {
+ new FindbugsDefinitions(), new SquidDefinitions()
+ }).load();
assertThat(context.repositories()).hasSize(2);
assertThat(context.repository("findbugs")).isNotNull();
@Test
public void define_common_rules() throws Exception {
CommonRuleDefinitions commonRulesDefinitions = new FakeCommonRuleDefinitions();
- RulesDefinition.Context context = new RuleDefinitionsLoader(mock(DeprecatedRulesDefinitionLoader.class), commonRulesDefinitions, new RulesDefinition[] {
- new SquidDefinitions()
- }).load();
+ RulesDefinition.Context context = new RuleDefinitionsLoader(mock(DeprecatedRulesDefinitionLoader.class), commonRulesDefinitions, mock(ServerPluginRepository.class),
+ new RulesDefinition[] {
+ new SquidDefinitions()
+ }).load();
assertThat(context.repositories()).extracting("key").containsOnly("squid", "common-java");
assertThat(context.repository("common-java").rules()).extracting("key").containsOnly("InsufficientBranchCoverage");
@Test
public void plugin_common_rules_are_overridden() throws Exception {
CommonRuleDefinitions commonRulesDefinitions = new FakeCommonRuleDefinitions();
- RulesDefinition.Context context = new RuleDefinitionsLoader(mock(DeprecatedRulesDefinitionLoader.class), commonRulesDefinitions, new RulesDefinition[] {
- new PluginCommonRuleDefinitions()
- }).load();
+ RulesDefinition.Context context = new RuleDefinitionsLoader(mock(DeprecatedRulesDefinitionLoader.class), commonRulesDefinitions, mock(ServerPluginRepository.class),
+ new RulesDefinition[] {
+ new PluginCommonRuleDefinitions()
+ }).load();
assertThat(context.repositories()).extracting("key").containsOnly("common-java");
assertThat(context.repository("common-java").rules()).extracting("key").containsOnly("InsufficientBranchCoverage");
*/
class Context {
private final Map<String, Repository> repositoriesByKey = new HashMap<>();
+ private String currentPluginKey;
/**
* New builder for {@link org.sonar.api.server.rule.RulesDefinition.Repository}.
}
repositoriesByKey.put(newRepository.key, new RepositoryImpl(newRepository, existing));
}
+
+ public void setCurrentPluginKey(@Nullable String pluginKey) {
+ this.currentPluginKey = pluginKey;
+ }
}
interface NewExtendedRepository {
@Override
public NewRule createRule(String ruleKey) {
checkArgument(!newRules.containsKey(ruleKey), "The rule '%s' of repository '%s' is declared several times", ruleKey, key);
- NewRule newRule = new NewRule(key, ruleKey);
+ NewRule newRule = new NewRule(context.currentPluginKey, key, ruleKey);
newRules.put(ruleKey, newRule);
return newRule;
}
}
class NewRule {
+ private final String pluginKey;
private final String repoKey;
private final String key;
private RuleType type;
private final DebtRemediationFunctions functions;
private boolean activatedByDefault;
- private NewRule(String repoKey, String key) {
+ private NewRule(@Nullable String pluginKey, String repoKey, String key) {
+ this.pluginKey = pluginKey;
this.repoKey = repoKey;
this.key = key;
this.functions = new DefaultDebtRemediationFunctions(repoKey, key);
@Immutable
class Rule {
+ private final String pluginKey;
private final Repository repository;
private final String repoKey;
private final String key;
private final boolean activatedByDefault;
private Rule(Repository repository, NewRule newRule) {
+ this.pluginKey = newRule.pluginKey;
this.repository = repository;
this.repoKey = newRule.repoKey;
this.key = newRule.key;
return repository;
}
+ /**
+ * @since 6.6 the plugin the rule was declared in
+ */
+ @CheckForNull
+ public String pluginKey() {
+ return pluginKey;
+ }
+
public String key() {
return key;
}
pluginInstancesByKeys.clear();
infosByKeys.clear();
+ keysByClassLoader.clear();
}
@Override