aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-webserver-core
diff options
context:
space:
mode:
Diffstat (limited to 'server/sonar-webserver-core')
-rw-r--r--server/sonar-webserver-core/src/it/java/org/sonar/server/rule/registration/RulesRegistrantIT.java9
-rw-r--r--server/sonar-webserver-core/src/main/java/org/sonar/server/rule/registration/QualityProfileChangesUpdater.java111
-rw-r--r--server/sonar-webserver-core/src/main/java/org/sonar/server/rule/registration/RulesRegistrant.java22
-rw-r--r--server/sonar-webserver-core/src/test/java/org/sonar/server/rule/registration/QualityProfileChangesUpdaterTest.java20
4 files changed, 95 insertions, 67 deletions
diff --git a/server/sonar-webserver-core/src/it/java/org/sonar/server/rule/registration/RulesRegistrantIT.java b/server/sonar-webserver-core/src/it/java/org/sonar/server/rule/registration/RulesRegistrantIT.java
index b1b9c715829..1b1a99c0edd 100644
--- a/server/sonar-webserver-core/src/it/java/org/sonar/server/rule/registration/RulesRegistrantIT.java
+++ b/server/sonar-webserver-core/src/it/java/org/sonar/server/rule/registration/RulesRegistrantIT.java
@@ -52,6 +52,8 @@ import org.sonar.api.server.rule.RuleDescriptionSection;
import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.api.testfixtures.log.LogTester;
import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.Version;
+import org.sonar.core.platform.SonarQubeVersion;
import org.sonar.core.util.UuidFactory;
import org.sonar.core.util.UuidFactoryFast;
import org.sonar.db.DbClient;
@@ -149,6 +151,7 @@ public class RulesRegistrantIT {
private final DbClient dbClient = db.getDbClient();
private final MetadataIndex metadataIndex = mock();
private final UuidFactory uuidFactory = UuidFactoryFast.getInstance();
+ private final SonarQubeVersion sonarQubeVersion = new SonarQubeVersion(Version.create(10, 3));
private RuleIndexer ruleIndexer;
private ActiveRuleIndexer activeRuleIndexer;
@@ -1137,8 +1140,8 @@ public class RulesRegistrantIT {
execute(context -> context.createRepository("fake", "java").done());
//THEN
List<QProfileChangeDto> qProfileChangeDtos = dbClient.qProfileChangeDao().selectByQuery(db.getSession(), new QProfileChangeQuery(qProfileDto.getKee()));
- assertThat(qProfileChangeDtos).extracting(QProfileChangeDto::getRulesProfileUuid, QProfileChangeDto::getChangeType)
- .contains(tuple(qProfileDto.getRulesProfileUuid(), "DEACTIVATED"));
+ assertThat(qProfileChangeDtos).extracting(QProfileChangeDto::getRulesProfileUuid, QProfileChangeDto::getChangeType, QProfileChangeDto::getSqVersion)
+ .contains(tuple(qProfileDto.getRulesProfileUuid(), "DEACTIVATED", sonarQubeVersion.toString()));
}
@Test
@@ -1162,7 +1165,7 @@ public class RulesRegistrantIT {
reset(webServerRuleFinder);
RulesRegistrant task = new RulesRegistrant(loader, qProfileRules, dbClient, ruleIndexer, activeRuleIndexer, languages, system, webServerRuleFinder, metadataIndex,
- rulesKeyVerifier, startupRuleUpdater, newRuleCreator, qualityProfileChangesUpdater);
+ rulesKeyVerifier, startupRuleUpdater, newRuleCreator, qualityProfileChangesUpdater, sonarQubeVersion);
task.start();
// Execute a commit to refresh session state as the task is using its own session
db.getSession().commit();
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/rule/registration/QualityProfileChangesUpdater.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/rule/registration/QualityProfileChangesUpdater.java
index e2dd9e9c3c4..f8ccc6d9369 100644
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/rule/registration/QualityProfileChangesUpdater.java
+++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/rule/registration/QualityProfileChangesUpdater.java
@@ -19,55 +19,59 @@
*/
package org.sonar.server.rule.registration;
+import com.google.common.collect.Sets;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
+import org.jetbrains.annotations.NotNull;
import org.sonar.api.issue.impact.SoftwareQuality;
+import org.sonar.core.platform.SonarQubeVersion;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.QProfileChangeDto;
-import org.sonar.db.rule.RuleImpactChangeDto;
import org.sonar.db.rule.RuleChangeDto;
+import org.sonar.db.rule.RuleImpactChangeDto;
import org.sonar.server.rule.PluginRuleUpdate;
public class QualityProfileChangesUpdater {
private final DbClient dbClient;
private final UuidFactory uuidFactory;
+ private final SonarQubeVersion sonarQubeVersion;
- public QualityProfileChangesUpdater(DbClient dbClient, UuidFactory uuidFactory) {
+ public QualityProfileChangesUpdater(DbClient dbClient, UuidFactory uuidFactory, SonarQubeVersion sonarQubeVersion) {
this.dbClient = dbClient;
this.uuidFactory = uuidFactory;
+ this.sonarQubeVersion = sonarQubeVersion;
}
- public void updateWithoutCommit(DbSession dbSession, Set<PluginRuleUpdate> pluginRuleUpdates) {
- for (PluginRuleUpdate pluginRuleUpdate : pluginRuleUpdates) {
- String ruleChangeUuid = uuidFactory.create();
- RuleChangeDto ruleChangeDto = createRuleChange(ruleChangeUuid, pluginRuleUpdate);
+ public void createQprofileChangesForRuleUpdates(DbSession dbSession, Set<PluginRuleUpdate> pluginRuleUpdates) {
+ List<QProfileChangeDto> changesToPersist = pluginRuleUpdates.stream()
+ .flatMap(pluginRuleUpdate -> {
+ RuleChangeDto ruleChangeDto = createNewRuleChange(pluginRuleUpdate);
+ insertRuleChange(dbSession, ruleChangeDto);
- createRuleImpactChanges(ruleChangeUuid, pluginRuleUpdate, ruleChangeDto);
- insertRuleChange(dbSession, ruleChangeDto);
-
- for (String qualityProfileUuid : findQualityProfilesForRule(dbSession, pluginRuleUpdate.getRuleUuid())) {
- QProfileChangeDto qProfileChangeDto = new QProfileChangeDto();
- qProfileChangeDto.setUuid(uuidFactory.create());
- qProfileChangeDto.setChangeType("UPDATED");
- qProfileChangeDto.setRuleChange(ruleChangeDto);
- qProfileChangeDto.setRulesProfileUuid(qualityProfileUuid);
- dbClient.qProfileChangeDao().insert(dbSession, qProfileChangeDto);
- }
+ return findQualityProfilesForRule(dbSession, pluginRuleUpdate.getRuleUuid()).stream()
+ .map(qualityProfileUuid -> buildQprofileChangeDtoForRuleChange(qualityProfileUuid, ruleChangeDto));
+ }).toList();
+ if (!changesToPersist.isEmpty()) {
+ dbClient.qProfileChangeDao().bulkInsert(dbSession, changesToPersist);
}
}
- private static RuleChangeDto createRuleChange(String ruleChangeUuid, PluginRuleUpdate pluginRuleUpdate) {
+ private RuleChangeDto createNewRuleChange(PluginRuleUpdate pluginRuleUpdate) {
RuleChangeDto ruleChangeDto = new RuleChangeDto();
- ruleChangeDto.setUuid(ruleChangeUuid);
+ ruleChangeDto.setUuid(uuidFactory.create());
ruleChangeDto.setRuleUuid(pluginRuleUpdate.getRuleUuid());
ruleChangeDto.setOldCleanCodeAttribute(pluginRuleUpdate.getOldCleanCodeAttribute());
ruleChangeDto.setNewCleanCodeAttribute(pluginRuleUpdate.getNewCleanCodeAttribute());
+
+ ruleChangeDto.setRuleImpactChanges(createRuleImpactChanges(pluginRuleUpdate, ruleChangeDto));
return ruleChangeDto;
}
@@ -77,46 +81,53 @@ public class QualityProfileChangesUpdater {
.map(ActiveRuleDto::getProfileUuid)
.collect(Collectors.toSet());
}
-
private void insertRuleChange(DbSession dbSession, RuleChangeDto ruleChangeDto) {
dbClient.ruleChangeDao().insert(dbSession, ruleChangeDto);
}
- private static void createRuleImpactChanges(String ruleChangeUuid, PluginRuleUpdate pluginRuleUpdate, RuleChangeDto ruleChangeDto) {
- List<SoftwareQuality> matchingSoftwareQualities = pluginRuleUpdate.getMatchingSoftwareQualities();
- for (SoftwareQuality softwareQuality : matchingSoftwareQualities) {
+ private static Set<RuleImpactChangeDto> createRuleImpactChanges(PluginRuleUpdate pluginRuleUpdate, RuleChangeDto ruleChangeDto) {
+ Set<RuleImpactChangeDto> ruleImpactChangeDtos = new HashSet<>();
+
+ pluginRuleUpdate.getMatchingSoftwareQualities().stream()
+ .map(softwareQuality -> {
+ RuleImpactChangeDto ruleImpactChangeDto = new RuleImpactChangeDto();
+ ruleImpactChangeDto.setRuleChangeUuid(ruleChangeDto.getUuid());
+ ruleImpactChangeDto.setOldSeverity(pluginRuleUpdate.getOldImpacts().get(softwareQuality));
+ ruleImpactChangeDto.setOldSoftwareQuality(softwareQuality);
+ ruleImpactChangeDto.setNewSeverity(pluginRuleUpdate.getNewImpacts().get(softwareQuality));
+ ruleImpactChangeDto.setNewSoftwareQuality(softwareQuality);
+ return ruleImpactChangeDto;
+ }).forEach(ruleImpactChangeDtos::add);
+
+ Iterator<SoftwareQuality> removedIterator = (Sets.difference(pluginRuleUpdate.getOldImpacts().keySet(), pluginRuleUpdate.getMatchingSoftwareQualities())).iterator();
+ Iterator<SoftwareQuality> addedIterator = (Sets.difference(pluginRuleUpdate.getNewImpacts().keySet(), pluginRuleUpdate.getMatchingSoftwareQualities())).iterator();
+ while (removedIterator.hasNext() || addedIterator.hasNext()) {
RuleImpactChangeDto ruleImpactChangeDto = new RuleImpactChangeDto();
- ruleImpactChangeDto.setRuleChangeUuid(ruleChangeUuid);
- ruleImpactChangeDto.setOldSeverity(pluginRuleUpdate.getOldImpacts().get(softwareQuality));
- ruleImpactChangeDto.setOldSoftwareQuality(softwareQuality);
- ruleImpactChangeDto.setNewSeverity(pluginRuleUpdate.getNewImpacts().get(softwareQuality));
- ruleImpactChangeDto.setNewSoftwareQuality(softwareQuality);
- ruleChangeDto.addRuleImpactChangeDto(ruleImpactChangeDto);
- }
-
- List<SoftwareQuality> oldSoftwareQualities = pluginRuleUpdate.getOldImpacts().keySet()
- .stream()
- .filter(softwareQuality -> !matchingSoftwareQualities.contains(softwareQuality)).toList();
-
- List<SoftwareQuality> newSoftwareQualities = pluginRuleUpdate.getNewImpacts().keySet()
- .stream()
- .filter(softwareQuality -> !matchingSoftwareQualities.contains(softwareQuality)).toList();
-
- int size = Math.max(oldSoftwareQualities.size(), newSoftwareQualities.size());
- for(int i = 0; i < size; i++) {
- RuleImpactChangeDto ruleImpactChangeDto = new RuleImpactChangeDto();
- ruleImpactChangeDto.setRuleChangeUuid(ruleChangeUuid);
- if(i < oldSoftwareQualities.size()) {
- ruleImpactChangeDto.setOldSeverity(pluginRuleUpdate.getOldImpacts().get(oldSoftwareQualities.get(i)));
- ruleImpactChangeDto.setOldSoftwareQuality(oldSoftwareQualities.get(i));
+ ruleImpactChangeDto.setRuleChangeUuid(ruleChangeDto.getUuid());
+ if (removedIterator.hasNext()) {
+ var removedSoftwareQuality = removedIterator.next();
+ ruleImpactChangeDto.setOldSoftwareQuality(removedSoftwareQuality);
+ ruleImpactChangeDto.setOldSeverity(pluginRuleUpdate.getOldImpacts().get(removedSoftwareQuality));
}
- if(i < newSoftwareQualities.size()) {
- ruleImpactChangeDto.setNewSeverity(pluginRuleUpdate.getNewImpacts().get(newSoftwareQualities.get(i)));
- ruleImpactChangeDto.setNewSoftwareQuality(newSoftwareQualities.get(i));
+ if (addedIterator.hasNext()) {
+ var addedSoftwareQuality = addedIterator.next();
+ ruleImpactChangeDto.setNewSoftwareQuality(addedSoftwareQuality);
+ ruleImpactChangeDto.setNewSeverity(pluginRuleUpdate.getNewImpacts().get(addedSoftwareQuality));
}
- ruleChangeDto.addRuleImpactChangeDto(ruleImpactChangeDto);
+ ruleImpactChangeDtos.add(ruleImpactChangeDto);
}
+ return ruleImpactChangeDtos;
+ }
+ @NotNull
+ private QProfileChangeDto buildQprofileChangeDtoForRuleChange(String qualityProfileUuid, RuleChangeDto ruleChangeDto) {
+ QProfileChangeDto qProfileChangeDto = new QProfileChangeDto();
+ qProfileChangeDto.setUuid(uuidFactory.create());
+ qProfileChangeDto.setChangeType("UPDATED");
+ qProfileChangeDto.setRuleChange(ruleChangeDto);
+ qProfileChangeDto.setRulesProfileUuid(qualityProfileUuid);
+ qProfileChangeDto.setSqVersion(sonarQubeVersion.toString());
+ return qProfileChangeDto;
}
}
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/rule/registration/RulesRegistrant.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/rule/registration/RulesRegistrant.java
index 26575827823..e1f1249954a 100644
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/rule/registration/RulesRegistrant.java
+++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/rule/registration/RulesRegistrant.java
@@ -39,15 +39,17 @@ import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
+import org.sonar.core.platform.SonarQubeVersion;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
+import org.sonar.db.qualityprofile.QProfileChangeDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleRepositoryDto;
import org.sonar.server.es.metadata.MetadataIndex;
import org.sonar.server.qualityprofile.ActiveRuleChange;
import org.sonar.server.qualityprofile.QProfileRules;
-import org.sonar.server.rule.PluginRuleUpdate;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
+import org.sonar.server.rule.PluginRuleUpdate;
import org.sonar.server.rule.RuleDefinitionsLoader;
import org.sonar.server.rule.WebServerRuleFinder;
import org.sonar.server.rule.index.RuleIndexer;
@@ -77,11 +79,12 @@ public class RulesRegistrant implements Startable {
private final StartupRuleUpdater startupRuleUpdater;
private final NewRuleCreator newRuleCreator;
private final QualityProfileChangesUpdater qualityProfileChangesUpdater;
+ private final SonarQubeVersion sonarQubeVersion;
public RulesRegistrant(RuleDefinitionsLoader defLoader, QProfileRules qProfileRules, DbClient dbClient, RuleIndexer ruleIndexer,
ActiveRuleIndexer activeRuleIndexer, Languages languages, System2 system2, WebServerRuleFinder webServerRuleFinder,
MetadataIndex metadataIndex, RulesKeyVerifier rulesKeyVerifier, StartupRuleUpdater startupRuleUpdater,
- NewRuleCreator newRuleCreator, QualityProfileChangesUpdater qualityProfileChangesUpdater) {
+ NewRuleCreator newRuleCreator, QualityProfileChangesUpdater qualityProfileChangesUpdater, SonarQubeVersion sonarQubeVersion) {
this.defLoader = defLoader;
this.qProfileRules = qProfileRules;
this.dbClient = dbClient;
@@ -95,6 +98,7 @@ public class RulesRegistrant implements Startable {
this.startupRuleUpdater = startupRuleUpdater;
this.newRuleCreator = newRuleCreator;
this.qualityProfileChangesUpdater = qualityProfileChangesUpdater;
+ this.sonarQubeVersion = sonarQubeVersion;
}
@Override
@@ -108,7 +112,7 @@ public class RulesRegistrant implements Startable {
for (RulesDefinition.ExtendedRepository repoDef : repositories) {
if (languages.get(repoDef.language()) != null) {
Set<PluginRuleUpdate> pluginRuleUpdates = registerRules(rulesRegistrationContext, repoDef.rules(), dbSession);
- qualityProfileChangesUpdater.updateWithoutCommit(dbSession, pluginRuleUpdates);
+ qualityProfileChangesUpdater.createQprofileChangesForRuleUpdates(dbSession, pluginRuleUpdates);
dbSession.commit();
}
}
@@ -120,7 +124,13 @@ public class RulesRegistrant implements Startable {
// FIXME lack of resiliency, active rules index is corrupted if rule index fails
// to be updated. Only a single DB commit should be executed.
ruleIndexer.commitAndIndex(dbSession, rulesRegistrationContext.getAllModified().map(RuleDto::getUuid).collect(Collectors.toSet()));
- changes.forEach(arChange -> dbClient.qProfileChangeDao().insert(dbSession, arChange.toDto(null)));
+
+ List<QProfileChangeDto> qProfileChangeDtos = changes.stream()
+ .map(ActiveRuleChange::toSystemChangedDto)
+ .peek(dto -> dto.setSqVersion(sonarQubeVersion.toString()))
+ .toList();
+ dbClient.qProfileChangeDao().bulkInsert(dbSession, qProfileChangeDtos);
+
activeRuleIndexer.commitAndIndex(dbSession, changes);
rulesRegistrationContext.getRenamed().forEach(e -> LOG.info("Rule {} re-keyed to {}", e.getValue(), e.getKey().getKey()));
profiler.stopDebug();
@@ -314,8 +324,8 @@ public class RulesRegistrant implements Startable {
private static Set<String> getExistingAndRenamedRepositories(RulesRegistrationContext recorder, Collection<RulesDefinition.Repository> context) {
return Stream.concat(
- context.stream().map(RulesDefinition.ExtendedRepository::key),
- recorder.getRenamed().map(Map.Entry::getValue).map(RuleKey::repository))
+ context.stream().map(RulesDefinition.ExtendedRepository::key),
+ recorder.getRenamed().map(Map.Entry::getValue).map(RuleKey::repository))
.collect(Collectors.toSet());
}
diff --git a/server/sonar-webserver-core/src/test/java/org/sonar/server/rule/registration/QualityProfileChangesUpdaterTest.java b/server/sonar-webserver-core/src/test/java/org/sonar/server/rule/registration/QualityProfileChangesUpdaterTest.java
index aa8fbd01e16..80a37f131fb 100644
--- a/server/sonar-webserver-core/src/test/java/org/sonar/server/rule/registration/QualityProfileChangesUpdaterTest.java
+++ b/server/sonar-webserver-core/src/test/java/org/sonar/server/rule/registration/QualityProfileChangesUpdaterTest.java
@@ -27,6 +27,8 @@ import org.mockito.ArgumentCaptor;
import org.sonar.api.issue.impact.Severity;
import org.sonar.api.issue.impact.SoftwareQuality;
import org.sonar.api.rules.CleanCodeAttribute;
+import org.sonar.api.utils.Version;
+import org.sonar.core.platform.SonarQubeVersion;
import org.sonar.core.util.UuidFactoryImpl;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
@@ -56,8 +58,9 @@ public class QualityProfileChangesUpdaterTest {
private final RuleChangeDao ruleChangeDao = mock();
private final QProfileChangeDao qualityProfileChangeDao = mock();
private final ActiveRuleDao activeRuleDao = mock();
+ private final SonarQubeVersion sonarQubeVersion = new SonarQubeVersion(Version.create(10, 3));
- private final QualityProfileChangesUpdater underTest = new QualityProfileChangesUpdater(dbClient, UuidFactoryImpl.INSTANCE);
+ private final QualityProfileChangesUpdater underTest = new QualityProfileChangesUpdater(dbClient, UuidFactoryImpl.INSTANCE, sonarQubeVersion);
@Before
public void before() {
@@ -68,7 +71,7 @@ public class QualityProfileChangesUpdaterTest {
@Test
public void updateWithoutCommit_whenNoRuleChanges_thenDontInteractWithDatabase() {
- underTest.updateWithoutCommit(mock(), Set.of());
+ underTest.createQprofileChangesForRuleUpdates(mock(), Set.of());
verifyNoInteractions(dbClient);
}
@@ -80,7 +83,7 @@ public class QualityProfileChangesUpdaterTest {
pluginRuleUpdate.setOldCleanCodeAttribute(CleanCodeAttribute.TESTED);
pluginRuleUpdate.setRuleUuid(RULE_UUID);
- underTest.updateWithoutCommit(dbSession, Set.of(pluginRuleUpdate));
+ underTest.createQprofileChangesForRuleUpdates(dbSession, Set.of(pluginRuleUpdate));
verify(ruleChangeDao).insert(argThat(dbSession::equals), argThat(ruleChangeDto ->
ruleChangeDto.getNewCleanCodeAttribute() == CleanCodeAttribute.CLEAR
@@ -109,7 +112,7 @@ public class QualityProfileChangesUpdaterTest {
pluginRuleUpdate2.addNewImpact(SoftwareQuality.SECURITY, Severity.HIGH);
pluginRuleUpdate2.addOldImpact(SoftwareQuality.RELIABILITY, Severity.MEDIUM);
- underTest.updateWithoutCommit(dbSession, Set.of(pluginRuleUpdate, pluginRuleUpdate2));
+ underTest.createQprofileChangesForRuleUpdates(dbSession, Set.of(pluginRuleUpdate, pluginRuleUpdate2));
ArgumentCaptor<RuleChangeDto> captor = ArgumentCaptor.forClass(RuleChangeDto.class);
verify(ruleChangeDao, times(2)).insert(argThat(dbSession::equals), captor.capture());
@@ -146,10 +149,11 @@ public class QualityProfileChangesUpdaterTest {
pluginRuleUpdate.setOldCleanCodeAttribute(CleanCodeAttribute.TESTED);
pluginRuleUpdate.setRuleUuid(RULE_UUID);
- underTest.updateWithoutCommit(dbSession, Set.of(pluginRuleUpdate));
+ underTest.createQprofileChangesForRuleUpdates(dbSession, Set.of(pluginRuleUpdate));
- verify(qualityProfileChangeDao, times(2)).insert(argThat(dbSession::equals), argThat(qProfileChangeDto ->
- qProfileChangeDto.getChangeType().equals("UPDATED")
- && qProfileChangeDto.getRuleChange() != null));
+ verify(qualityProfileChangeDao, times(1)).bulkInsert(argThat(dbSession::equals),
+ argThat(qProfileChangeDtos ->
+ qProfileChangeDtos.stream()
+ .allMatch(dto -> "UPDATED".equals(dto.getChangeType()) && dto.getRuleChange() != null)));
}
}