return executeLargeInputs(ruleKeys, mapper(session)::selectParamsByRuleKeys);
}
+ public List<RuleParamDto> selectAllRuleParams(DbSession session) {
+ return mapper(session).selectAllRuleParams();
+ }
+
public List<RuleParamDto> selectRuleParamsByRuleUuids(DbSession dbSession, Collection<String> ruleUuids) {
return executeLargeInputs(ruleUuids, mapper(dbSession)::selectParamsByRuleUuids);
}
List<RuleParamDto> selectParamsByRuleKeys(@Param("ruleKeys") List<RuleKey> ruleKeys);
+ List<RuleParamDto> selectAllRuleParams();
+
void insertParameter(RuleParamDto param);
void updateParameter(RuleParamDto param);
inner join rules r on r.uuid = a.rule_uuid
</sql>
- <insert id="insert" parameterType="ActiveRule">
+ <insert id="insert" parameterType="ActiveRule" useGeneratedKeys="false">
insert into active_rules (
uuid,
profile_uuid,
)
</insert>
- <update id="update" parameterType="ActiveRule">
+ <update id="update" parameterType="ActiveRule" useGeneratedKeys="false">
update active_rules
set
failure_level = #{severity, jdbcType=INTEGER},
</select>
<select id="selectIndexingRuleExtensionsByIds" parameterType="map" resultType="org.sonar.db.rule.RuleExtensionForIndexingDto">
- <include refid="sqlSelectIndexingRuleExtensions" />
+ <include refid="sqlSelectIndexingRuleExtensions"/>
and
<foreach collection="ruleExtensionIds" index="index" item="ruleExtId" open="" separator=" or " close="">
( r.uuid = #{ruleExtId, jdbcType=VARCHAR} )
order by r.created_at asc
</select>
- <select id="scrollIndexingRules" resultType="org.sonar.db.rule.RuleForIndexingDto" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY">
+ <select id="scrollIndexingRules" resultType="org.sonar.db.rule.RuleForIndexingDto" fetchSize="${_scrollFetchSize}"
+ resultSetType="FORWARD_ONLY">
<include refid="sqlSelectIndexingRules"/>
order by r.created_at asc
</select>
<include refid="outerJoinRulesMetadata"/>
where
r.status != 'REMOVED' and r.is_external=${_false} and r.is_template=${_false}
- and r.rule_type in <foreach collection="types" item="type" separator="," open="(" close=")">#{type, jdbcType=INTEGER}</foreach>
- and r.language in <foreach collection="languages" item="language" separator="," open="(" close=")">#{language, jdbcType=VARCHAR}</foreach>
+ and r.rule_type in
+ <foreach collection="types" item="type" separator="," open="(" close=")">#{type, jdbcType=INTEGER}</foreach>
+ and r.language in
+ <foreach collection="languages" item="language" separator="," open="(" close=")">#{language, jdbcType=VARCHAR}</foreach>
</select>
<insert id="insertDefinition" parameterType="org.sonar.db.rule.RuleDefinitionDto" useGeneratedKeys="false">
</foreach>
</select>
+ <select id="selectAllRuleParams" resultType="RuleParam">
+ select
+ <include refid="paramColumns"/>
+ from
+ rules_parameters p
+ </select>
+
<select id="selectParamsByRuleKey" resultType="RuleParam" parameterType="org.sonar.api.rule.RuleKey">
select
<include refid="paramColumns"/>
</foreach>
</delete>
- <insert id="insertDeprecatedRuleKey" parameterType="org.sonar.db.rule.DeprecatedRuleKeyDto" keyColumn="uuid" useGeneratedKeys="false" keyProperty="uuid">
+ <insert id="insertDeprecatedRuleKey" parameterType="org.sonar.db.rule.DeprecatedRuleKeyDto" keyColumn="uuid" useGeneratedKeys="false"
+ keyProperty="uuid">
INSERT INTO deprecated_rule_keys (
uuid,
rule_uuid,
import org.sonar.db.rule.RuleParamDto;
import org.sonar.markdown.Markdown;
-import static com.google.common.collect.Lists.newArrayList;
-import static java.util.Optional.empty;
-
/**
* Will be removed in the future.
*/
@Override
public Optional<RuleDefinitionDto> findDtoByKey(RuleKey key) {
try (DbSession dbSession = dbClient.openSession(false)) {
- Optional<RuleDefinitionDto> rule = ruleDao.selectDefinitionByKey(dbSession, key);
- if (rule.isPresent() && rule.get().getStatus() != RuleStatus.REMOVED) {
- return rule;
- } else {
- return empty();
- }
+ return ruleDao.selectDefinitionByKey(dbSession, key)
+ .filter(r -> r.getStatus() != RuleStatus.REMOVED);
+ }
+ }
+
+ @Override
+ public Optional<RuleDefinitionDto> findDtoByUuid(String uuid) {
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ return ruleDao.selectDefinitionByUuid(uuid, dbSession)
+ .filter(r -> r.getStatus() != RuleStatus.REMOVED);
+ }
+ }
+
+ @Override
+ public Collection<RuleDefinitionDto> findAll() {
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ List<RuleDefinitionDto> list = new ArrayList<>();
+ ruleDao.selectEnabled(dbSession, r -> list.add(r.getResultObject()));
+ return list;
}
}
}
}
- List<org.sonar.api.rules.RuleParam> apiParams = newArrayList();
+ List<org.sonar.api.rules.RuleParam> apiParams = new ArrayList<>();
for (RuleParamDto param : params) {
apiParams.add(new org.sonar.api.rules.RuleParam(apiRule, param.getName(), param.getDescription(), param.getType())
.setDefaultValue(param.getDefaultValue()));
*/
package org.sonar.server.rule;
+import java.util.Collection;
import java.util.Optional;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.RuleFinder;
public interface ServerRuleFinder extends RuleFinder {
Optional<RuleDefinitionDto> findDtoByKey(RuleKey key);
+
+ Optional<RuleDefinitionDto> findDtoByUuid(String uuid);
+
+ Collection<RuleDefinitionDto> findAll();
+
}
import com.google.common.collect.ImmutableSet;
import org.junit.Before;
import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleQuery;
@org.junit.Rule
public DbTester dbTester = DbTester.create(System2.INSTANCE);
- private DbClient dbClient = dbTester.getDbClient();
- private DbSession session = dbTester.getSession();
+ private final DbClient dbClient = dbTester.getDbClient();
+ private final DbSession session = dbTester.getSession();
- private RuleDto rule1 = new RuleDto()
+ private final RuleDto rule1 = new RuleDto()
.setName("Check Header")
.setConfigKey("Checker/Treewalker/HeaderCheck")
.setRuleKey("com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck")
.setScope(Scope.MAIN)
.setStatus(RuleStatus.READY);
- private RuleDto rule2 = new RuleDto()
+ private final RuleDto rule2 = new RuleDto()
.setName("Disabled checked")
.setConfigKey("Checker/Treewalker/DisabledCheck")
.setRuleKey("DisabledCheck")
.setScope(Scope.MAIN)
.setStatus(RuleStatus.REMOVED);
- private RuleDto rule3 = new RuleDto()
+ private final RuleDto rule3 = new RuleDto()
.setName("Check Annotation")
.setConfigKey("Checker/Treewalker/AnnotationUseStyleCheck")
.setRuleKey("com.puppycrawl.tools.checkstyle.checks.annotation.AnnotationUseStyleCheck")
.setScope(Scope.MAIN)
.setStatus(RuleStatus.READY);
- private RuleDto rule4 = new RuleDto()
+ private final RuleDto rule4 = new RuleDto()
.setName("Call Super First")
.setConfigKey("rulesets/android.xml/CallSuperFirst")
.setRuleKey("CallSuperFirst")
.setScope(Scope.MAIN)
.setStatus(RuleStatus.READY);
- private DefaultRuleFinder underTest = new DefaultRuleFinder(dbClient);
+ private final DefaultRuleFinder underTest = new DefaultRuleFinder(dbClient);
@Before
public void setup() {
// find_all_enabled
assertThat(underTest.findAll(RuleQuery.create())).extracting("ruleKey").containsOnly(rule1.getKey(), rule3.getKey(), rule4.getKey());
- assertThat(underTest.findAll(RuleQuery.create())).hasSize(3);
+
+ // find_all
+ assertThat(underTest.findAll()).extracting("ruleKey").containsOnly(rule1.getKey().rule(), rule3.getKey().rule(), rule4.getKey().rule());
// do_not_find_disabled_rules
assertThat(underTest.findByKey("checkstyle", "DisabledCheck")).isNull();
// do_not_find_unknown_rules
assertThat(underTest.findAll(RuleQuery.create().withRepositoryKey("unknown_repository"))).isEmpty();
+
+ assertThat(underTest.findDtoByKey(RuleKey.of("pmd", "CallSuperFirst")).get().getUuid()).isEqualTo(rule4.getUuid());
+ assertThat(underTest.findDtoByUuid(rule4.getUuid())).isPresent();
+ }
+
+ @Test
+ public void should_fail_find() {
+ assertThat(underTest.findDtoByKey(RuleKey.of("pmd", "unknown"))).isEmpty();
+ assertThat(underTest.findDtoByUuid("unknown")).isEmpty();
}
@Test
public void find_all_not_include_removed_rule() {
// rule 3 is REMOVED
assertThat(underTest.findAll(RuleQuery.create())).extracting("ruleKey").containsOnly(rule1.getKey(), rule3.getKey(), rule4.getKey());
+ assertThat(underTest.findAll()).extracting("ruleKey").containsOnly(rule1.getKey().rule(), rule3.getKey().rule(), rule4.getKey().rule());
}
@Test
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.plugins;
+
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.sonar.api.Startable;
+import org.sonar.api.utils.Preconditions;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.api.utils.log.Profiler;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.plugin.PluginDto;
+
+import static java.util.function.Function.identity;
+
+public class DetectPluginChange implements Startable {
+ private static final Logger LOG = Loggers.get(DetectPluginChange.class);
+
+ private final ServerPluginRepository serverPluginRepository;
+ private final DbClient dbClient;
+ private Boolean changesDetected = null;
+
+ public DetectPluginChange(ServerPluginRepository serverPluginRepository, DbClient dbClient) {
+ this.serverPluginRepository = serverPluginRepository;
+ this.dbClient = dbClient;
+ }
+
+ @Override
+ public void start() {
+ Preconditions.checkState(changesDetected == null, "Can only call #start() once");
+ Profiler profiler = Profiler.create(LOG).startInfo("Detect plugin changes");
+ changesDetected = anyChange();
+ if (changesDetected) {
+ LOG.info("Plugin changes detected");
+ } else {
+ LOG.debug("No plugin changes detected");
+ }
+ profiler.stopDebug();
+ }
+
+ /**
+ * @throws NullPointerException if {@link #start} hasn't been called
+ */
+ public boolean anyPluginChanged() {
+ return changesDetected;
+ }
+
+ private boolean anyChange() {
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ Map<String, PluginDto> dbPluginsByKey = dbClient.pluginDao().selectAll(dbSession).stream()
+ .collect(Collectors.toMap(PluginDto::getKee, identity()));
+ Map<String, ServerPlugin> filePluginsByKey = serverPluginRepository.getPlugins().stream()
+ .collect(Collectors.toMap(p -> p.getPluginInfo().getKey(), p -> p));
+
+ if (!dbPluginsByKey.keySet().equals(filePluginsByKey.keySet())) {
+ return true;
+ }
+
+ // TODO ideally we would detect plugins that were removed and added again, because we don't delete removed plugins from the plugins table.
+ for (ServerPlugin installed : filePluginsByKey.values()) {
+ PluginDto dbPlugin = dbPluginsByKey.get(installed.getPluginInfo().getKey());
+ if (changed(dbPlugin, installed)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean changed(PluginDto dbPlugin, ServerPlugin filePlugin) {
+ return !dbPlugin.getFileHash().equals(filePlugin.getJar().getMd5()) || !dbPlugin.getType().equals(toTypeDto(filePlugin.getType()));
+ }
+
+ static PluginDto.Type toTypeDto(PluginType type) {
+ switch (type) {
+ case EXTERNAL:
+ return PluginDto.Type.EXTERNAL;
+ case BUNDLED:
+ return PluginDto.Type.BUNDLED;
+ default:
+ throw new IllegalStateException("Unknown type: " + type);
+ }
+ }
+
+ @Override
+ public void stop() {
+ // Nothing to do
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.rule;
+
+import com.google.common.collect.Ordering;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.rules.RulePriority;
+import org.sonar.api.rules.RuleQuery;
+import org.sonar.core.util.stream.MoreCollectors;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.rule.RuleDefinitionDto;
+import org.sonar.db.rule.RuleDto;
+import org.sonar.db.rule.RuleParamDto;
+import org.sonar.markdown.Markdown;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.unmodifiableMap;
+import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
+
+/**
+ * A {@link RuleFinder} implementation that retrieves all rule definitions and their parameter when instantiated, cache
+ * them in memory and provide implementation of {@link RuleFinder}'s method which only read from this data in memory.
+ */
+public class CachingRuleFinder implements ServerRuleFinder {
+
+ private static final Ordering<Map.Entry<RuleDefinitionDto, Rule>> FIND_BY_QUERY_ORDER = Ordering.natural().reverse().onResultOf(entry -> entry.getKey().getUpdatedAt());
+
+ private final Map<RuleKey, RuleDefinitionDto> ruleDtosByKey;
+ private final Map<String, RuleDefinitionDto> ruleDtosByUuid;
+ private final Map<RuleDefinitionDto, Rule> rulesByRuleDefinition;
+ private final Map<RuleKey, Rule> rulesByKey;
+
+ public CachingRuleFinder(DbClient dbClient) {
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ List<RuleDefinitionDto> dtos = dbClient.ruleDao().selectAllDefinitions(dbSession);
+ this.ruleDtosByKey = dtos.stream().collect(Collectors.toMap(RuleDefinitionDto::getKey, d -> d));
+ this.ruleDtosByUuid = dtos.stream().collect(Collectors.toMap(RuleDefinitionDto::getUuid, d -> d));
+ this.rulesByRuleDefinition = buildRulesByRuleDefinitionDto(dbClient, dbSession, dtos);
+ this.rulesByKey = this.rulesByRuleDefinition.entrySet().stream()
+ .collect(uniqueIndex(entry -> entry.getKey().getKey(), Map.Entry::getValue));
+ }
+ }
+
+ private static Map<RuleDefinitionDto, Rule> buildRulesByRuleDefinitionDto(DbClient dbClient, DbSession dbSession, List<RuleDefinitionDto> dtos) {
+ Map<String, List<RuleParamDto>> ruleParamsByRuleUuid = retrieveRuleParameters(dbClient, dbSession);
+ Map<RuleDefinitionDto, Rule> rulesByDefinition = new HashMap<>(dtos.size());
+ for (RuleDefinitionDto definition : dtos) {
+ rulesByDefinition.put(definition, toRule(definition, ruleParamsByRuleUuid.getOrDefault(definition.getUuid(), emptyList())));
+ }
+ return unmodifiableMap(rulesByDefinition);
+ }
+
+ private static Map<String, List<RuleParamDto>> retrieveRuleParameters(DbClient dbClient, DbSession dbSession) {
+ return dbClient.ruleDao().selectAllRuleParams(dbSession).stream()
+ .collect(Collectors.groupingBy(RuleParamDto::getRuleUuid));
+ }
+
+ @Override
+ @CheckForNull
+ public Rule findByKey(@Nullable String repositoryKey, @Nullable String key) {
+ if (repositoryKey == null || key == null) {
+ return null;
+ }
+ return findByKey(RuleKey.of(repositoryKey, key));
+ }
+
+ @Override
+ @CheckForNull
+ public Rule findByKey(RuleKey key) {
+ return rulesByKey.get(key);
+ }
+
+ @Override
+ @CheckForNull
+ public Rule find(@Nullable RuleQuery query) {
+ if (query == null) {
+ return null;
+ }
+
+ return rulesByRuleDefinition.entrySet().stream()
+ .filter(entry -> matchQuery(entry.getKey(), query))
+ .sorted(FIND_BY_QUERY_ORDER)
+ .map(Map.Entry::getValue)
+ .findFirst()
+ .orElse(null);
+ }
+
+ @Override
+ public Collection<Rule> findAll(@Nullable RuleQuery query) {
+ if (query == null) {
+ return Collections.emptyList();
+ }
+ return rulesByRuleDefinition.entrySet().stream()
+ .filter(entry -> matchQuery(entry.getKey(), query))
+ .sorted(FIND_BY_QUERY_ORDER)
+ .map(Map.Entry::getValue)
+ .collect(MoreCollectors.toList());
+ }
+
+ private static boolean matchQuery(RuleDefinitionDto ruleDefinition, RuleQuery ruleQuery) {
+ if (RuleStatus.REMOVED.equals(ruleDefinition.getStatus())) {
+ return false;
+ }
+ String repositoryKey = ruleQuery.getRepositoryKey();
+ if (ruleQuery.getRepositoryKey() != null && !repositoryKey.equals(ruleDefinition.getRepositoryKey())) {
+ return false;
+ }
+ String key = ruleQuery.getKey();
+ if (key != null && !key.equals(ruleDefinition.getRuleKey())) {
+ return false;
+ }
+ String configKey = ruleQuery.getConfigKey();
+ return configKey == null || configKey.equals(ruleDefinition.getConfigKey());
+ }
+
+ private static Rule toRule(RuleDefinitionDto ruleDefinition, List<RuleParamDto> params) {
+ String severity = ruleDefinition.getSeverityString();
+ String description = ruleDefinition.getDescription();
+ RuleDto.Format descriptionFormat = ruleDefinition.getDescriptionFormat();
+
+ Rule apiRule = new Rule();
+ apiRule
+ .setName(ruleDefinition.getName())
+ .setLanguage(ruleDefinition.getLanguage())
+ .setKey(ruleDefinition.getRuleKey())
+ .setConfigKey(ruleDefinition.getConfigKey())
+ .setIsTemplate(ruleDefinition.isTemplate())
+ .setCreatedAt(new Date(ruleDefinition.getCreatedAt()))
+ .setUpdatedAt(new Date(ruleDefinition.getUpdatedAt()))
+ .setRepositoryKey(ruleDefinition.getRepositoryKey())
+ .setSeverity(severity != null ? RulePriority.valueOf(severity) : null)
+ .setStatus(ruleDefinition.getStatus().name())
+ .setSystemTags(ruleDefinition.getSystemTags().toArray(new String[ruleDefinition.getSystemTags().size()]))
+ .setTags(new String[0]);
+ if (description != null && descriptionFormat != null) {
+ if (RuleDto.Format.HTML.equals(descriptionFormat)) {
+ apiRule.setDescription(description);
+ } else {
+ apiRule.setDescription(Markdown.convertToHtml(description));
+ }
+ }
+
+ List<org.sonar.api.rules.RuleParam> apiParams = new ArrayList<>();
+ for (RuleParamDto param : params) {
+ apiParams.add(new org.sonar.api.rules.RuleParam(apiRule, param.getName(), param.getDescription(), param.getType())
+ .setDefaultValue(param.getDefaultValue()));
+ }
+ apiRule.setParams(apiParams);
+
+ return apiRule;
+ }
+
+ @Override
+ public Optional<RuleDefinitionDto> findDtoByKey(RuleKey key) {
+ return Optional.ofNullable(this.ruleDtosByKey.get(key));
+ }
+
+ @Override
+ public Optional<RuleDefinitionDto> findDtoByUuid(String uuid) {
+ return Optional.ofNullable(this.ruleDtosByUuid.get(uuid));
+ }
+
+ @Override
+ public Collection<RuleDefinitionDto> findAll() {
+ return ruleDtosByUuid.values();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.rule;
+
+/**
+ * {@link ServerRuleFinder} implementation that supports caching used by the Web Server.
+ * <p>
+ * Caching is enabled right after loading of rules is done (see {@link RegisterRules}) and disabled
+ * once all startup tasks are done (see {@link org.sonar.server.platform.platformlevel.PlatformLevelStartup}).
+ * </p>
+ */
+public interface WebServerRuleFinder extends ServerRuleFinder {
+ /**
+ * Enable caching.
+ */
+ void startCaching();
+
+ /**
+ * Disable caching.
+ */
+ void stopCaching();
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.rule;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.util.Collection;
+import java.util.Optional;
+import javax.annotation.CheckForNull;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleQuery;
+import org.sonar.db.DbClient;
+import org.sonar.db.rule.RuleDefinitionDto;
+
+public class WebServerRuleFinderImpl implements WebServerRuleFinder {
+ private final DbClient dbClient;
+ private final ServerRuleFinder defaultFinder;
+ @VisibleForTesting
+ ServerRuleFinder delegate;
+
+ public WebServerRuleFinderImpl(DbClient dbClient) {
+ this.dbClient = dbClient;
+ this.defaultFinder = new DefaultRuleFinder(dbClient);
+ this.delegate = this.defaultFinder;
+ }
+
+ @Override
+ public void startCaching() {
+ this.delegate = new CachingRuleFinder(dbClient);
+ }
+
+ @Override
+ public void stopCaching() {
+ this.delegate = this.defaultFinder;
+ }
+
+ @Override
+ @CheckForNull
+ public Rule findByKey(String repositoryKey, String key) {
+ return delegate.findByKey(repositoryKey, key);
+ }
+
+ @Override
+ @CheckForNull
+ public Rule findByKey(RuleKey key) {
+ return delegate.findByKey(key);
+ }
+
+ @Override
+ @CheckForNull
+ public Rule find(RuleQuery query) {
+ return delegate.find(query);
+ }
+
+ @Override
+ public Collection<Rule> findAll(RuleQuery query) {
+ return delegate.findAll(query);
+ }
+
+ @Override
+ public Optional<RuleDefinitionDto> findDtoByKey(RuleKey key) {
+ return delegate.findDtoByKey(key);
+ }
+
+ @Override
+ public Optional<RuleDefinitionDto> findDtoByUuid(String uuid) {
+ return delegate.findDtoByUuid(uuid);
+ }
+
+ @Override
+ public Collection<RuleDefinitionDto> findAll() {
+ return delegate.findAll();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.plugins;
+
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.Plugin;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.db.DbTester;
+import org.sonar.db.plugin.PluginDto;
+import org.sonar.server.plugins.PluginFilesAndMd5.FileAndMd5;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class DetectPluginChangeTest {
+ @Rule
+ public DbTester dbTester = DbTester.create();
+
+ private final ServerPluginRepository pluginRepository = new ServerPluginRepository();
+ private final DetectPluginChange detectPluginChange = new DetectPluginChange(pluginRepository, dbTester.getDbClient());
+
+ @Test
+ public void detect_changed_plugin() {
+ addPluginToDb("plugin1", "hash1", PluginDto.Type.BUNDLED);
+ addPluginToFs("plugin1", "hash2", PluginType.BUNDLED);
+
+ detectPluginChange.start();
+ assertThat(detectPluginChange.anyPluginChanged()).isTrue();
+ }
+
+ @Test
+ public void detect_changed_type() {
+ addPluginToDb("plugin1", "hash1", PluginDto.Type.BUNDLED);
+ addPluginToFs("plugin1", "hash1", PluginType.EXTERNAL);
+
+ detectPluginChange.start();
+ assertThat(detectPluginChange.anyPluginChanged()).isTrue();
+ }
+
+ @Test
+ public void detect_new_plugin() {
+ addPluginToDb("plugin1", "hash1", PluginDto.Type.BUNDLED);
+ addPluginToFs("plugin2", "hash1", PluginType.BUNDLED);
+
+ detectPluginChange.start();
+ assertThat(detectPluginChange.anyPluginChanged()).isTrue();
+ }
+
+ @Ignore
+ @Test
+ public void detect_missing_plugin() {
+ // TODO
+ addPluginToDb("plugin1", "hash1", PluginDto.Type.BUNDLED);
+ addPluginToFs("plugin1", "hash1", PluginType.BUNDLED);
+
+ detectPluginChange.start();
+ assertThat(detectPluginChange.anyPluginChanged()).isTrue();
+ }
+
+ @Test
+ public void detect_no_changes_bundled() {
+ addPluginToDb("plugin1", "hash1", PluginDto.Type.BUNDLED);
+ addPluginToFs("plugin1", "hash1", PluginType.BUNDLED);
+ addPluginToDb("plugin2", "hash2", PluginDto.Type.EXTERNAL);
+ addPluginToFs("plugin2", "hash2", PluginType.EXTERNAL);
+
+ detectPluginChange.start();
+ assertThat(detectPluginChange.anyPluginChanged()).isFalse();
+ }
+
+ @Test
+ public void fail_if_start_twice() {
+ detectPluginChange.start();
+ assertThrows(IllegalStateException.class, detectPluginChange::start);
+ }
+
+ @Test
+ public void fail_if_not_started() {
+ assertThrows(NullPointerException.class, detectPluginChange::anyPluginChanged);
+ }
+
+ private void addPluginToDb(String key, String hash, PluginDto.Type type) {
+ dbTester.pluginDbTester().insertPlugin(p -> p.setKee(key).setFileHash(hash).setType(type));
+ }
+
+ private void addPluginToFs(String key, String hash, PluginType type) {
+ PluginInfo pluginInfo = new PluginInfo(key);
+ Plugin plugin = mock(Plugin.class);
+ FileAndMd5 fileAndMd5 = mock(FileAndMd5.class);
+ when(fileAndMd5.getMd5()).thenReturn(hash);
+ ServerPlugin serverPlugin = new ServerPlugin(pluginInfo, type, plugin, fileAndMd5, null);
+ pluginRepository.addPlugin(serverPlugin);
+ }
+
+}
/**
* Detect usage of an active admin account with default credential in order to ask this account to reset its password during authentication.
*/
-public class DefaultAdminCredentialsVerifierImpl implements Startable, DefaultAdminCredentialsVerifier {
+public class DefaultAdminCredentialsVerifierImpl implements DefaultAdminCredentialsVerifier {
private static final Logger LOGGER = Loggers.get(STARTUP_LOGGER_NAME);
this.notificationManager = notificationManager;
}
- @Override
- public void start() {
+ public void runAtStart() {
try (DbSession session = dbClient.openSession(false)) {
UserDto admin = getAdminUser(session);
if (admin == null || !isDefaultCredentialUser(session, admin)) {
}
}
+ @Override
public boolean hasDefaultCredentialUser() {
try (DbSession session = dbClient.openSession(false)) {
UserDto admin = getAdminUser(session);
notificationManager.scheduleForSending(new DefaultAdminCredentialsVerifierNotification());
dbClient.internalPropertiesDao().save(session, DEFAULT_ADMIN_CREDENTIAL_USAGE_EMAIL, Boolean.TRUE.toString());
}
-
- @Override
- public void stop() {
- // Nothing to do
- }
}
package org.sonar.server.qualityprofile;
import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleParamDto;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
+import org.sonar.server.rule.ServerRuleFinder;
import org.sonar.server.util.TypeValidations;
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.collect.Lists.newArrayList;
+import static java.util.Collections.emptySet;
import static java.util.Objects.requireNonNull;
public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert {
private final DbClient dbClient;
+ private final ServerRuleFinder ruleFinder;
private final System2 system2;
private final UuidFactory uuidFactory;
private final TypeValidations typeValidations;
private final ActiveRuleIndexer activeRuleIndexer;
private RuleRepository ruleRepository;
- public BuiltInQProfileInsertImpl(DbClient dbClient, System2 system2, UuidFactory uuidFactory, TypeValidations typeValidations, ActiveRuleIndexer activeRuleIndexer) {
+ public BuiltInQProfileInsertImpl(DbClient dbClient, ServerRuleFinder ruleFinder, System2 system2, UuidFactory uuidFactory,
+ TypeValidations typeValidations, ActiveRuleIndexer activeRuleIndexer) {
this.dbClient = dbClient;
+ this.ruleFinder = ruleFinder;
this.system2 = system2;
this.uuidFactory = uuidFactory;
this.typeValidations = typeValidations;
Date now = new Date(system2.now());
RulesProfileDto ruleProfile = insertRulesProfile(dbSession, builtInQProfile, now);
- List<ActiveRuleChange> changes = builtInQProfile.getActiveRules()
- .stream()
- .map(activeRule -> insertActiveRule(dbSession, ruleProfile, activeRule, now.getTime()))
+ List<ActiveRuleChange> changes = builtInQProfile.getActiveRules().stream()
+ .map(activeRule -> insertActiveRule(dbSession, batchDbSession, ruleProfile, activeRule, now.getTime()))
.collect(MoreCollectors.toList());
changes.forEach(change -> dbClient.qProfileChangeDao().insert(batchDbSession, change.toDto(null)));
activeRuleIndexer.commitAndIndex(dbSession, changes);
}
+
private void createDefaultAndOrgQProfiles(DbSession dbSession, DbSession batchDbSession, BuiltInQProfile builtIn, RulesProfileDto rulesProfileDto) {
Optional<String> qProfileUuid = dbClient.defaultQProfileDao().selectDefaultQProfileUuid(dbSession, builtIn.getLanguage());
.setRulesProfileUuid(rulesProfileDto.getUuid())
.setUuid(uuidFactory.create());
- if (builtIn.isDefault() && !qProfileUuid.isPresent()) {
+ if (builtIn.isDefault() && qProfileUuid.isEmpty()) {
DefaultQProfileDto defaultQProfileDto = new DefaultQProfileDto()
.setQProfileUuid(dto.getUuid())
.setLanguage(builtIn.getLanguage());
private void initRuleRepository(DbSession dbSession) {
if (ruleRepository == null) {
- ruleRepository = new RuleRepository(dbClient, dbSession);
+ ruleRepository = new RuleRepository(dbClient, dbSession, ruleFinder);
}
}
return dto;
}
- private ActiveRuleChange insertActiveRule(DbSession dbSession, RulesProfileDto rulesProfileDto, BuiltInQProfile.ActiveRule activeRule, long now) {
+ private ActiveRuleChange insertActiveRule(DbSession dbSession, DbSession batchDbSession, RulesProfileDto rulesProfileDto, BuiltInQProfile.ActiveRule activeRule, long now) {
RuleKey ruleKey = activeRule.getRuleKey();
RuleDefinitionDto ruleDefinitionDto = ruleRepository.getDefinition(ruleKey)
.orElseThrow(() -> new IllegalStateException("RuleDefinition not found for key " + ruleKey));
dto.setSeverity(firstNonNull(activeRule.getSeverity(), ruleDefinitionDto.getSeverityString()));
dto.setUpdatedAt(now);
dto.setCreatedAt(now);
- dbClient.activeRuleDao().insert(dbSession, dto);
+ dbClient.activeRuleDao().insert(batchDbSession, dto);
List<ActiveRuleParamDto> paramDtos = insertActiveRuleParams(dbSession, activeRule, dto);
return change;
}
- private List<ActiveRuleParamDto> insertActiveRuleParams(DbSession session, BuiltInQProfile.ActiveRule activeRule,
- ActiveRuleDto activeRuleDto) {
- Map<String, String> valuesByParamKey = activeRule.getParams()
- .stream()
+ private List<ActiveRuleParamDto> insertActiveRuleParams(DbSession session, BuiltInQProfile.ActiveRule activeRule, ActiveRuleDto activeRuleDto) {
+ Map<String, String> valuesByParamKey = activeRule.getParams().stream()
.collect(MoreCollectors.uniqueIndex(BuiltInQualityProfilesDefinition.OverriddenParam::key, BuiltInQualityProfilesDefinition.OverriddenParam::overriddenValue));
- List<ActiveRuleParamDto> rules = ruleRepository.getRuleParams(activeRule.getRuleKey())
- .stream()
+ List<ActiveRuleParamDto> rules = ruleRepository.getRuleParams(activeRule.getRuleKey()).stream()
.map(param -> createParamDto(param, Optional.ofNullable(valuesByParamKey.get(param.getName())).orElse(param.getDefaultValue())))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
private static class RuleRepository {
- private final Map<RuleKey, RuleDefinitionDto> definitions;
private final Map<RuleKey, Set<RuleParamDto>> params;
+ private final ServerRuleFinder ruleFinder;
+
+ private RuleRepository(DbClient dbClient, DbSession session, ServerRuleFinder ruleFinder) {
+ this.ruleFinder = ruleFinder;
+ this.params = new HashMap<>();
+
+ for (RuleParamDto ruleParam : dbClient.ruleDao().selectAllRuleParams(session)) {
+ Optional<RuleKey> ruleKey = ruleFinder.findDtoByUuid(ruleParam.getRuleUuid())
+ .map(r -> RuleKey.of(r.getRepositoryKey(), r.getRuleKey()));
- private RuleRepository(DbClient dbClient, DbSession session) {
- this.definitions = dbClient.ruleDao().selectAllDefinitions(session)
- .stream()
- .collect(Collectors.toMap(RuleDefinitionDto::getKey, Function.identity()));
- Map<String, RuleKey> ruleUuidsByKey = definitions.values()
- .stream()
- .collect(MoreCollectors.uniqueIndex(RuleDefinitionDto::getUuid, RuleDefinitionDto::getKey));
- this.params = new HashMap<>(ruleUuidsByKey.size());
- dbClient.ruleDao().selectRuleParamsByRuleKeys(session, definitions.keySet())
- .forEach(ruleParam -> params.compute(
- ruleUuidsByKey.get(ruleParam.getRuleUuid()),
- (key, value) -> {
- if (value == null) {
- return ImmutableSet.of(ruleParam);
- }
- return ImmutableSet.copyOf(Sets.union(value, Collections.singleton(ruleParam)));
- }));
+ if (ruleKey.isPresent()) {
+ params.computeIfAbsent(ruleKey.get(), r -> new HashSet<>()).add(ruleParam);
+ }
+ }
}
private Optional<RuleDefinitionDto> getDefinition(RuleKey ruleKey) {
- return Optional.ofNullable(definitions.get(requireNonNull(ruleKey, "RuleKey can't be null")));
+ return ruleFinder.findDtoByKey(requireNonNull(ruleKey, "RuleKey can't be null"));
}
private Set<RuleParamDto> getRuleParams(RuleKey ruleKey) {
- Set<RuleParamDto> res = params.get(requireNonNull(ruleKey, "RuleKey can't be null"));
- return res == null ? Collections.emptySet() : res;
+ return params.getOrDefault(requireNonNull(ruleKey, "RuleKey can't be null"), emptySet());
}
}
}
import org.sonar.db.DbSession;
import org.sonar.db.rule.DeprecatedRuleKeyDto;
import org.sonar.db.rule.RuleDefinitionDto;
+import org.sonar.server.rule.ServerRuleFinder;
import static com.google.common.base.Preconditions.checkState;
private static final String DEFAULT_PROFILE_NAME = "Sonar way";
private final DbClient dbClient;
+ private final ServerRuleFinder ruleFinder;
private final Languages languages;
private final List<BuiltInQualityProfilesDefinition> definitions;
private List<BuiltInQProfile> qProfiles;
/**
* Requires for pico container when no {@link BuiltInQualityProfilesDefinition} is defined at all
*/
- public BuiltInQProfileRepositoryImpl(DbClient dbClient, Languages languages) {
- this(dbClient, languages, new BuiltInQualityProfilesDefinition[0]);
+ public BuiltInQProfileRepositoryImpl(DbClient dbClient, ServerRuleFinder ruleFinder, Languages languages) {
+ this(dbClient, ruleFinder, languages, new BuiltInQualityProfilesDefinition[0]);
}
- public BuiltInQProfileRepositoryImpl(DbClient dbClient, Languages languages, BuiltInQualityProfilesDefinition... definitions) {
+ public BuiltInQProfileRepositoryImpl(DbClient dbClient, ServerRuleFinder ruleFinder, Languages languages, BuiltInQualityProfilesDefinition... definitions) {
this.dbClient = dbClient;
+ this.ruleFinder = ruleFinder;
this.languages = languages;
this.definitions = ImmutableList.copyOf(definitions);
}
private Map<RuleKey, RuleDefinitionDto> loadRuleDefinitionsByRuleKey() {
try (DbSession dbSession = dbClient.openSession(false)) {
- List<RuleDefinitionDto> ruleDefinitions = dbClient.ruleDao().selectAllDefinitions(dbSession);
+ Collection<RuleDefinitionDto> ruleDefinitions = ruleFinder.findAll();
Multimap<String, DeprecatedRuleKeyDto> deprecatedRuleKeysByRuleId = dbClient.ruleDao().selectAllDeprecatedRuleKeys(dbSession).stream()
.collect(MoreCollectors.index(DeprecatedRuleKeyDto::getRuleUuid));
Map<RuleKey, RuleDefinitionDto> rulesByRuleKey = new HashMap<>();
private final DefaultAdminCredentialsVerifierImpl underTest = new DefaultAdminCredentialsVerifierImpl(db.getDbClient(), localAuthentication, notificationManager);
- @After
- public void after() {
- underTest.stop();
- }
-
@Test
public void correctly_detect_if_admin_account_is_used_with_default_credential() {
UserDto admin = db.users().insertUser(u -> u.setLogin(ADMIN_LOGIN));
UserDto admin = db.users().insertUser(u -> u.setLogin(ADMIN_LOGIN));
changePassword(admin, "admin");
- underTest.start();
+ underTest.runAtStart();
assertThat(db.users().selectUserByLogin(admin.getLogin()).get().isResetPassword()).isTrue();
assertThat(logTester.logs(LoggerLevel.WARN)).contains("Default Administrator credentials are still being used. Make sure to change the password or deactivate the account.");
db.getDbClient().internalPropertiesDao().save(db.getSession(), DEFAULT_ADMIN_CREDENTIAL_USAGE_EMAIL, "true");
db.commit();
- underTest.start();
+ underTest.runAtStart();
verifyNoMoreInteractions(notificationManager);
}
UserDto admin = db.users().insertUser(u -> u.setLogin(ADMIN_LOGIN));
changePassword(admin, "something_else");
- underTest.start();
+ underTest.runAtStart();
assertThat(db.users().selectUserByLogin(admin.getLogin()).get().isResetPassword()).isFalse();
assertThat(logTester.logs()).isEmpty();
UserDto otherUser = db.users().insertUser();
changePassword(otherUser, "admin");
- underTest.start();
+ underTest.runAtStart();
assertThat(db.users().selectUserByLogin(otherUser.getLogin()).get().isResetPassword()).isFalse();
assertThat(logTester.logs()).isEmpty();
UserDto admin = db.users().insertUser(u -> u.setLogin(ADMIN_LOGIN).setActive(false));
changePassword(admin, "admin");
- underTest.start();
+ underTest.runAtStart();
assertThat(db.users().selectUserByLogin(admin.getLogin()).get().isResetPassword()).isFalse();
assertThat(logTester.logs()).isEmpty();
*/
package org.sonar.server.qualityprofile;
+import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.PropertyType;
import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.rule.Severity;
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
import org.sonar.db.qualityprofile.QProfileChangeQuery;
import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.db.rule.RuleDefinitionDto;
+import org.sonar.db.rule.RuleParamDto;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
+import org.sonar.server.rule.DefaultRuleFinder;
+import org.sonar.server.rule.ServerRuleFinder;
+import org.sonar.server.util.StringTypeValidation;
import org.sonar.server.util.TypeValidations;
-import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@Rule
public ExpectedException expectedException = ExpectedException.none();
- private System2 system2 = new AlwaysIncreasingSystem2();
- private UuidFactory uuidFactory = new SequenceUuidFactory();
- private TypeValidations typeValidations = new TypeValidations(emptyList());
- private DbSession dbSession = db.getSession();
- private DbSession batchDbSession = db.getDbClient().openSession(true);
- private ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class);
- private BuiltInQProfileInsertImpl underTest = new BuiltInQProfileInsertImpl(db.getDbClient(), system2, uuidFactory, typeValidations, activeRuleIndexer);
+ private final System2 system2 = new AlwaysIncreasingSystem2();
+ private final UuidFactory uuidFactory = new SequenceUuidFactory();
+ private final TypeValidations typeValidations = new TypeValidations(singletonList(new StringTypeValidation()));
+ private final DbSession dbSession = db.getSession();
+ private final DbSession batchDbSession = db.getDbClient().openSession(true);
+ private final ServerRuleFinder ruleFinder = new DefaultRuleFinder(db.getDbClient());
+ private final ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class);
+ private final BuiltInQProfileInsertImpl underTest = new BuiltInQProfileInsertImpl(db.getDbClient(), ruleFinder, system2, uuidFactory, typeValidations, activeRuleIndexer);
@After
public void tearDown() {
call(builtIn);
verifyTableSize("rules_profiles", 1);
+ verifyTableSize("org_qprofiles", 1);
verifyTableSize("active_rules", 2);
verifyTableSize("active_rule_parameters", 0);
verifyTableSize("qprofile_changes", 2);
+ verifyTableSize("default_qprofiles", 0);
+
QProfileDto profile = verifyProfileInDb(builtIn);
verifyActiveRuleInDb(profile, rule1, Severity.CRITICAL);
verifyActiveRuleInDb(profile, rule2, Severity.MAJOR);
}
+ @Test
+ public void insert_default_qp() {
+ BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
+ context.createBuiltInQualityProfile("the name", "xoo")
+ .setDefault(true)
+ .done();
+
+ BuiltInQProfile builtIn = builtInQProfileRepository.create(context.profile("xoo", "the name"));
+ call(builtIn);
+
+ verifyTableSize("rules_profiles", 1);
+ verifyTableSize("org_qprofiles", 1);
+ verifyTableSize("active_rules", 0);
+ verifyTableSize("active_rule_parameters", 0);
+ verifyTableSize("qprofile_changes", 0);
+ verifyTableSize("default_qprofiles", 1);
+
+ verifyProfileInDb(builtIn);
+ }
+
+ @Test
+ public void insert_active_rules_with_params() {
+ RuleDefinitionDto rule1 = db.rules().insert(r -> r.setLanguage("xoo"));
+ RuleParamDto param1 = db.rules().insertRuleParam(rule1, p -> p.setType(PropertyType.STRING.name()));
+ RuleParamDto param2 = db.rules().insertRuleParam(rule1, p -> p.setType(PropertyType.STRING.name()));
+
+ BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
+ NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("the name", "xoo");
+
+ newQp.activateRule(rule1.getRepositoryKey(), rule1.getRuleKey()).overrideSeverity(Severity.CRITICAL);
+ newQp.done();
+
+ BuiltInQProfile builtIn = builtInQProfileRepository.create(context.profile("xoo", "the name"), rule1);
+ call(builtIn);
+
+ verifyTableSize("rules_profiles", 1);
+ verifyTableSize("org_qprofiles", 1);
+ verifyTableSize("active_rules", 1);
+ verifyTableSize("active_rule_parameters", 2);
+ verifyTableSize("qprofile_changes", 1);
+
+ QProfileDto profile = verifyProfileInDb(builtIn);
+ verifyActiveRuleInDb(profile, rule1, Severity.CRITICAL, param1, param2);
+ }
+
@Test
public void flag_profile_as_default_if_declared_as_default_by_api() {
BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
QProfileDto defaultProfile = db.getDbClient().qualityProfileDao().selectDefaultProfile(dbSession, "xoo");
assertThat(defaultProfile.getKee()).isEqualTo(currentDefault.getKee());
+ verifyTableSize("rules_profiles", 2);
}
@Test
assertThat(defaultProfile).isNull();
}
- // TODO test params
// TODO test lot of active_rules, params, orgas
- private void verifyActiveRuleInDb(QProfileDto profile, RuleDefinitionDto rule, String expectedSeverity) {
+ private void verifyActiveRuleInDb(QProfileDto profile, RuleDefinitionDto rule, String expectedSeverity, RuleParamDto... paramDtos) {
ActiveRuleDto activeRule = db.getDbClient().activeRuleDao().selectByKey(dbSession, ActiveRuleKey.of(profile, rule.getKey())).get();
assertThat(activeRule.getUuid()).isNotNull();
assertThat(activeRule.getInheritance()).isNull();
assertThat(activeRule.getUpdatedAt()).isPositive();
List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleUuid(dbSession, activeRule.getUuid());
- assertThat(params).isEmpty();
+ assertThat(params).extracting(ActiveRuleParamDto::getKey).containsOnly(Arrays.stream(paramDtos).map(RuleParamDto::getName).toArray(String[]::new));
QProfileChangeQuery changeQuery = new QProfileChangeQuery(profile.getKee());
QProfileChangeDto change = db.getDbClient().qProfileChangeDao().selectByQuery(dbSession, changeQuery).stream()
*/
package org.sonar.server.qualityprofile;
-import java.util.ArrayList;
import java.util.List;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.db.DbTester;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.server.language.LanguageTesting;
+import org.sonar.server.rule.DefaultRuleFinder;
+import org.sonar.server.rule.ServerRuleFinder;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
@Rule
public DbTester db = DbTester.create();
- private DbClient dbClient = db.getDbClient();
+ private final DbClient dbClient = db.getDbClient();
+ private final ServerRuleFinder ruleFinder = new DefaultRuleFinder(dbClient);
@Test
public void create_qprofile_with_rule() {
RuleDefinitionDto rule1 = db.rules().insert();
RuleDefinitionDto rule2 = db.rules().insert();
db.rules().insert();
- List<DummyProfileDefinition> definitions = singletonList(new DummyProfileDefinition("foo", "foo", false,
- asList(rule1.getKey(), rule2.getKey())));
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), definitions.toArray(new BuiltInQualityProfilesDefinition[0]));
+ DummyProfileDefinition definition = new DummyProfileDefinition("foo", "foo", false, asList(rule1.getKey(), rule2.getKey()));
+ BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE), definition);
underTest.initialize();
@Test
public void make_single_profile_of_a_language_default_even_if_not_flagged_as_so() {
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), new DummyProfileDefinition("foo", "foo1", false));
+ BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE),
+ new DummyProfileDefinition("foo", "foo1", false));
underTest.initialize();
@Test
public void make_single_profile_of_a_language_default_even_if_flagged_as_so() {
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), new DummyProfileDefinition("foo", "foo1", true));
+ BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE),
+ new DummyProfileDefinition("foo", "foo1", true));
underTest.initialize();
@Test
public void make_first_profile_of_a_language_default_when_none_flagged_as_so() {
- List<DummyProfileDefinition> definitions = new ArrayList<>(
- asList(new DummyProfileDefinition("foo", "foo1", false), new DummyProfileDefinition("foo", "foo2", false)));
- String firstName = definitions.get(0).getName();
- String secondName = definitions.get(1).getName();
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), definitions.toArray(new BuiltInQualityProfilesDefinition[0]));
+ DummyProfileDefinition[] definitions = new DummyProfileDefinition[] {new DummyProfileDefinition("foo", "foo1", false), new DummyProfileDefinition("foo", "foo2", false)};
+ String firstName = definitions[0].getName();
+ String secondName = definitions[1].getName();
+ BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE), definitions);
underTest.initialize();
@Test
public void create_profile_Sonar_Way_as_default_if_none_other_is_defined_default_for_a_given_language() {
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(
- dbClient, new Languages(FOO_LANGUAGE),
+ dbClient, ruleFinder, new Languages(FOO_LANGUAGE),
new DummyProfileDefinition("foo", "doh", false), new DummyProfileDefinition("foo", "boo", false),
new DummyProfileDefinition("foo", SONAR_WAY_QP_NAME, false), new DummyProfileDefinition("foo", "goo", false));
@Test
public void do_not_create_Sonar_Way_as_default_if_other_profile_is_defined_as_default() {
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(
- dbClient, new Languages(FOO_LANGUAGE),
+ dbClient, ruleFinder, new Languages(FOO_LANGUAGE),
new DummyProfileDefinition("foo", SONAR_WAY_QP_NAME, false), new DummyProfileDefinition("foo", "goo", true));
underTest.initialize();
public void match_Sonar_Way_default_with_case_sensitivity() {
String sonarWayInOtherCase = SONAR_WAY_QP_NAME.toUpperCase();
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(
- dbClient, new Languages(FOO_LANGUAGE),
+ dbClient, ruleFinder, new Languages(FOO_LANGUAGE),
new DummyProfileDefinition("foo", "goo", false), new DummyProfileDefinition("foo", sonarWayInOtherCase, false));
underTest.initialize();
@Test
public void create_no_BuiltInQProfile_when_all_definitions_apply_to_non_defined_languages() {
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), new Languages(), new DummyProfileDefinition("foo", "P1", false));
+ BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), ruleFinder, new Languages(),
+ new DummyProfileDefinition("foo", "P1", false));
underTest.initialize();
RuleDefinitionDto rule1 = db.rules().insert();
db.rules().insertDeprecatedKey(d -> d.setRuleUuid(rule1.getUuid()).setOldRepositoryKey("oldRepo").setOldRuleKey("oldKey"));
RuleDefinitionDto rule2 = db.rules().insert();
- List<DummyProfileDefinition> definitions = singletonList(new DummyProfileDefinition("foo", "foo", false,
- asList(RuleKey.of("oldRepo", "oldKey"), rule2.getKey())));
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), definitions.toArray(new BuiltInQualityProfilesDefinition[0]));
+ DummyProfileDefinition definition = new DummyProfileDefinition("foo", "foo", false,
+ asList(RuleKey.of("oldRepo", "oldKey"), rule2.getKey()));
+ BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE), definition);
underTest.initialize();
@Test
public void fail_with_ISE_when_rule_does_not_exist() {
- List<DummyProfileDefinition> definitions = singletonList(new DummyProfileDefinition("foo", "foo", false, singletonList(EXTERNAL_XOO)));
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), definitions.toArray(new BuiltInQualityProfilesDefinition[0]));
+ DummyProfileDefinition[] definitions = new DummyProfileDefinition[] {new DummyProfileDefinition("foo", "foo", false, singletonList(EXTERNAL_XOO))};
+ BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE), definitions);
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage(String.format("Rule with key '%s' not found", EXTERNAL_XOO.toString()));
@Test
public void fail_with_ISE_when_two_profiles_with_different_name_are_default_for_the_same_language() {
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE),
+ BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE),
new DummyProfileDefinition("foo", "foo1", true), new DummyProfileDefinition("foo", "foo2", true));
-
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Several Quality profiles are flagged as default for the language foo: [foo1, foo2]");
@Test
public void get_throws_ISE_if_called_before_initialize() {
- BuiltInQProfileRepositoryImpl underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), new Languages());
+ BuiltInQProfileRepositoryImpl underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), ruleFinder, new Languages());
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("initialize must be called first");
@Test
public void initialize_throws_ISE_if_called_twice() {
- BuiltInQProfileRepositoryImpl underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), new Languages());
+ BuiltInQProfileRepositoryImpl underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), ruleFinder, new Languages());
underTest.initialize();
expectedException.expect(IllegalStateException.class);
@Test
public void initialize_throws_ISE_if_language_has_no_builtin_qp() {
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), new Languages(FOO_LANGUAGE));
+ BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), ruleFinder, new Languages(FOO_LANGUAGE));
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("The following languages have no built-in quality profiles: foo");
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2021 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.rule;
-
-import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ListMultimap;
-import com.google.common.collect.Ordering;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.rules.RulePriority;
-import org.sonar.api.rules.RuleQuery;
-import org.sonar.core.util.stream.MoreCollectors;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.rule.RuleDefinitionDto;
-import org.sonar.db.rule.RuleDto;
-import org.sonar.db.rule.RuleParamDto;
-import org.sonar.markdown.Markdown;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.sonar.core.util.stream.MoreCollectors.toSet;
-import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
-
-/**
- * A {@link RuleFinder} implementation that retrieves all rule definitions and their parameter when instantiated, cache
- * them in memory and provide implementation of {@link RuleFinder}'s method which only read from this data in memory.
- */
-public class CachingRuleFinder implements ServerRuleFinder {
-
- private static final Ordering<Map.Entry<RuleDefinitionDto, Rule>> FIND_BY_QUERY_ORDER = Ordering.natural().reverse().onResultOf(entry -> entry.getKey().getUpdatedAt());
-
- private final Map<RuleKey, RuleDefinitionDto> ruleDtosByKey;
- private final Map<RuleDefinitionDto, Rule> rulesByRuleDefinition;
- private final Map<RuleKey, Rule> rulesByKey;
-
- public CachingRuleFinder(DbClient dbClient) {
- try (DbSession dbSession = dbClient.openSession(false)) {
- List<RuleDefinitionDto> dtos = dbClient.ruleDao().selectAllDefinitions(dbSession);
- this.ruleDtosByKey = dtos.stream().collect(Collectors.toMap(RuleDefinitionDto::getKey, d -> d));
- this.rulesByRuleDefinition = buildRulesByRuleDefinitionDto(dbClient, dbSession, dtos);
- this.rulesByKey = this.rulesByRuleDefinition.entrySet().stream()
- .collect(uniqueIndex(entry -> entry.getKey().getKey(), Map.Entry::getValue));
- }
- }
-
- private static Map<RuleDefinitionDto, Rule> buildRulesByRuleDefinitionDto(DbClient dbClient, DbSession dbSession, List<RuleDefinitionDto> dtos) {
- Set<RuleKey> ruleKeys = dtos.stream().map(RuleDefinitionDto::getKey).collect(toSet(dtos.size()));
- ListMultimap<String, RuleParamDto> ruleParamsByRuleUuid = retrieveRuleParameters(dbClient, dbSession, ruleKeys);
- Map<RuleDefinitionDto, Rule> rulesByDefinition = new HashMap<>(dtos.size());
- for (RuleDefinitionDto definition : dtos) {
- rulesByDefinition.put(definition, toRule(definition, ruleParamsByRuleUuid.get(definition.getUuid())));
- }
- return ImmutableMap.copyOf(rulesByDefinition);
- }
-
- private static ImmutableListMultimap<String, RuleParamDto> retrieveRuleParameters(DbClient dbClient, DbSession dbSession, Set<RuleKey> ruleKeys) {
- if (ruleKeys.isEmpty()) {
- return ImmutableListMultimap.of();
- }
- return dbClient.ruleDao().selectRuleParamsByRuleKeys(dbSession, ruleKeys)
- .stream()
- .collect(MoreCollectors.index(RuleParamDto::getRuleUuid));
- }
-
- @Override
- @CheckForNull
- public Rule findByKey(@Nullable String repositoryKey, @Nullable String key) {
- if (repositoryKey == null || key == null) {
- return null;
- }
- return findByKey(RuleKey.of(repositoryKey, key));
- }
-
- @Override
- @CheckForNull
- public Rule findByKey(RuleKey key) {
- return rulesByKey.get(key);
- }
-
- @Override
- @CheckForNull
- public Rule find(@Nullable RuleQuery query) {
- if (query == null) {
- return null;
- }
-
- return rulesByRuleDefinition.entrySet().stream()
- .filter(entry -> matchQuery(entry.getKey(), query))
- .sorted(FIND_BY_QUERY_ORDER)
- .map(Map.Entry::getValue)
- .findFirst()
- .orElse(null);
- }
-
- @Override
- public Collection<Rule> findAll(@Nullable RuleQuery query) {
- if (query == null) {
- return Collections.emptyList();
- }
- return rulesByRuleDefinition.entrySet().stream()
- .filter(entry -> matchQuery(entry.getKey(), query))
- .sorted(FIND_BY_QUERY_ORDER)
- .map(Map.Entry::getValue)
- .collect(MoreCollectors.toList());
- }
-
- private static boolean matchQuery(RuleDefinitionDto ruleDefinition, RuleQuery ruleQuery) {
- if (RuleStatus.REMOVED.equals(ruleDefinition.getStatus())) {
- return false;
- }
- String repositoryKey = ruleQuery.getRepositoryKey();
- if (ruleQuery.getRepositoryKey() != null && !repositoryKey.equals(ruleDefinition.getRepositoryKey())) {
- return false;
- }
- String key = ruleQuery.getKey();
- if (key != null && !key.equals(ruleDefinition.getRuleKey())) {
- return false;
- }
- String configKey = ruleQuery.getConfigKey();
- return configKey == null || configKey.equals(ruleDefinition.getConfigKey());
- }
-
- private static Rule toRule(RuleDefinitionDto ruleDefinition, List<RuleParamDto> params) {
- String severity = ruleDefinition.getSeverityString();
- String description = ruleDefinition.getDescription();
- RuleDto.Format descriptionFormat = ruleDefinition.getDescriptionFormat();
-
- Rule apiRule = new Rule();
- apiRule
- .setName(ruleDefinition.getName())
- .setLanguage(ruleDefinition.getLanguage())
- .setKey(ruleDefinition.getRuleKey())
- .setConfigKey(ruleDefinition.getConfigKey())
- .setIsTemplate(ruleDefinition.isTemplate())
- .setCreatedAt(new Date(ruleDefinition.getCreatedAt()))
- .setUpdatedAt(new Date(ruleDefinition.getUpdatedAt()))
- .setRepositoryKey(ruleDefinition.getRepositoryKey())
- .setSeverity(severity != null ? RulePriority.valueOf(severity) : null)
- .setStatus(ruleDefinition.getStatus().name())
- .setSystemTags(ruleDefinition.getSystemTags().toArray(new String[ruleDefinition.getSystemTags().size()]))
- .setTags(new String[0]);
- if (description != null && descriptionFormat != null) {
- if (RuleDto.Format.HTML.equals(descriptionFormat)) {
- apiRule.setDescription(description);
- } else {
- apiRule.setDescription(Markdown.convertToHtml(description));
- }
- }
-
- List<org.sonar.api.rules.RuleParam> apiParams = newArrayList();
- for (RuleParamDto param : params) {
- apiParams.add(new org.sonar.api.rules.RuleParam(apiRule, param.getName(), param.getDescription(), param.getType())
- .setDefaultValue(param.getDefaultValue()));
- }
- apiRule.setParams(apiParams);
-
- return apiRule;
- }
-
- @Override
- public Optional<RuleDefinitionDto> findDtoByKey(RuleKey key) {
- return Optional.ofNullable(this.ruleDtosByKey.get(key));
- }
-}
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nullable;
-import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.picocontainer.Startable;
import org.sonar.api.resources.Languages;
import static com.google.common.collect.Sets.difference;
import static com.google.common.collect.Sets.intersection;
import static java.lang.String.format;
+import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
+import static java.util.Collections.unmodifiableMap;
import static org.sonar.core.util.stream.MoreCollectors.toList;
import static org.sonar.core.util.stream.MoreCollectors.toSet;
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
@Override
public void start() {
Profiler profiler = Profiler.create(LOG).startInfo("Register rules");
- try (DbSession dbSession = dbClient.openSession(false)) {
+ try (DbSession dbSession = dbClient.openSession(true)) {
RulesDefinition.Context ruleDefinitionContext = defLoader.load();
List<RulesDefinition.Repository> repositories = ruleDefinitionContext.repositories();
RegisterRulesContext registerRulesContext = createRegisterRulesContext(dbSession);
for (RulesDefinition.ExtendedRepository repoDef : repositories) {
if (languages.get(repoDef.language()) != null) {
- for (RulesDefinition.Rule ruleDef : repoDef.rules()) {
- registerRule(registerRulesContext, ruleDef, dbSession);
- }
+ registerRules(registerRulesContext, repoDef.rules(), dbSession);
dbSession.commit();
}
}
Map<RuleKey, RuleDefinitionDto> allRules = dbClient.ruleDao().selectAllDefinitions(dbSession).stream()
.collect(uniqueIndex(RuleDefinitionDto::getKey));
Map<String, Set<SingleDeprecatedRuleKey>> existingDeprecatedKeysById = loadDeprecatedRuleKeys(dbSession);
- return new RegisterRulesContext(allRules, existingDeprecatedKeysById);
+ Map<String, List<RuleParamDto>> ruleParamsByRuleUuid = loadAllRuleParameters(dbSession);
+ return new RegisterRulesContext(allRules, existingDeprecatedKeysById, ruleParamsByRuleUuid);
+ }
+
+ private Map<String, List<RuleParamDto>> loadAllRuleParameters(DbSession dbSession) {
+ return dbClient.ruleDao().selectAllRuleParams(dbSession).stream()
+ .collect(Collectors.groupingBy(RuleParamDto::getRuleUuid));
}
private Map<String, Set<SingleDeprecatedRuleKey>> loadDeprecatedRuleKeys(DbSession dbSession) {
private final Map<RuleKey, RuleDefinitionDto> dbRules;
private final Set<RuleDefinitionDto> known;
private final Map<String, Set<SingleDeprecatedRuleKey>> dbDeprecatedKeysByUuid;
+ private final Map<String, List<RuleParamDto>> ruleParamsByRuleUuid;
private final Map<RuleKey, RuleDefinitionDto> dbRulesByDbDeprecatedKey;
// mutable data
private final Set<RuleDefinitionDto> created = new HashSet<>();
private final Set<RuleDefinitionDto> unchanged = new HashSet<>();
private final Set<RuleDefinitionDto> removed = new HashSet<>();
- private RegisterRulesContext(Map<RuleKey, RuleDefinitionDto> dbRules, Map<String, Set<SingleDeprecatedRuleKey>> dbDeprecatedKeysByUuid) {
+ private RegisterRulesContext(Map<RuleKey, RuleDefinitionDto> dbRules, Map<String, Set<SingleDeprecatedRuleKey>> dbDeprecatedKeysByUuid,
+ Map<String, List<RuleParamDto>> ruleParamsByRuleUuid) {
this.dbRules = ImmutableMap.copyOf(dbRules);
this.known = ImmutableSet.copyOf(dbRules.values());
this.dbDeprecatedKeysByUuid = dbDeprecatedKeysByUuid;
+ this.ruleParamsByRuleUuid = ruleParamsByRuleUuid;
this.dbRulesByDbDeprecatedKey = buildDbRulesByDbDeprecatedKey(dbDeprecatedKeysByUuid, dbRules);
}
Map<String, RuleDefinitionDto> dbRulesByRuleUuid = dbRules.values().stream()
.collect(uniqueIndex(RuleDefinitionDto::getUuid));
- ImmutableMap.Builder<RuleKey, RuleDefinitionDto> builder = ImmutableMap.builder();
+ Map<RuleKey, RuleDefinitionDto> rulesByKey = new LinkedHashMap<>();
for (Map.Entry<String, Set<SingleDeprecatedRuleKey>> entry : dbDeprecatedKeysByUuid.entrySet()) {
String ruleUuid = entry.getKey();
RuleDefinitionDto rule = dbRulesByRuleUuid.get(ruleUuid);
if (rule == null) {
LOG.warn("Could not retrieve rule with uuid %s referenced by a deprecated rule key. " +
- "The following deprecated rule keys seem to be referencing a non-existing rule",
+ "The following deprecated rule keys seem to be referencing a non-existing rule",
ruleUuid, entry.getValue());
} else {
- entry.getValue().forEach(d -> builder.put(d.getOldRuleKeyAsRuleKey(), rule));
+ entry.getValue().forEach(d -> rulesByKey.put(d.getOldRuleKeyAsRuleKey(), rule));
}
}
- return builder.build();
+ return unmodifiableMap(rulesByKey);
}
private boolean hasDbRules() {
return res;
}
- private ImmutableMap<RuleKey, SingleDeprecatedRuleKey> getDbDeprecatedKeysByOldRuleKey() {
+ private Map<RuleKey, SingleDeprecatedRuleKey> getDbDeprecatedKeysByOldRuleKey() {
return dbDeprecatedKeysByUuid.values().stream()
.flatMap(Collection::stream)
.collect(uniqueIndex(SingleDeprecatedRuleKey::getOldRuleKeyAsRuleKey));
return dbDeprecatedKeysByUuid.getOrDefault(rule.getUuid(), emptySet());
}
+ private List<RuleParamDto> getRuleParametersFor(String ruleUuid) {
+ return ruleParamsByRuleUuid.getOrDefault(ruleUuid, emptyList());
+ }
+
private Stream<RuleDefinitionDto> getRemaining() {
Set<RuleDefinitionDto> res = new HashSet<>(dbRules.values());
res.removeAll(unchanged);
}
private void persistRepositories(DbSession dbSession, List<RulesDefinition.Repository> repositories) {
- List<RuleRepositoryDto> dtos = repositories
- .stream()
+ List<RuleRepositoryDto> dtos = repositories.stream()
.map(r -> new RuleRepositoryDto(r.key(), r.language(), r.name()))
.collect(toList(repositories.size()));
List<String> keys = dtos.stream().map(RuleRepositoryDto::getKey).collect(toList(repositories.size()));
// nothing
}
- private void registerRule(RegisterRulesContext context, RulesDefinition.Rule ruleDef, DbSession session) {
- RuleKey ruleKey = RuleKey.of(ruleDef.repository().key(), ruleDef.key());
+ private void registerRules(RegisterRulesContext context, List<RulesDefinition.Rule> ruleDefs, DbSession session) {
+ Map<RulesDefinition.Rule, RuleDefinitionDto> dtos = new LinkedHashMap<>(ruleDefs.size());
- RuleDefinitionDto ruleDefinitionDto = context.getDbRuleFor(ruleDef)
- .orElseGet(() -> {
- RuleDefinitionDto newRule = createRuleDto(ruleDef, session);
- context.created(newRule);
- return newRule;
- });
+ for (RulesDefinition.Rule ruleDef : ruleDefs) {
+ RuleKey ruleKey = RuleKey.of(ruleDef.repository().key(), ruleDef.key());
- // we must detect renaming __before__ we modify the DTO
- if (!ruleDefinitionDto.getKey().equals(ruleKey)) {
- context.renamed(ruleDefinitionDto);
- ruleDefinitionDto.setRuleKey(ruleKey);
- }
+ RuleDefinitionDto ruleDefinitionDto = context.getDbRuleFor(ruleDef)
+ .orElseGet(() -> {
+ RuleDefinitionDto newRule = createRuleDto(ruleDef, session);
+ context.created(newRule);
+ return newRule;
+ });
+ dtos.put(ruleDef, ruleDefinitionDto);
+
+ // we must detect renaming __before__ we modify the DTO
+ if (!ruleDefinitionDto.getKey().equals(ruleKey)) {
+ context.renamed(ruleDefinitionDto);
+ ruleDefinitionDto.setRuleKey(ruleKey);
+ }
- if (mergeRule(ruleDef, ruleDefinitionDto)) {
- context.updated(ruleDefinitionDto);
- }
+ if (mergeRule(ruleDef, ruleDefinitionDto)) {
+ context.updated(ruleDefinitionDto);
+ }
- if (mergeDebtDefinitions(ruleDef, ruleDefinitionDto)) {
- context.updated(ruleDefinitionDto);
- }
+ if (mergeDebtDefinitions(ruleDef, ruleDefinitionDto)) {
+ context.updated(ruleDefinitionDto);
+ }
- if (mergeTags(ruleDef, ruleDefinitionDto)) {
- context.updated(ruleDefinitionDto);
- }
+ if (mergeTags(ruleDef, ruleDefinitionDto)) {
+ context.updated(ruleDefinitionDto);
+ }
- if (mergeSecurityStandards(ruleDef, ruleDefinitionDto)) {
- context.updated(ruleDefinitionDto);
- }
+ if (mergeSecurityStandards(ruleDef, ruleDefinitionDto)) {
+ context.updated(ruleDefinitionDto);
+ }
- if (context.isUpdated(ruleDefinitionDto) || context.isRenamed(ruleDefinitionDto)) {
- update(session, ruleDefinitionDto);
- } else if (!context.isCreated(ruleDefinitionDto)) {
- context.unchanged(ruleDefinitionDto);
+ if (context.isUpdated(ruleDefinitionDto) || context.isRenamed(ruleDefinitionDto)) {
+ update(session, ruleDefinitionDto);
+ } else if (!context.isCreated(ruleDefinitionDto)) {
+ context.unchanged(ruleDefinitionDto);
+ }
}
- mergeParams(ruleDef, ruleDefinitionDto, session);
- updateDeprecatedKeys(context, ruleDef, ruleDefinitionDto, session);
+ for (Map.Entry<RulesDefinition.Rule, RuleDefinitionDto> e : dtos.entrySet()) {
+ mergeParams(context, e.getKey(), e.getValue(), session);
+ updateDeprecatedKeys(context, e.getKey(), e.getValue(), session);
+ }
}
private RuleDefinitionDto createRuleDto(RulesDefinition.Rule ruleDef, DbSession session) {
private static boolean mergeRule(RulesDefinition.Rule def, RuleDefinitionDto dto) {
boolean changed = false;
- if (!StringUtils.equals(dto.getName(), def.name())) {
+ if (!Objects.equals(dto.getName(), def.name())) {
dto.setName(def.name());
changed = true;
}
if (mergeDescription(def, dto)) {
changed = true;
}
- if (!StringUtils.equals(dto.getPluginKey(), def.pluginKey())) {
+ if (!Objects.equals(dto.getPluginKey(), def.pluginKey())) {
dto.setPluginKey(def.pluginKey());
changed = true;
}
- if (!StringUtils.equals(dto.getConfigKey(), def.internalKey())) {
+ if (!Objects.equals(dto.getConfigKey(), def.internalKey())) {
dto.setConfigKey(def.internalKey());
changed = true;
}
String severity = def.severity();
- if (!ObjectUtils.equals(dto.getSeverityString(), severity)) {
+ if (!Objects.equals(dto.getSeverityString(), severity)) {
dto.setSeverity(severity);
changed = true;
}
dto.setStatus(def.status());
changed = true;
}
- if (!StringUtils.equals(dto.getScope().name(), def.scope().name())) {
+ if (!Objects.equals(dto.getScope().name(), def.scope().name())) {
dto.setScope(toDtoScope(def.scope()));
changed = true;
}
- if (!StringUtils.equals(dto.getLanguage(), def.repository().language())) {
+ if (!Objects.equals(dto.getLanguage(), def.repository().language())) {
dto.setLanguage(def.repository().language());
changed = true;
}
RuleType type = RuleType.valueOf(def.type().name());
- if (!ObjectUtils.equals(dto.getType(), type.getDbConstant())) {
+ if (!Objects.equals(dto.getType(), type.getDbConstant())) {
dto.setType(type);
changed = true;
}
private static boolean mergeDescription(RulesDefinition.Rule def, RuleDefinitionDto dto) {
boolean changed = false;
- if (def.htmlDescription() != null && !StringUtils.equals(dto.getDescription(), def.htmlDescription())) {
+ if (def.htmlDescription() != null && !Objects.equals(dto.getDescription(), def.htmlDescription())) {
dto.setDescription(def.htmlDescription());
dto.setDescriptionFormat(Format.HTML);
changed = true;
- } else if (def.markdownDescription() != null && !StringUtils.equals(dto.getDescription(), def.markdownDescription())) {
+ } else if (def.markdownDescription() != null && !Objects.equals(dto.getDescription(), def.markdownDescription())) {
dto.setDescription(def.markdownDescription());
dto.setDescriptionFormat(Format.MARKDOWN);
changed = true;
@Nullable String remediationCoefficient, @Nullable String remediationOffset, @Nullable String effortToFixDescription) {
boolean changed = false;
- if (!StringUtils.equals(dto.getDefRemediationFunction(), remediationFunction)) {
+ if (!Objects.equals(dto.getDefRemediationFunction(), remediationFunction)) {
dto.setDefRemediationFunction(remediationFunction);
changed = true;
}
- if (!StringUtils.equals(dto.getDefRemediationGapMultiplier(), remediationCoefficient)) {
+ if (!Objects.equals(dto.getDefRemediationGapMultiplier(), remediationCoefficient)) {
dto.setDefRemediationGapMultiplier(remediationCoefficient);
changed = true;
}
- if (!StringUtils.equals(dto.getDefRemediationBaseEffort(), remediationOffset)) {
+ if (!Objects.equals(dto.getDefRemediationBaseEffort(), remediationOffset)) {
dto.setDefRemediationBaseEffort(remediationOffset);
changed = true;
}
- if (!StringUtils.equals(dto.getGapDescription(), effortToFixDescription)) {
+ if (!Objects.equals(dto.getGapDescription(), effortToFixDescription)) {
dto.setGapDescription(effortToFixDescription);
changed = true;
}
return changed;
}
- private void mergeParams(RulesDefinition.Rule ruleDef, RuleDefinitionDto rule, DbSession session) {
- List<RuleParamDto> paramDtos = dbClient.ruleDao().selectRuleParamsByRuleKey(session, rule.getKey());
+ private void mergeParams(RegisterRulesContext context, RulesDefinition.Rule ruleDef, RuleDefinitionDto rule, DbSession session) {
+ List<RuleParamDto> paramDtos = context.getRuleParametersFor(rule.getUuid());
Map<String, RuleParamDto> existingParamsByName = new HashMap<>();
Profiler profiler = Profiler.create(Loggers.get(getClass()));
private static boolean mergeParam(RuleParamDto paramDto, RulesDefinition.Param paramDef) {
boolean changed = false;
- if (!StringUtils.equals(paramDto.getType(), paramDef.type().toString())) {
+ if (!Objects.equals(paramDto.getType(), paramDef.type().toString())) {
paramDto.setType(paramDef.type().toString());
changed = true;
}
- if (!StringUtils.equals(paramDto.getDefaultValue(), paramDef.defaultValue())) {
+ if (!Objects.equals(paramDto.getDefaultValue(), paramDef.defaultValue())) {
paramDto.setDefaultValue(paramDef.defaultValue());
changed = true;
}
- if (!StringUtils.equals(paramDto.getDescription(), paramDef.description())) {
+ if (!Objects.equals(paramDto.getDescription(), paramDef.description())) {
paramDto.setDescription(paramDef.description());
changed = true;
}
return changed;
}
- private void updateDeprecatedKeys(RegisterRulesContext context, RulesDefinition.Rule ruleDef, RuleDefinitionDto rule,
- DbSession dbSession) {
+ private void updateDeprecatedKeys(RegisterRulesContext context, RulesDefinition.Rule ruleDef, RuleDefinitionDto rule, DbSession dbSession) {
Set<SingleDeprecatedRuleKey> deprecatedRuleKeysFromDefinition = SingleDeprecatedRuleKey.from(ruleDef);
Set<SingleDeprecatedRuleKey> deprecatedRuleKeysFromDB = context.getDBDeprecatedKeysFor(rule);
changed = true;
} else if (dto.getSystemTags().size() != ruleDef.tags().size() ||
!dto.getSystemTags().containsAll(ruleDef.tags())) {
- dto.setSystemTags(ruleDef.tags());
- changed = true;
- }
+ dto.setSystemTags(ruleDef.tags());
+ changed = true;
+ }
return changed;
}
changed = true;
} else if (dto.getSecurityStandards().size() != ruleDef.securityStandards().size() ||
!dto.getSecurityStandards().containsAll(ruleDef.securityStandards())) {
- dto.setSecurityStandards(ruleDef.securityStandards());
- changed = true;
- }
+ dto.setSecurityStandards(ruleDef.securityStandards());
+ changed = true;
+ }
return changed;
}
private static boolean updateCustomRuleFromTemplateRule(RuleDefinitionDto customRule, RuleDefinitionDto templateRule) {
boolean changed = false;
- if (!StringUtils.equals(customRule.getLanguage(), templateRule.getLanguage())) {
+ if (!Objects.equals(customRule.getLanguage(), templateRule.getLanguage())) {
customRule.setLanguage(templateRule.getLanguage());
changed = true;
}
- if (!StringUtils.equals(customRule.getConfigKey(), templateRule.getConfigKey())) {
+ if (!Objects.equals(customRule.getConfigKey(), templateRule.getConfigKey())) {
customRule.setConfigKey(templateRule.getConfigKey());
changed = true;
}
- if (!StringUtils.equals(customRule.getPluginKey(), templateRule.getPluginKey())) {
+ if (!Objects.equals(customRule.getPluginKey(), templateRule.getPluginKey())) {
customRule.setPluginKey(templateRule.getPluginKey());
changed = true;
}
- if (!StringUtils.equals(customRule.getDefRemediationFunction(), templateRule.getDefRemediationFunction())) {
+ if (!Objects.equals(customRule.getDefRemediationFunction(), templateRule.getDefRemediationFunction())) {
customRule.setDefRemediationFunction(templateRule.getDefRemediationFunction());
changed = true;
}
- if (!StringUtils.equals(customRule.getDefRemediationGapMultiplier(), templateRule.getDefRemediationGapMultiplier())) {
+ if (!Objects.equals(customRule.getDefRemediationGapMultiplier(), templateRule.getDefRemediationGapMultiplier())) {
customRule.setDefRemediationGapMultiplier(templateRule.getDefRemediationGapMultiplier());
changed = true;
}
- if (!StringUtils.equals(customRule.getDefRemediationBaseEffort(), templateRule.getDefRemediationBaseEffort())) {
+ if (!Objects.equals(customRule.getDefRemediationBaseEffort(), templateRule.getDefRemediationBaseEffort())) {
customRule.setDefRemediationBaseEffort(templateRule.getDefRemediationBaseEffort());
changed = true;
}
- if (!StringUtils.equals(customRule.getGapDescription(), templateRule.getGapDescription())) {
+ if (!Objects.equals(customRule.getGapDescription(), templateRule.getGapDescription())) {
customRule.setGapDescription(templateRule.getGapDescription());
changed = true;
}
customRule.setStatus(templateRule.getStatus());
changed = true;
}
- if (!StringUtils.equals(customRule.getSeverityString(), templateRule.getSeverityString())) {
+ if (!Objects.equals(customRule.getSeverityString(), templateRule.getSeverityString())) {
customRule.setSeverity(templateRule.getSeverityString());
changed = true;
}
- if (!StringUtils.equals(customRule.getRepositoryKey(), templateRule.getRepositoryKey())) {
+ if (!Objects.equals(customRule.getRepositoryKey(), templateRule.getRepositoryKey())) {
customRule.setRepositoryKey(templateRule.getRepositoryKey());
changed = true;
}
lazyToString(() -> intersection.stream().map(RuleKey::toString).collect(Collectors.joining(","))));
// Find incorrect usage of deprecated keys
- ImmutableMap<RuleKey, SingleDeprecatedRuleKey> dbDeprecatedRuleKeysByOldRuleKey = registerRulesContext.getDbDeprecatedKeysByOldRuleKey();
+ Map<RuleKey, SingleDeprecatedRuleKey> dbDeprecatedRuleKeysByOldRuleKey = registerRulesContext.getDbDeprecatedKeysByOldRuleKey();
Set<String> incorrectRuleKeyMessage = definedRules.stream()
.flatMap(r -> filterInvalidDeprecatedRuleKeys(dbDeprecatedRuleKeysByOldRuleKey, r))
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2021 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.rule;
-
-/**
- * {@link ServerRuleFinder} implementation that supports caching used by the Web Server.
- * <p>
- * Caching is enabled right after loading of rules is done (see {@link RegisterRules}) and disabled
- * once all startup tasks are done (see {@link org.sonar.server.platform.platformlevel.PlatformLevelStartup}).
- * </p>
- */
-public interface WebServerRuleFinder extends ServerRuleFinder {
- /**
- * Enable caching.
- */
- void startCaching();
-
- /**
- * Disable caching.
- */
- void stopCaching();
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2021 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.rule;
-
-import com.google.common.annotations.VisibleForTesting;
-import java.util.Collection;
-import java.util.Optional;
-import javax.annotation.CheckForNull;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleQuery;
-import org.sonar.db.DbClient;
-import org.sonar.db.rule.RuleDefinitionDto;
-
-public class WebServerRuleFinderImpl implements WebServerRuleFinder {
- private final DbClient dbClient;
- private final ServerRuleFinder defaultFinder;
- @VisibleForTesting
- ServerRuleFinder delegate;
-
- public WebServerRuleFinderImpl(DbClient dbClient) {
- this.dbClient = dbClient;
- this.defaultFinder = new DefaultRuleFinder(dbClient);
- this.delegate = this.defaultFinder;
- }
-
- @Override
- public void startCaching() {
- this.delegate = new CachingRuleFinder(dbClient);
- }
-
- @Override
- public void stopCaching() {
- this.delegate = this.defaultFinder;
- }
-
- @Override
- @CheckForNull
- public Rule findByKey(String repositoryKey, String key) {
- return delegate.findByKey(repositoryKey, key);
- }
-
- @Override
- @CheckForNull
- public Rule findByKey(RuleKey key) {
- return delegate.findByKey(key);
- }
-
- @Override
- @CheckForNull
- public Rule find(RuleQuery query) {
- return delegate.find(query);
- }
-
- @Override
- public Collection<Rule> findAll(RuleQuery query) {
- return delegate.findAll(query);
- }
-
- @Override
- public Optional<RuleDefinitionDto> findDtoByKey(RuleKey key) {
- return delegate.findDtoByKey(key);
- }
-}
*/
package org.sonar.server.startup;
-import static com.google.common.collect.FluentIterable.concat;
-import static com.google.common.collect.Lists.newArrayList;
-
import com.google.common.annotations.VisibleForTesting;
import java.util.HashMap;
import java.util.List;
import org.sonar.db.metric.MetricDto;
import org.sonar.server.metric.MetricToDto;
+import static com.google.common.collect.FluentIterable.concat;
+import static com.google.common.collect.Lists.newArrayList;
+
public class RegisterMetrics implements Startable {
private static final Logger LOG = Loggers.get(RegisterMetrics.class);
void register(Iterable<Metric> metrics) {
Profiler profiler = Profiler.create(LOG).startInfo("Register metrics");
- try (DbSession session = dbClient.openSession(false)) {
+ try (DbSession session = dbClient.openSession(true)) {
save(session, metrics);
sanitizeQualityGates(session);
session.commit();
verify(dbClient).openSession(anyBoolean());
verify(ruleDao).selectAllDefinitions(dbSession);
+ verify(ruleDao).selectAllRuleParams(dbSession);
verifyNoMoreInteractions(ruleDao);
}
new CachingRuleFinder(dbClient);
- verify(ruleDao).selectRuleParamsByRuleKeys(dbSession, ImmutableSet.copyOf(ruleKeys));
+ verify(ruleDao).selectAllRuleParams(dbSession);
}
@Test
private static final RuleKey RULE_KEY3 = RuleKey.of("fake", "rule3");
private static final RuleKey HOTSPOT_RULE_KEY = RuleKey.of("fake", "hotspot");
- private TestSystem2 system = new TestSystem2().setNow(DATE1.getTime());
+ private final TestSystem2 system = new TestSystem2().setNow(DATE1.getTime());
@org.junit.Rule
public ExpectedException expectedException = ExpectedException.none();
@org.junit.Rule
public LogTester logTester = new LogTester();
- private QProfileRules qProfileRules = mock(QProfileRules.class);
- private WebServerRuleFinder webServerRuleFinder = mock(WebServerRuleFinder.class);
- private DbClient dbClient = db.getDbClient();
+ private final QProfileRules qProfileRules = mock(QProfileRules.class);
+ private final WebServerRuleFinder webServerRuleFinder = mock(WebServerRuleFinder.class);
+ private final DbClient dbClient = db.getDbClient();
+ private final MetadataIndex metadataIndex = mock(MetadataIndex.class);
+ private final UuidFactory uuidFactory = UuidFactoryFast.getInstance();
+
private RuleIndexer ruleIndexer;
private ActiveRuleIndexer activeRuleIndexer;
private RuleIndex ruleIndex;
- private MetadataIndex metadataIndex = mock(MetadataIndex.class);
- private UuidFactory uuidFactory = UuidFactoryFast.getInstance();
+
@Before
public void before() {
}
@SafeVarargs
- private final void createRule(RulesDefinition.Context context, String language, String repositoryKey, String ruleKey, Consumer<NewRule>... consumers) {
+ private void createRule(RulesDefinition.Context context, String language, String repositoryKey, String ruleKey, Consumer<NewRule>... consumers) {
NewRepository repo = context.createRepository(repositoryKey, language);
NewRule newRule = repo.createRule(ruleKey)
.setName(ruleKey)
@Rule
public DbTester dbTester = DbTester.create(System2.INSTANCE);
- private UuidFactory uuidFactory = new SequenceUuidFactory();
- private DbClient dbClient = dbTester.getDbClient();
+ private final UuidFactory uuidFactory = new SequenceUuidFactory();
+ private final DbClient dbClient = dbTester.getDbClient();
+ private final RegisterMetrics register = new RegisterMetrics(dbClient, uuidFactory);
/**
* Insert new metrics, including custom metrics
.setUserManaged(true)
.create();
- RegisterMetrics register = new RegisterMetrics(dbClient, uuidFactory);
register.register(asList(m1, custom));
Map<String, MetricDto> metricsByKey = selectAllMetrics();
.setDirection(1)
.setHidden(false));
- RegisterMetrics register = new RegisterMetrics(dbClient, uuidFactory);
Metric m1 = new Metric.Builder("m1", "New name", Metric.ValueType.FLOAT)
.setDescription("new description")
.setDirection(-1)
IntStream.range(0, count)
.forEach(t -> dbTester.measures().insertMetric(m -> m.setEnabled(random.nextBoolean())));
- RegisterMetrics register = new RegisterMetrics(dbClient, uuidFactory);
register.register(Collections.emptyList());
assertThat(selectAllMetrics().values().stream())
MetricDto enabledMetric = dbTester.measures().insertMetric(t -> t.setEnabled(true));
MetricDto disabledMetric = dbTester.measures().insertMetric(t -> t.setEnabled(false));
- RegisterMetrics register = new RegisterMetrics(dbClient, uuidFactory);
register.register(asList(builderOf(enabledMetric).create(), builderOf(disabledMetric).create()));
assertThat(selectAllMetrics().values())
@Test
public void insert_core_metrics() {
- RegisterMetrics register = new RegisterMetrics(dbClient, uuidFactory);
register.start();
assertThat(dbTester.countRowsOfTable("metrics")).isEqualTo(CoreMetrics.getMetrics().size());
private final UuidFactory uuidFactory;
private final System2 system2;
- public RegisterQualityGates(DbClient dbClient,
- QualityGateConditionsUpdater qualityGateConditionsUpdater, UuidFactory uuidFactory, System2 system2) {
+ public RegisterQualityGates(DbClient dbClient, QualityGateConditionsUpdater qualityGateConditionsUpdater, UuidFactory uuidFactory, System2 system2) {
this.dbClient = dbClient;
this.qualityGateConditionsUpdater = qualityGateConditionsUpdater;
this.qualityGateDao = dbClient.qualityGateDao();
.setQualityGateUuid(qualityGateUuid);
}
- // id does not belongs to equals to be able to be compared with builtin
+ // id does not belong to equals to be able to be compared with builtin
@Override
public boolean equals(Object o) {
if (this == o) {
Objects.equals(errorThreshold, that.errorThreshold);
}
- // id does not belongs to hashcode to be able to be compared with builtin
+ // id does not belong to hashcode to be able to be compared with builtin
@Override
public int hashCode() {
return Objects.hash(metricKey, operator, errorThreshold);
import org.sonar.db.qualityprofile.RulesProfileDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
+import org.sonar.server.rule.DefaultRuleFinder;
+import org.sonar.server.rule.ServerRuleFinder;
import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.util.TypeValidations;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.sonar.api.rules.RulePriority.MAJOR;
private DbClient dbClient = db.getDbClient();
private TypeValidations typeValidations = mock(TypeValidations.class);
private ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class);
- private BuiltInQProfileInsert builtInQProfileInsert = new BuiltInQProfileInsertImpl(dbClient, system2, UuidFactoryFast.getInstance(), typeValidations, activeRuleIndexer);
+ private ServerRuleFinder ruleFinder = new DefaultRuleFinder(dbClient);
+ private BuiltInQProfileInsert builtInQProfileInsert = new BuiltInQProfileInsertImpl(dbClient, ruleFinder, system2, UuidFactoryFast.getInstance(),
+ typeValidations, activeRuleIndexer);
private RuleActivator ruleActivator = new RuleActivator(system2, dbClient, typeValidations, userSessionRule);
private QProfileRules qProfileRules = new QProfileRulesImpl(dbClient, ruleActivator, mock(RuleIndex.class), activeRuleIndexer);
private BuiltInQProfileUpdate builtInQProfileUpdate = new BuiltInQProfileUpdateImpl(dbClient, ruleActivator, activeRuleIndexer);
underTest.start();
- verifyZeroInteractions(builtInQualityProfilesNotification);
+ verifyNoInteractions(builtInQualityProfilesNotification);
}
@Test
return addIfStandalone;
}
- private WebServer getWebServer() {
+ protected WebServer getWebServer() {
return getOptional(WebServer.class)
.orElseThrow(() -> new IllegalStateException("WebServer not available in Pico yet"));
}
- private abstract class AddIf {
+ protected abstract class AddIf {
private final boolean condition;
- private AddIf(boolean condition) {
+ protected AddIf(boolean condition) {
this.condition = condition;
}
import org.sonar.server.platform.WebCoreExtensionsInstaller;
import org.sonar.server.platform.db.migration.NoopDatabaseMigrationImpl;
import org.sonar.server.platform.serverid.ServerIdModule;
+import org.sonar.server.plugins.DetectPluginChange;
import org.sonar.server.setting.DatabaseSettingLoader;
import org.sonar.server.setting.DatabaseSettingsEnabler;
@Override
protected void configureLevel() {
- addIfStartupLeader(StartupMetadataPersister.class);
+ addIfStartupLeader(
+ StartupMetadataPersister.class,
+ DetectPluginChange.class);
add(
NoopDatabaseMigrationImpl.class,
ServerIdModule.class,
import org.sonar.core.platform.EditionProvider;
import org.sonar.core.platform.PlatformEditionProvider;
import org.sonar.server.app.ProcessCommandWrapper;
+import org.sonar.server.authentication.DefaultAdminCredentialsVerifierImpl;
import org.sonar.server.ce.queue.CeQueueCleaner;
import org.sonar.server.es.IndexerStartupTask;
import org.sonar.server.platform.ServerLifecycleNotifier;
import org.sonar.server.platform.web.RegisterServletFilters;
+import org.sonar.server.plugins.DetectPluginChange;
import org.sonar.server.plugins.PluginConsentVerifier;
import org.sonar.server.qualitygate.ProjectsInWarningDaemon;
import org.sonar.server.qualitygate.RegisterQualityGates;
import org.sonar.server.user.ThreadLocalUserSession;
public class PlatformLevelStartup extends PlatformLevel {
+ private AddIfStartupLeaderAndPluginsChanged addIfPluginsChanged;
+
public PlatformLevelStartup(PlatformLevel parent) {
super("startup tasks", parent);
}
@Override
protected void configureLevel() {
add(GeneratePluginIndex.class,
- RegisterPlugins.class,
ServerLifecycleNotifier.class);
addIfStartupLeader(
- IndexerStartupTask.class,
+ IndexerStartupTask.class);
+ addIfStartupLeaderAndPluginsChanged(
RegisterMetrics.class,
RegisterQualityGates.class,
- RegisterRules.class);
- add(BuiltInQProfileLoader.class);
+ RegisterRules.class,
+ BuiltInQProfileLoader.class);
addIfStartupLeader(
BuiltInQualityProfilesUpdateListener.class,
+ BuiltInQProfileUpdateImpl.class);
+ addIfStartupLeaderAndPluginsChanged(
BuiltInQProfileInsertImpl.class,
- BuiltInQProfileUpdateImpl.class,
- RegisterQualityProfiles.class,
+ RegisterQualityProfiles.class);
+ addIfStartupLeader(
RegisterPermissionTemplates.class,
RenameDeprecatedPropertyKeys.class,
CeQueueCleaner.class,
UpgradeSuggestionsCleaner.class,
PluginConsentVerifier.class);
+ add(RegisterPlugins.class,
+ // RegisterServletFilters makes the WebService engine of Level4 served by the MasterServletFilter, therefore it
+ // must be started after all the other startup tasks
+ RegisterServletFilters.class
+ );
+ }
+
+ /**
+ * Add a component to container only if plugins have changed since last start.
+ *
+ * @throws IllegalStateException if called from PlatformLevel3 or below, plugin info is loaded yet
+ */
+ AddIfStartupLeaderAndPluginsChanged addIfStartupLeaderAndPluginsChanged(Object... objects) {
+ if (addIfPluginsChanged == null) {
+ this.addIfPluginsChanged = new AddIfStartupLeaderAndPluginsChanged(getWebServer().isStartupLeader() && anyPluginChanged());
+ }
+ addIfPluginsChanged.ifAdd(objects);
+ return addIfPluginsChanged;
+ }
+
+ private boolean anyPluginChanged() {
+ return getOptional(DetectPluginChange.class)
+ .map(DetectPluginChange::anyPluginChanged)
+ .orElseThrow(() -> new IllegalStateException("DetectPluginChange not available in Pico yet"));
+ }
- // RegisterServletFilters makes the WebService engine of Level4 served by the MasterServletFilter, therefore it
- // must be started after all the other startup tasks
- add(RegisterServletFilters.class);
+ public final class AddIfStartupLeaderAndPluginsChanged extends AddIf {
+ private AddIfStartupLeaderAndPluginsChanged(boolean condition) {
+ super(condition);
+ }
}
@Override
get(WebServerRuleFinder.class).stopCaching();
Loggers.get(PlatformLevelStartup.class)
.info("Running {} Edition", get(PlatformEditionProvider.class).get().map(EditionProvider.Edition::getLabel).orElse(""));
+ get(DefaultAdminCredentialsVerifierImpl.class).runAtStart();
}
});