aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-webserver-auth/src
diff options
context:
space:
mode:
authorLukasz Jarocki <lukasz.jarocki@sonarsource.com>2022-02-08 13:06:37 +0100
committersonartech <sonartech@sonarsource.com>2022-02-18 15:48:04 +0000
commit90d9a31aa2feb59ce8546fede2721892473ec993 (patch)
treed654a9a53c47f08770e2f063a25ef0b5ff20d5d0 /server/sonar-webserver-auth/src
parent0c8ff1bac53c2dfa89e7be014b64b411f24434c0 (diff)
downloadsonarqube-90d9a31aa2feb59ce8546fede2721892473ec993.tar.gz
sonarqube-90d9a31aa2feb59ce8546fede2721892473ec993.zip
SONAR-15919 added filtering rule set change events based on languages user subscribed to
Diffstat (limited to 'server/sonar-webserver-auth/src')
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotification.java30
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationBuilder.java220
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationHandler.java62
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationTemplate.java113
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfile.java148
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileInsert.java30
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImpl.java212
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileLoader.java44
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepository.java41
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImpl.java232
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdate.java32
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImpl.java95
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesUpdateListener.java76
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/DescendantProfilesSupplier.java55
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/DistributedRuleActivatorEventsDistributor.java45
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/QProfileName.java71
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/QualityProfileChangeEventService.java33
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/QualityProfileChangeEventServiceImpl.java206
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/RuleActivationContext.java366
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java536
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/RuleActivatorEventsDistributor.java30
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/StandaloneRuleActivatorEventsDistributor.java42
-rw-r--r--server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/package-info.java24
-rw-r--r--server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationHandlerTest.java136
-rw-r--r--server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationTemplateTest.java283
-rw-r--r--server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationTest.java141
-rw-r--r--server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImplTest.java245
-rw-r--r--server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileLoaderTest.java39
-rw-r--r--server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImplTest.java269
-rw-r--r--server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImplTest.java554
-rw-r--r--server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesUpdateListenerTest.java183
-rw-r--r--server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/RuleActivatorTest.java237
-rw-r--r--server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryRule.java103
33 files changed, 0 insertions, 4933 deletions
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotification.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotification.java
deleted file mode 100644
index df8d85c816a..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotification.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import org.sonar.api.notifications.Notification;
-
-public class BuiltInQPChangeNotification extends Notification {
- static final String TYPE = "built-in-quality-profiles";
-
- public BuiltInQPChangeNotification() {
- super(TYPE);
- }
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationBuilder.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationBuilder.java
deleted file mode 100644
index 7de478f2e9b..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationBuilder.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.IntStream;
-import org.sonar.api.notifications.Notification;
-
-import static com.google.common.base.Preconditions.checkState;
-import static java.lang.Integer.parseInt;
-import static java.lang.Long.parseLong;
-import static java.lang.String.format;
-import static java.util.Objects.requireNonNull;
-
-public class BuiltInQPChangeNotificationBuilder {
-
- private static final String NUMBER_OF_PROFILES = "numberOfProfiles";
- private static final String PROFILE_NAME = ".profileName";
- private static final String LANGUAGE_KEY = ".languageKey";
- private static final String LANGUAGE_NAME = ".languageName";
- private static final String NEW_RULES = ".newRules";
- private static final String UPDATED_RULES = ".updatedRules";
- private static final String REMOVED_RULES = ".removedRules";
- private static final String START_DATE = ".startDate";
- private static final String END_DATE = ".endDate";
-
- private final List<Profile> profiles = new ArrayList<>();
-
- public BuiltInQPChangeNotificationBuilder addProfile(Profile profile) {
- profiles.add(profile);
- return this;
- }
-
- public BuiltInQPChangeNotification build() {
- BuiltInQPChangeNotification notification = new BuiltInQPChangeNotification();
- notification.setFieldValue(NUMBER_OF_PROFILES, String.valueOf(profiles.size()));
- AtomicInteger count = new AtomicInteger();
- profiles.forEach(profile -> {
- int index = count.getAndIncrement();
- notification.setFieldValue(index + PROFILE_NAME, profile.getProfileName());
- notification.setFieldValue(index + LANGUAGE_KEY, profile.getLanguageKey());
- notification.setFieldValue(index + LANGUAGE_NAME, profile.getLanguageName());
- notification.setFieldValue(index + NEW_RULES, String.valueOf(profile.getNewRules()));
- notification.setFieldValue(index + UPDATED_RULES, String.valueOf(profile.getUpdatedRules()));
- notification.setFieldValue(index + REMOVED_RULES, String.valueOf(profile.getRemovedRules()));
- notification.setFieldValue(index + START_DATE, String.valueOf(profile.getStartDate()));
- notification.setFieldValue(index + END_DATE, String.valueOf(profile.getEndDate()));
- });
- return notification;
- }
-
- public static BuiltInQPChangeNotificationBuilder parse(Notification notification) {
- checkState(BuiltInQPChangeNotification.TYPE.equals(notification.getType()),
- "Expected notification of type %s but got %s", BuiltInQPChangeNotification.TYPE, notification.getType());
- BuiltInQPChangeNotificationBuilder notif = new BuiltInQPChangeNotificationBuilder();
- String numberOfProfilesText = notification.getFieldValue(NUMBER_OF_PROFILES);
- checkState(numberOfProfilesText != null, "Could not read the built-in quality profile notification");
- Integer numberOfProfiles = Integer.valueOf(numberOfProfilesText);
- IntStream.rangeClosed(0, numberOfProfiles - 1)
- .mapToObj(index -> Profile.newBuilder()
- .setProfileName(getNonNullFieldValue(notification, index + PROFILE_NAME))
- .setLanguageKey(getNonNullFieldValue(notification, index + LANGUAGE_KEY))
- .setLanguageName(getNonNullFieldValue(notification, index + LANGUAGE_NAME))
- .setNewRules(parseInt(getNonNullFieldValue(notification, index + NEW_RULES)))
- .setUpdatedRules(parseInt(getNonNullFieldValue(notification, index + UPDATED_RULES)))
- .setRemovedRules(parseInt(getNonNullFieldValue(notification, index + REMOVED_RULES)))
- .setStartDate(parseLong(getNonNullFieldValue(notification, index + START_DATE)))
- .setEndDate(parseLong(getNonNullFieldValue(notification, index + END_DATE)))
- .build())
- .forEach(notif::addProfile);
- return notif;
- }
-
- private static String getNonNullFieldValue(Notification notification, String key) {
- String value = notification.getFieldValue(key);
- return requireNonNull(value, format("Notification field '%s' is null", key));
- }
-
- public List<Profile> getProfiles() {
- return profiles;
- }
-
- public static class Profile {
- private final String profileName;
- private final String languageKey;
- private final String languageName;
- private final int newRules;
- private final int updatedRules;
- private final int removedRules;
- private final long startDate;
- private final long endDate;
-
- public Profile(Builder builder) {
- this.profileName = builder.profileName;
- this.languageKey = builder.languageKey;
- this.languageName = builder.languageName;
- this.newRules = builder.newRules;
- this.updatedRules = builder.updatedRules;
- this.removedRules = builder.removedRules;
- this.startDate = builder.startDate;
- this.endDate = builder.endDate;
- }
-
- public String getProfileName() {
- return profileName;
- }
-
- public String getLanguageKey() {
- return languageKey;
- }
-
- public String getLanguageName() {
- return languageName;
- }
-
- public int getNewRules() {
- return newRules;
- }
-
- public int getUpdatedRules() {
- return updatedRules;
- }
-
- public int getRemovedRules() {
- return removedRules;
- }
-
- public long getStartDate() {
- return startDate;
- }
-
- public long getEndDate() {
- return endDate;
- }
-
- public static Builder newBuilder() {
- return new Builder();
- }
-
- public static class Builder {
- private String profileName;
- private String languageKey;
- private String languageName;
- private int newRules;
- private int updatedRules;
- private int removedRules;
- private long startDate;
- private long endDate;
-
- private Builder() {
- }
-
- public Builder setLanguageKey(String languageKey) {
- this.languageKey = requireNonNull(languageKey, "languageKEy should not be null");
- return this;
- }
-
- public Builder setLanguageName(String languageName) {
- this.languageName = requireNonNull(languageName, "languageName should not be null");
- return this;
- }
-
- public Builder setProfileName(String profileName) {
- this.profileName = requireNonNull(profileName, "profileName should not be null");
- return this;
- }
-
- public Builder setNewRules(int newRules) {
- checkState(newRules >= 0, "newRules should not be negative");
- this.newRules = newRules;
- return this;
- }
-
- public Builder setUpdatedRules(int updatedRules) {
- checkState(updatedRules >= 0, "updatedRules should not be negative");
- this.updatedRules = updatedRules;
- return this;
- }
-
- public Builder setRemovedRules(int removedRules) {
- checkState(removedRules >= 0, "removedRules should not be negative");
- this.removedRules = removedRules;
- return this;
- }
-
- public Builder setStartDate(long startDate) {
- this.startDate = startDate;
- return this;
- }
-
- public Builder setEndDate(long endDate) {
- this.endDate = endDate;
- return this;
- }
-
- public Profile build() {
- return new Profile(this);
- }
- }
- }
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationHandler.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationHandler.java
deleted file mode 100644
index 5402ead1042..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationHandler.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import java.util.Collection;
-import java.util.Optional;
-import java.util.Set;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.server.notification.EmailNotificationHandler;
-import org.sonar.server.notification.NotificationDispatcherMetadata;
-import org.sonar.server.notification.email.EmailNotificationChannel;
-import org.sonar.server.notification.email.EmailNotificationChannel.EmailDeliveryRequest;
-
-import static org.sonar.core.util.stream.MoreCollectors.toSet;
-
-public class BuiltInQPChangeNotificationHandler extends EmailNotificationHandler<BuiltInQPChangeNotification> {
- private final DbClient dbClient;
-
- public BuiltInQPChangeNotificationHandler(DbClient dbClient, EmailNotificationChannel emailNotificationChannel) {
- super(emailNotificationChannel);
- this.dbClient = dbClient;
- }
-
- @Override
- public Optional<NotificationDispatcherMetadata> getMetadata() {
- return Optional.empty();
- }
-
- @Override
- public Class<BuiltInQPChangeNotification> getNotificationClass() {
- return BuiltInQPChangeNotification.class;
- }
-
- @Override
- public Set<EmailDeliveryRequest> toEmailDeliveryRequests(Collection<BuiltInQPChangeNotification> notifications) {
- try (DbSession session = dbClient.openSession(false)) {
- return dbClient.authorizationDao()
- .selectQualityProfileAdministratorLogins(session)
- .stream()
- .flatMap(t -> notifications.stream().map(notification -> new EmailDeliveryRequest(t.getEmail(), notification)))
- .collect(toSet());
- }
- }
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationTemplate.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationTemplate.java
deleted file mode 100644
index bd1096664a2..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationTemplate.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.util.Comparator;
-import java.util.Date;
-import javax.annotation.CheckForNull;
-import org.sonar.api.notifications.Notification;
-import org.sonar.api.platform.Server;
-import org.sonar.server.issue.notification.EmailMessage;
-import org.sonar.server.issue.notification.EmailTemplate;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.sonar.api.utils.DateUtils.formatDate;
-import static org.sonar.server.qualityprofile.BuiltInQPChangeNotificationBuilder.Profile;
-import static org.sonar.server.qualityprofile.BuiltInQPChangeNotificationBuilder.parse;
-
-public class BuiltInQPChangeNotificationTemplate implements EmailTemplate {
-
- private final Server server;
-
- public BuiltInQPChangeNotificationTemplate(Server server) {
- this.server = server;
- }
-
- @Override
- @CheckForNull
- public EmailMessage format(Notification notification) {
- if (!BuiltInQPChangeNotification.TYPE.equals(notification.getType())) {
- return null;
- }
-
- BuiltInQPChangeNotificationBuilder profilesNotification = parse(notification);
- StringBuilder message = new StringBuilder("The following built-in profiles have been updated:\n\n");
- profilesNotification.getProfiles().stream()
- .sorted(Comparator.comparing(Profile::getLanguageName).thenComparing(Profile::getProfileName))
- .forEach(profile -> {
- message.append("\"")
- .append(profile.getProfileName())
- .append("\" - ")
- .append(profile.getLanguageName())
- .append(": ")
- .append(server.getPublicRootUrl()).append("/profiles/changelog?language=")
- .append(profile.getLanguageKey())
- .append("&name=")
- .append(encode(profile.getProfileName()))
- .append("&since=")
- .append(formatDate(new Date(profile.getStartDate())))
- .append("&to=")
- .append(formatDate(new Date(profile.getEndDate())))
- .append("\n");
- int newRules = profile.getNewRules();
- if (newRules > 0) {
- message.append(" ").append(newRules).append(" new rule")
- .append(plural(newRules))
- .append('\n');
- }
- int updatedRules = profile.getUpdatedRules();
- if (updatedRules > 0) {
- message.append(" ").append(updatedRules).append(" rule")
- .append(updatedRules > 1 ? "s have been updated" : " has been updated")
- .append("\n");
- }
- int removedRules = profile.getRemovedRules();
- if (removedRules > 0) {
- message.append(" ").append(removedRules).append(" rule")
- .append(plural(removedRules))
- .append(" removed\n");
- }
- message.append("\n");
- });
-
- message.append("This is a good time to review your quality profiles and update them to benefit from the latest evolutions: ");
- message.append(server.getPublicRootUrl()).append("/profiles");
-
- // And finally return the email that will be sent
- return new EmailMessage()
- .setMessageId(BuiltInQPChangeNotification.TYPE)
- .setSubject("Built-in quality profiles have been updated")
- .setPlainTextMessage(message.toString());
- }
-
- private static String plural(int count) {
- return count > 1 ? "s" : "";
- }
-
- public String encode(String text) {
- try {
- return URLEncoder.encode(text, UTF_8.name());
- } catch (UnsupportedEncodingException e) {
- throw new IllegalStateException(String.format("Cannot encode %s", text), e);
- }
- }
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfile.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfile.java
deleted file mode 100644
index 866c7dc0801..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfile.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
-import java.util.List;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
-
-import static org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.BuiltInActiveRule;
-import static org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.OverriddenParam;
-
-/**
- * Represent a Quality Profile as computed from {@link BuiltInQualityProfilesDefinition} provided by installed plugins.
- */
-@Immutable
-public final class BuiltInQProfile {
- private final QProfileName qProfileName;
- private final boolean isDefault;
- private final List<ActiveRule> activeRules;
-
- private BuiltInQProfile(Builder builder) {
- this.qProfileName = new QProfileName(builder.language, builder.name);
- this.isDefault = builder.declaredDefault || builder.computedDefault;
- this.activeRules = ImmutableList.copyOf(builder.activeRules);
- }
-
- public String getName() {
- return qProfileName.getName();
- }
-
- public String getLanguage() {
- return qProfileName.getLanguage();
- }
-
- public QProfileName getQProfileName() {
- return qProfileName;
- }
-
- public boolean isDefault() {
- return isDefault;
- }
-
- public List<ActiveRule> getActiveRules() {
- return activeRules;
- }
-
- static final class ActiveRule {
- private final String ruleUuid;
- private final RuleKey ruleKey;
- private final String severity;
- private final List<OverriddenParam> params;
-
- ActiveRule(String ruleUuid, BuiltInActiveRule builtIn) {
- this(ruleUuid, RuleKey.of(builtIn.repoKey(), builtIn.ruleKey()), builtIn.overriddenSeverity(), builtIn.overriddenParams());
- }
-
- ActiveRule(String ruleUuid, RuleKey ruleKey, @Nullable String severity, List<OverriddenParam> params) {
- this.ruleUuid = ruleUuid;
- this.ruleKey = ruleKey;
- this.severity = severity;
- this.params = params;
- }
-
- public String getRuleUuid() {
- return ruleUuid;
- }
-
- public RuleKey getRuleKey() {
- return ruleKey;
- }
-
- @CheckForNull
- public String getSeverity() {
- return severity;
- }
-
- public List<OverriddenParam> getParams() {
- return params;
- }
- }
-
- static final class Builder {
- private String language;
- private String name;
- private boolean declaredDefault;
- private boolean computedDefault;
- private final List<ActiveRule> activeRules = new ArrayList<>();
-
- public Builder setLanguage(String language) {
- this.language = language;
- return this;
- }
-
- Builder setName(String name) {
- this.name = name;
- return this;
- }
-
- String getName() {
- return name;
- }
-
- Builder setDeclaredDefault(boolean declaredDefault) {
- this.declaredDefault = declaredDefault;
- return this;
- }
-
- boolean isDeclaredDefault() {
- return declaredDefault;
- }
-
- Builder setComputedDefault(boolean flag) {
- computedDefault = flag;
- return this;
- }
-
- Builder addRule(ActiveRule activeRule) {
- this.activeRules.add(activeRule);
- return this;
- }
-
- BuiltInQProfile build() {
- return new BuiltInQProfile(this);
- }
- }
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileInsert.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileInsert.java
deleted file mode 100644
index 7cfd2d28faf..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileInsert.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import org.sonar.db.DbSession;
-
-public interface BuiltInQProfileInsert {
- /**
- * Persist a new built-in profile
- * Db sessions are committed and Elasticsearch indices are updated
- */
- void create(DbSession batchSession, BuiltInQProfile builtInQProfile);
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImpl.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImpl.java
deleted file mode 100644
index d4aad4ffbbf..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImpl.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import com.google.common.base.Splitter;
-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.stream.Collectors;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
-import org.sonar.api.server.rule.RuleParamType;
-import org.sonar.api.utils.System2;
-import org.sonar.core.util.UuidFactory;
-import org.sonar.core.util.stream.MoreCollectors;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.qualityprofile.ActiveRuleDto;
-import org.sonar.db.qualityprofile.ActiveRuleKey;
-import org.sonar.db.qualityprofile.ActiveRuleParamDto;
-import org.sonar.db.qualityprofile.DefaultQProfileDto;
-import org.sonar.db.qualityprofile.OrgQProfileDto;
-import org.sonar.db.qualityprofile.RulesProfileDto;
-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, 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;
- this.activeRuleIndexer = activeRuleIndexer;
- }
-
- @Override
- public void create(DbSession batchDbSession, BuiltInQProfile builtInQProfile) {
- initRuleRepository(batchDbSession);
-
- Date now = new Date(system2.now());
- RulesProfileDto ruleProfile = insertRulesProfile(batchDbSession, builtInQProfile, now);
-
- List<ActiveRuleChange> changes = builtInQProfile.getActiveRules().stream()
- .map(activeRule -> insertActiveRule(batchDbSession, ruleProfile, activeRule, now.getTime()))
- .collect(MoreCollectors.toList());
-
- changes.forEach(change -> dbClient.qProfileChangeDao().insert(batchDbSession, change.toDto(null)));
-
- createDefaultAndOrgQProfiles(batchDbSession, builtInQProfile, ruleProfile);
-
- activeRuleIndexer.commitAndIndex(batchDbSession, changes);
- }
-
-
- private void createDefaultAndOrgQProfiles(DbSession batchDbSession, BuiltInQProfile builtIn, RulesProfileDto rulesProfileDto) {
- Optional<String> qProfileUuid = dbClient.defaultQProfileDao().selectDefaultQProfileUuid(batchDbSession, builtIn.getLanguage());
-
- OrgQProfileDto dto = new OrgQProfileDto()
- .setRulesProfileUuid(rulesProfileDto.getUuid())
- .setUuid(uuidFactory.create());
-
- if (builtIn.isDefault() && qProfileUuid.isEmpty()) {
- DefaultQProfileDto defaultQProfileDto = new DefaultQProfileDto()
- .setQProfileUuid(dto.getUuid())
- .setLanguage(builtIn.getLanguage());
- dbClient.defaultQProfileDao().insert(batchDbSession, defaultQProfileDto);
- }
-
- dbClient.qualityProfileDao().insert(batchDbSession, dto);
- }
-
- private void initRuleRepository(DbSession dbSession) {
- if (ruleRepository == null) {
- ruleRepository = new RuleRepository(dbClient, dbSession, ruleFinder);
- }
- }
-
- private RulesProfileDto insertRulesProfile(DbSession dbSession, BuiltInQProfile builtIn, Date now) {
- RulesProfileDto dto = new RulesProfileDto()
- .setUuid(uuidFactory.create())
- .setName(builtIn.getName())
- .setLanguage(builtIn.getLanguage())
- .setIsBuiltIn(true)
- .setRulesUpdatedAtAsDate(now);
- dbClient.qualityProfileDao().insert(dbSession, dto);
- return dto;
- }
-
- private ActiveRuleChange insertActiveRule(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));
-
- ActiveRuleDto dto = new ActiveRuleDto();
- dto.setProfileUuid(rulesProfileDto.getUuid());
- dto.setRuleUuid(ruleDefinitionDto.getUuid());
- dto.setKey(ActiveRuleKey.of(rulesProfileDto, ruleDefinitionDto.getKey()));
- dto.setSeverity(firstNonNull(activeRule.getSeverity(), ruleDefinitionDto.getSeverityString()));
- dto.setUpdatedAt(now);
- dto.setCreatedAt(now);
- dbClient.activeRuleDao().insert(batchDbSession, dto);
-
- List<ActiveRuleParamDto> paramDtos = insertActiveRuleParams(batchDbSession, activeRule, dto);
-
- ActiveRuleChange change = new ActiveRuleChange(ActiveRuleChange.Type.ACTIVATED, dto, ruleDefinitionDto);
- change.setSeverity(dto.getSeverityString());
- paramDtos.forEach(paramDto -> change.setParameter(paramDto.getKey(), paramDto.getValue()));
- return change;
- }
-
- 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()
- .map(param -> createParamDto(param, Optional.ofNullable(valuesByParamKey.get(param.getName())).orElse(param.getDefaultValue())))
- .filter(Objects::nonNull)
- .collect(Collectors.toList());
-
- rules.forEach(paramDto -> dbClient.activeRuleDao().insertParam(session, activeRuleDto, paramDto));
- return rules;
- }
-
- @CheckForNull
- private ActiveRuleParamDto createParamDto(RuleParamDto param, @Nullable String value) {
- if (value == null) {
- return null;
- }
- ActiveRuleParamDto paramDto = ActiveRuleParamDto.createFor(param);
- paramDto.setValue(validateParam(param, value));
- return paramDto;
- }
-
- private String validateParam(RuleParamDto ruleParam, String value) {
- RuleParamType ruleParamType = RuleParamType.parse(ruleParam.getType());
- if (ruleParamType.multiple()) {
- List<String> values = newArrayList(Splitter.on(",").split(value));
- typeValidations.validate(values, ruleParamType.type(), ruleParamType.values());
- } else {
- typeValidations.validate(value, ruleParamType.type(), ruleParamType.values());
- }
- return value;
- }
-
- private static class RuleRepository {
- 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()));
-
- if (ruleKey.isPresent()) {
- params.computeIfAbsent(ruleKey.get(), r -> new HashSet<>()).add(ruleParam);
- }
- }
- }
-
- private Optional<RuleDefinitionDto> getDefinition(RuleKey ruleKey) {
- return ruleFinder.findDtoByKey(requireNonNull(ruleKey, "RuleKey can't be null"));
- }
-
- private Set<RuleParamDto> getRuleParams(RuleKey ruleKey) {
- return params.getOrDefault(requireNonNull(ruleKey, "RuleKey can't be null"), emptySet());
- }
- }
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileLoader.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileLoader.java
deleted file mode 100644
index b97571648de..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileLoader.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import org.picocontainer.Startable;
-
-/**
- * Startable added to {@link org.sonar.server.platform.platformlevel.PlatformLevelStartup} responsible for initializing
- * {@link BuiltInQProfileRepository}.
- */
-public class BuiltInQProfileLoader implements Startable {
- private final BuiltInQProfileRepository builtInQProfileRepository;
-
- public BuiltInQProfileLoader(BuiltInQProfileRepository builtInQProfileRepository) {
- this.builtInQProfileRepository = builtInQProfileRepository;
- }
-
- @Override
- public void start() {
- builtInQProfileRepository.initialize();
- }
-
- @Override
- public void stop() {
- // nothing to do
- }
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepository.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepository.java
deleted file mode 100644
index 72db5b95b49..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepository.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import java.util.List;
-
-public interface BuiltInQProfileRepository {
- /**
- * Initializes the Repository.
- *
- * This method is intended to be called from a startup task
- * (see {@link org.sonar.server.platform.platformlevel.PlatformLevelStartup}).
- *
- * @throws IllegalStateException if called more then once
- */
- void initialize();
-
- /**
- * @return an immutable list
- *
- * @throws IllegalStateException if {@link #initialize()} has not been called
- */
- List<BuiltInQProfile> get();
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImpl.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImpl.java
deleted file mode 100644
index 57ca9b115ae..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImpl.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Multimap;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-import javax.annotation.Nullable;
-import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
-import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.BuiltInQualityProfile;
-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.util.stream.MoreCollectors;
-import org.sonar.db.DbClient;
-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;
-
-public class BuiltInQProfileRepositoryImpl implements BuiltInQProfileRepository {
- private static final Logger LOGGER = Loggers.get(BuiltInQProfileRepositoryImpl.class);
- 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, ServerRuleFinder ruleFinder, Languages languages) {
- this(dbClient, ruleFinder, languages, new BuiltInQualityProfilesDefinition[0]);
- }
-
- public BuiltInQProfileRepositoryImpl(DbClient dbClient, ServerRuleFinder ruleFinder, Languages languages, BuiltInQualityProfilesDefinition... definitions) {
- this.dbClient = dbClient;
- this.ruleFinder = ruleFinder;
- this.languages = languages;
- this.definitions = ImmutableList.copyOf(definitions);
- }
-
- @Override
- public void initialize() {
- checkState(qProfiles == null, "initialize must be called only once");
-
- Profiler profiler = Profiler.create(LOGGER).startInfo("Load quality profiles");
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- for (BuiltInQualityProfilesDefinition definition : definitions) {
- definition.define(context);
- }
- Map<String, Map<String, BuiltInQualityProfile>> rulesProfilesByLanguage = validateAndClean(context);
- this.qProfiles = toFlatList(rulesProfilesByLanguage);
- ensureAllLanguagesHaveAtLeastOneBuiltInQP();
- profiler.stopDebug();
- }
-
- @Override
- public List<BuiltInQProfile> get() {
- checkState(qProfiles != null, "initialize must be called first");
-
- return qProfiles;
- }
-
- private void ensureAllLanguagesHaveAtLeastOneBuiltInQP() {
- Set<String> languagesWithBuiltInQProfiles = qProfiles.stream().map(BuiltInQProfile::getLanguage).collect(Collectors.toSet());
- Set<String> languagesWithoutBuiltInQProfiles = Arrays.stream(languages.all())
- .map(Language::getKey)
- .filter(key -> !languagesWithBuiltInQProfiles.contains(key))
- .collect(Collectors.toSet());
-
- checkState(languagesWithoutBuiltInQProfiles.isEmpty(), "The following languages have no built-in quality profiles: %s",
- String.join("", languagesWithoutBuiltInQProfiles));
- }
-
- private Map<String, Map<String, BuiltInQualityProfile>> validateAndClean(BuiltInQualityProfilesDefinition.Context context) {
- Map<String, Map<String, BuiltInQualityProfile>> profilesByLanguageAndName = context.profilesByLanguageAndName();
- profilesByLanguageAndName.entrySet()
- .removeIf(entry -> {
- String language = entry.getKey();
- if (languages.get(language) == null) {
- LOGGER.info("Language {} is not installed, related quality profiles are ignored", language);
- return true;
- }
- return false;
- });
-
- return profilesByLanguageAndName;
- }
-
- private List<BuiltInQProfile> toFlatList(Map<String, Map<String, BuiltInQualityProfile>> rulesProfilesByLanguage) {
- if (rulesProfilesByLanguage.isEmpty()) {
- return Collections.emptyList();
- }
- Map<RuleKey, RuleDefinitionDto> rulesByRuleKey = loadRuleDefinitionsByRuleKey();
- Map<String, List<BuiltInQProfile.Builder>> buildersByLanguage = rulesProfilesByLanguage
- .entrySet()
- .stream()
- .collect(MoreCollectors.uniqueIndex(
- Map.Entry::getKey,
- rulesProfilesByLanguageAndName -> toQualityProfileBuilders(rulesProfilesByLanguageAndName, rulesByRuleKey)));
- return buildersByLanguage
- .entrySet()
- .stream()
- .filter(BuiltInQProfileRepositoryImpl::ensureAtMostOneDeclaredDefault)
- .map(entry -> toQualityProfiles(entry.getValue()))
- .flatMap(Collection::stream)
- .collect(MoreCollectors.toList());
- }
-
- private Map<RuleKey, RuleDefinitionDto> loadRuleDefinitionsByRuleKey() {
- try (DbSession dbSession = dbClient.openSession(false)) {
- 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<>();
- for (RuleDefinitionDto ruleDefinition : ruleDefinitions) {
- rulesByRuleKey.put(ruleDefinition.getKey(), ruleDefinition);
- deprecatedRuleKeysByRuleId.get(ruleDefinition.getUuid()).forEach(t -> rulesByRuleKey.put(RuleKey.of(t.getOldRepositoryKey(), t.getOldRuleKey()), ruleDefinition));
- }
- return rulesByRuleKey;
- }
- }
-
- /**
- * Creates {@link BuiltInQProfile.Builder} for each unique quality profile name for a given language.
- * Builders will have the following properties populated:
- * <ul>
- * <li>{@link BuiltInQProfile.Builder#language language}: key of the method's parameter</li>
- * <li>{@link BuiltInQProfile.Builder#name name}: {@link RulesProfile#getName()}</li>
- * <li>{@link BuiltInQProfile.Builder#declaredDefault declaredDefault}: {@code true} if at least one RulesProfile
- * with a given name has {@link RulesProfile#getDefaultProfile()} is {@code true}</li>
- * <li>{@link BuiltInQProfile.Builder#activeRules activeRules}: the concatenate of the active rules of all
- * RulesProfile with a given name</li>
- * </ul>
- */
- private static List<BuiltInQProfile.Builder> toQualityProfileBuilders(Map.Entry<String, Map<String, BuiltInQualityProfile>> rulesProfilesByLanguageAndName,
- Map<RuleKey, RuleDefinitionDto> rulesByRuleKey) {
- String language = rulesProfilesByLanguageAndName.getKey();
- // use a LinkedHashMap to keep order of insertion of RulesProfiles
- Map<String, BuiltInQProfile.Builder> qualityProfileBuildersByName = new LinkedHashMap<>();
- for (BuiltInQualityProfile builtInProfile : rulesProfilesByLanguageAndName.getValue().values()) {
- qualityProfileBuildersByName.compute(
- builtInProfile.name(),
- (name, existingBuilder) -> updateOrCreateBuilder(language, existingBuilder, builtInProfile, rulesByRuleKey));
- }
- return ImmutableList.copyOf(qualityProfileBuildersByName.values());
- }
-
- /**
- * Fails if more than one {@link BuiltInQProfile.Builder#declaredDefault} is {@code true}, otherwise returns {@code true}.
- */
- private static boolean ensureAtMostOneDeclaredDefault(Map.Entry<String, List<BuiltInQProfile.Builder>> entry) {
- Set<String> declaredDefaultProfileNames = entry.getValue().stream()
- .filter(BuiltInQProfile.Builder::isDeclaredDefault)
- .map(BuiltInQProfile.Builder::getName)
- .collect(MoreCollectors.toSet());
- checkState(declaredDefaultProfileNames.size() <= 1, "Several Quality profiles are flagged as default for the language %s: %s", entry.getKey(), declaredDefaultProfileNames);
- return true;
- }
-
- private static BuiltInQProfile.Builder updateOrCreateBuilder(String language, @Nullable BuiltInQProfile.Builder existingBuilder, BuiltInQualityProfile builtInProfile,
- Map<RuleKey, RuleDefinitionDto> rulesByRuleKey) {
- BuiltInQProfile.Builder builder = createOrReuseBuilder(existingBuilder, language, builtInProfile);
- builder.setDeclaredDefault(builtInProfile.isDefault());
- builtInProfile.rules().forEach(builtInActiveRule -> {
- RuleKey ruleKey = RuleKey.of(builtInActiveRule.repoKey(), builtInActiveRule.ruleKey());
- RuleDefinitionDto ruleDefinition = rulesByRuleKey.get(ruleKey);
- checkState(ruleDefinition != null, "Rule with key '%s' not found", ruleKey);
- builder.addRule(new BuiltInQProfile.ActiveRule(ruleDefinition.getUuid(), ruleDefinition.getKey(),
- builtInActiveRule.overriddenSeverity(), builtInActiveRule.overriddenParams()));
- });
- return builder;
- }
-
- private static BuiltInQProfile.Builder createOrReuseBuilder(@Nullable BuiltInQProfile.Builder existingBuilder, String language, BuiltInQualityProfile builtInProfile) {
- if (existingBuilder == null) {
- return new BuiltInQProfile.Builder()
- .setLanguage(language)
- .setName(builtInProfile.name());
- }
- return existingBuilder;
- }
-
- private static List<BuiltInQProfile> toQualityProfiles(List<BuiltInQProfile.Builder> builders) {
- if (builders.stream().noneMatch(BuiltInQProfile.Builder::isDeclaredDefault)) {
- Optional<BuiltInQProfile.Builder> sonarWayProfile = builders.stream().filter(builder -> builder.getName().equals(DEFAULT_PROFILE_NAME)).findFirst();
- if (sonarWayProfile.isPresent()) {
- sonarWayProfile.get().setComputedDefault(true);
- } else {
- builders.iterator().next().setComputedDefault(true);
- }
- }
- return builders.stream()
- .map(BuiltInQProfile.Builder::build)
- .collect(MoreCollectors.toList(builders.size()));
- }
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdate.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdate.java
deleted file mode 100644
index 44403a027e7..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdate.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import java.util.List;
-import org.sonar.db.DbSession;
-import org.sonar.db.qualityprofile.RulesProfileDto;
-
-public interface BuiltInQProfileUpdate {
- /**
- * Persist an existing built-in profile.
- * Db session is committed and Elasticsearch indices are updated.
- */
- List<ActiveRuleChange> update(DbSession dbSession, BuiltInQProfile builtInQProfile, RulesProfileDto ruleProfile);
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImpl.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImpl.java
deleted file mode 100644
index 9f0f059f6b5..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImpl.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Stream;
-import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
-import org.sonar.core.util.stream.MoreCollectors;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.qualityprofile.ActiveRuleDto;
-import org.sonar.db.qualityprofile.RulesProfileDto;
-import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
-
-import static org.sonar.core.util.stream.MoreCollectors.toSet;
-
-public class BuiltInQProfileUpdateImpl implements BuiltInQProfileUpdate {
-
- private final DbClient dbClient;
- private final RuleActivator ruleActivator;
- private final ActiveRuleIndexer activeRuleIndexer;
- private final QualityProfileChangeEventService qualityProfileChangeEventService;
-
- public BuiltInQProfileUpdateImpl(DbClient dbClient, RuleActivator ruleActivator, ActiveRuleIndexer activeRuleIndexer,
- QualityProfileChangeEventService qualityProfileChangeEventService) {
- this.dbClient = dbClient;
- this.ruleActivator = ruleActivator;
- this.activeRuleIndexer = activeRuleIndexer;
- this.qualityProfileChangeEventService = qualityProfileChangeEventService;
- }
-
- public List<ActiveRuleChange> update(DbSession dbSession, BuiltInQProfile builtInDefinition, RulesProfileDto initialRuleProfile) {
- // Keep reference to all the activated rules before update
- Set<String> deactivatedRuleUuids = dbClient.activeRuleDao().selectByRuleProfile(dbSession, initialRuleProfile)
- .stream()
- .map(ActiveRuleDto::getRuleUuid)
- .collect(MoreCollectors.toHashSet());
-
- // all rules, including those which are removed from built-in profile
- Set<String> ruleUuids = Stream.concat(
- deactivatedRuleUuids.stream(),
- builtInDefinition.getActiveRules().stream().map(BuiltInQProfile.ActiveRule::getRuleUuid))
- .collect(toSet());
-
- Collection<RuleActivation> activations = new ArrayList<>();
- for (BuiltInQProfile.ActiveRule ar : builtInDefinition.getActiveRules()) {
- RuleActivation activation = convert(ar);
- activations.add(activation);
- deactivatedRuleUuids.remove(activation.getRuleUuid());
- }
-
- RuleActivationContext context = ruleActivator.createContextForBuiltInProfile(dbSession, initialRuleProfile, ruleUuids);
- List<ActiveRuleChange> changes = new ArrayList<>();
-
- changes.addAll(ruleActivator.activate(dbSession, activations, context));
-
- // these rules are no longer part of the built-in profile
- deactivatedRuleUuids.forEach(ruleUuid -> changes.addAll(ruleActivator.deactivate(dbSession, context, ruleUuid, false)));
-
- if (!changes.isEmpty()) {
- qualityProfileChangeEventService.distributeRuleChangeEvent(context.getProfiles(), changes, initialRuleProfile.getLanguage());
- }
-
- activeRuleIndexer.commitAndIndex(dbSession, changes);
- return changes;
- }
-
- private static RuleActivation convert(BuiltInQProfile.ActiveRule ar) {
- Map<String, String> params = ar.getParams().stream()
- .collect(MoreCollectors.uniqueIndex(BuiltInQualityProfilesDefinition.OverriddenParam::key, BuiltInQualityProfilesDefinition.OverriddenParam::overriddenValue));
- return RuleActivation.create(ar.getRuleUuid(), ar.getSeverity(), params);
- }
-
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesUpdateListener.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesUpdateListener.java
deleted file mode 100644
index 0e9a2ae021f..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesUpdateListener.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import com.google.common.collect.Multimap;
-import java.util.Collection;
-import org.sonar.api.config.Configuration;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Languages;
-import org.sonar.server.notification.NotificationManager;
-import org.sonar.server.qualityprofile.BuiltInQPChangeNotificationBuilder.Profile;
-
-import static org.sonar.core.config.CorePropertyDefinitions.DISABLE_NOTIFICATION_ON_BUILT_IN_QPROFILES;
-import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.ACTIVATED;
-import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.DEACTIVATED;
-import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.UPDATED;
-
-public class BuiltInQualityProfilesUpdateListener {
-
- private final NotificationManager notificationManager;
- private final Languages languages;
- private final Configuration config;
-
- public BuiltInQualityProfilesUpdateListener(NotificationManager notificationManager, Languages languages, Configuration config) {
- this.notificationManager = notificationManager;
- this.languages = languages;
- this.config = config;
- }
-
- void onChange(Multimap<QProfileName, ActiveRuleChange> changedProfiles, long startDate, long endDate) {
- if (config.getBoolean(DISABLE_NOTIFICATION_ON_BUILT_IN_QPROFILES).orElse(false)) {
- return;
- }
-
- BuiltInQPChangeNotificationBuilder builder = new BuiltInQPChangeNotificationBuilder();
- changedProfiles.keySet().stream()
- .map(changedProfile -> {
- String profileName = changedProfile.getName();
- Language language = languages.get(changedProfile.getLanguage());
- Collection<ActiveRuleChange> activeRuleChanges = changedProfiles.get(changedProfile);
- int newRules = (int) activeRuleChanges.stream().map(ActiveRuleChange::getType).filter(ACTIVATED::equals).count();
- int updatedRules = (int) activeRuleChanges.stream().map(ActiveRuleChange::getType).filter(UPDATED::equals).count();
- int removedRules = (int) activeRuleChanges.stream().map(ActiveRuleChange::getType).filter(DEACTIVATED::equals).count();
- return Profile.newBuilder()
- .setProfileName(profileName)
- .setLanguageKey(language.getKey())
- .setLanguageName(language.getName())
- .setNewRules(newRules)
- .setUpdatedRules(updatedRules)
- .setRemovedRules(removedRules)
- .setStartDate(startDate)
- .setEndDate(endDate)
- .build();
- })
- .forEach(builder::addProfile);
-
- notificationManager.scheduleForSending(builder.build());
- }
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/DescendantProfilesSupplier.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/DescendantProfilesSupplier.java
deleted file mode 100644
index 10127dc0c8e..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/DescendantProfilesSupplier.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import java.util.Collection;
-import org.sonar.db.qualityprofile.ActiveRuleDto;
-import org.sonar.db.qualityprofile.ActiveRuleParamDto;
-import org.sonar.db.qualityprofile.QProfileDto;
-
-@FunctionalInterface
-public interface DescendantProfilesSupplier {
-
- Result get(Collection<QProfileDto> profiles, Collection<String> ruleUuids);
-
- final class Result {
- private final Collection<QProfileDto> profiles;
- private final Collection<ActiveRuleDto> activeRules;
- private final Collection<ActiveRuleParamDto> activeRuleParams;
-
- public Result(Collection<QProfileDto> profiles, Collection<ActiveRuleDto> activeRules, Collection<ActiveRuleParamDto> activeRuleParams) {
- this.profiles = profiles;
- this.activeRules = activeRules;
- this.activeRuleParams = activeRuleParams;
- }
-
- public Collection<QProfileDto> getProfiles() {
- return profiles;
- }
-
- public Collection<ActiveRuleDto> getActiveRules() {
- return activeRules;
- }
-
- public Collection<ActiveRuleParamDto> getActiveRuleParams() {
- return activeRuleParams;
- }
- }
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/DistributedRuleActivatorEventsDistributor.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/DistributedRuleActivatorEventsDistributor.java
deleted file mode 100644
index a6a3b847913..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/DistributedRuleActivatorEventsDistributor.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import org.sonar.api.server.ServerSide;
-import org.sonar.core.util.RuleActivationListener;
-import org.sonar.core.util.RuleSetChangeEvent;
-import org.sonar.process.cluster.hz.HazelcastMember;
-
-@ServerSide
-public class DistributedRuleActivatorEventsDistributor implements RuleActivatorEventsDistributor {
-
- private HazelcastMember hazelcastMember;
-
- public DistributedRuleActivatorEventsDistributor(HazelcastMember hazelcastMember) {
- this.hazelcastMember = hazelcastMember;
- }
-
- @Override
- public void subscribe(RuleActivationListener listener) {
- hazelcastMember.subscribeRuleActivationTopic(listener);
- }
-
- @Override
- public void pushEvent(RuleSetChangeEvent event) {
- hazelcastMember.publishEvent(event);
- }
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/QProfileName.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/QProfileName.java
deleted file mode 100644
index ad910ce3f0f..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/QProfileName.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import javax.annotation.Nullable;
-
-public class QProfileName {
- private final String lang;
- private final String name;
-
- public QProfileName(String lang, String name) {
- this.lang = lang;
- this.name = name;
- }
-
- public String getLanguage() {
- return lang;
- }
-
- public String getName() {
- return name;
- }
-
- public static QProfileName createFor(String lang, String name){
- return new QProfileName(lang, name);
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- QProfileName that = (QProfileName) o;
- if (!lang.equals(that.lang)) {
- return false;
- }
- return name.equals(that.name);
- }
-
- @Override
- public int hashCode() {
- int result = lang.hashCode();
- result = 31 * result + name.hashCode();
- return result;
- }
-
- @Override
- public String toString() {
- return String.format("%s/%s", lang, name);
- }
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/QualityProfileChangeEventService.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/QualityProfileChangeEventService.java
deleted file mode 100644
index 008afff27f5..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/QualityProfileChangeEventService.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Optional;
-import org.sonar.db.project.ProjectDto;
-import org.sonar.db.qualityprofile.QProfileDto;
-
-public interface QualityProfileChangeEventService {
-
- void publishRuleActivationToSonarLintClients(ProjectDto project, Optional<QProfileDto> activatedProfile, Optional<QProfileDto> deactivatedProfile);
-
- void distributeRuleChangeEvent(Collection<QProfileDto> profiles, List<ActiveRuleChange> activeRuleChanges, String language);
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/QualityProfileChangeEventServiceImpl.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/QualityProfileChangeEventServiceImpl.java
deleted file mode 100644
index 22c96e6ff4a..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/QualityProfileChangeEventServiceImpl.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-import org.jetbrains.annotations.NotNull;
-import org.sonar.api.server.ServerSide;
-import org.sonar.core.util.ParamChange;
-import org.sonar.core.util.RuleChange;
-import org.sonar.core.util.RuleSetChangeEvent;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.project.ProjectDto;
-import org.sonar.db.qualityprofile.ActiveRuleParamDto;
-import org.sonar.db.qualityprofile.ProjectQprofileAssociationDto;
-import org.sonar.db.qualityprofile.QProfileDto;
-import org.sonar.db.rule.RuleDto;
-import org.sonar.server.rule.index.RuleIndex;
-import org.sonar.server.rule.index.RuleQuery;
-
-@ServerSide
-public class QualityProfileChangeEventServiceImpl implements QualityProfileChangeEventService {
-
- private final DbClient dbClient;
- private final RuleIndex ruleIndex;
- private final RuleActivatorEventsDistributor eventsDistributor;
-
- public QualityProfileChangeEventServiceImpl(DbClient dbClient, RuleIndex ruleIndex, RuleActivatorEventsDistributor eventsDistributor) {
- this.dbClient = dbClient;
- this.ruleIndex = ruleIndex;
- this.eventsDistributor = eventsDistributor;
- }
-
- @Override
- public void publishRuleActivationToSonarLintClients(ProjectDto project, Optional<QProfileDto> activatedProfile, Optional<QProfileDto> deactivatedProfile) {
- List<RuleChange> activatedRules = new ArrayList<>();
- List<RuleChange> deactivatedRules = new ArrayList<>();
-
- try (DbSession dbSession = dbClient.openSession(false)) {
-
- if (activatedProfile.isPresent()) {
- RuleQuery query = new RuleQuery().setQProfile(activatedProfile.get()).setActivation(true).setIncludeExternal(true);
- // .setLanguages() ?
- Iterator<String> searchIdResult = ruleIndex.searchAll(query);
- List<String> uuids = new ArrayList<>();
- while (searchIdResult.hasNext()) {
- uuids.add(searchIdResult.next());
- }
-
- List<RuleDto> ruleDtos = dbClient.ruleDao().selectByUuids(dbSession, uuids);
- Map<String, List<ActiveRuleParamDto>> paramsByRuleUuid = dbClient.activeRuleDao().selectParamsByActiveRuleUuids(dbSession, uuids)
- .stream().collect(Collectors.groupingBy(ActiveRuleParamDto::getActiveRuleUuid));
-
- for (RuleDto ruleDto : ruleDtos) {
- RuleChange ruleChange = toRuleChange(ruleDto, paramsByRuleUuid);
- activatedRules.add(ruleChange);
- }
- }
-
- if (deactivatedProfile.isPresent()) {
- RuleQuery query = new RuleQuery().setQProfile(deactivatedProfile.get()).setActivation(true).setIncludeExternal(true);
- // .setLanguages() ?
- Iterator<String> searchIdResult = ruleIndex.searchAll(query);
- List<String> uuids = new ArrayList<>();
- while (searchIdResult.hasNext()) {
- uuids.add(searchIdResult.next());
- }
-
- List<RuleDto> ruleDtos = dbClient.ruleDao().selectByUuids(dbSession, uuids);
- Map<String, List<ActiveRuleParamDto>> paramsByRuleUuid = dbClient.activeRuleDao().selectParamsByActiveRuleUuids(dbSession, uuids)
- .stream().collect(Collectors.groupingBy(ActiveRuleParamDto::getActiveRuleUuid));
-
- for (RuleDto ruleDto : ruleDtos) {
- RuleChange ruleChange = toRuleChange(ruleDto, paramsByRuleUuid);
- deactivatedRules.add(ruleChange);
- }
- }
-
- }
-
- RuleSetChangeEvent event = new RuleSetChangeEvent(new String[]{project.getKey()}, activatedRules.toArray(new RuleChange[0]), deactivatedRules.toArray(new RuleChange[0]));
- eventsDistributor.pushEvent(event);
- }
-
- @NotNull
- private RuleChange toRuleChange(RuleDto ruleDto, Map<String, List<ActiveRuleParamDto>> paramsByRuleUuid) {
- RuleChange ruleChange = new RuleChange();
- ruleChange.setKey(ruleDto.getRuleKey());
- ruleChange.setLanguage(ruleDto.getLanguage());
- ruleChange.setSeverity(ruleDto.getSeverityString());
-
- List<ParamChange> paramChanges = new ArrayList<>();
- List<ActiveRuleParamDto> activeRuleParamDtos = paramsByRuleUuid.getOrDefault(ruleDto.getUuid(), new ArrayList<>());
- for (ActiveRuleParamDto activeRuleParam : activeRuleParamDtos) {
- paramChanges.add(new ParamChange(activeRuleParam.getKey(), activeRuleParam.getValue()));
- }
- ruleChange.setParams(paramChanges.toArray(new ParamChange[0]));
-
- String templateUuid = ruleDto.getTemplateUuid();
- if (templateUuid != null && !"".equals(templateUuid)) {
- try (DbSession dbSession = dbClient.openSession(false)) {
- RuleDto templateRule = dbClient.ruleDao().selectByUuid(templateUuid, dbSession)
- .orElseThrow(() -> new IllegalStateException(String.format("unknow Template Rule '%s'", templateUuid)));
- ruleChange.setTemplateKey(templateRule.getRuleKey());
- }
- }
-
- return ruleChange;
- }
-
- public void distributeRuleChangeEvent(Collection<QProfileDto> profiles, List<ActiveRuleChange> activeRuleChanges, String language) {
- if (activeRuleChanges.isEmpty()) {
- return;
- }
-
- Set<RuleChange> activatedRules = new HashSet<>();
- Set<RuleChange> deactivatedRules = new HashSet<>();
-
- for (ActiveRuleChange arc : activeRuleChanges) {
-
- RuleChange ruleChange = new RuleChange();
- ruleChange.setKey(arc.getActiveRule().getRuleKey().rule());
- ruleChange.setSeverity(arc.getSeverity());
- ruleChange.setLanguage(language);
-
- Optional<String> templateKey = templateKey(arc);
- templateKey.ifPresent(ruleChange::setTemplateKey);
-
- // params
- List<ParamChange> paramChanges = new ArrayList<>();
- for (Map.Entry<String, String> entry : arc.getParameters().entrySet()) {
- paramChanges.add(new ParamChange(entry.getKey(), entry.getValue()));
- }
- ruleChange.setParams(paramChanges.toArray(new ParamChange[0]));
-
- switch (arc.getType()) {
- case ACTIVATED:
- case UPDATED:
- activatedRules.add(ruleChange);
- break;
- case DEACTIVATED:
- deactivatedRules.add(ruleChange);
- break;
- }
- }
-
- Set<String> projectKeys = getProjectKeys(profiles);
-
- RuleSetChangeEvent event = new RuleSetChangeEvent(projectKeys.toArray(new String[0]), activatedRules.toArray(new RuleChange[0]), deactivatedRules.toArray(new RuleChange[0]));
- eventsDistributor.pushEvent(event);
-
- }
-
- private Optional<String> templateKey(ActiveRuleChange arc) {
- try (DbSession dbSession = dbClient.openSession(false)) {
- String ruleUuid = arc.getRuleUuid();
- RuleDto rule = dbClient.ruleDao().selectByUuid(ruleUuid, dbSession).orElseThrow(() -> new IllegalStateException("unknow rule"));
- String templateUuid = rule.getTemplateUuid();
- if (templateUuid != null && !"".equals(templateUuid)) {
- RuleDto templateRule = dbClient.ruleDao().selectByUuid(templateUuid, dbSession)
- .orElseThrow(() -> new IllegalStateException(String.format("unknow Template Rule '%s'", templateUuid)));
- return Optional.of(templateRule.getRuleKey());
- }
- }
- return Optional.empty();
- }
-
- private Set<String> getProjectKeys(Collection<QProfileDto> profiles) {
- Set<String> projectKeys = new HashSet<>();
- try (DbSession dbSession = dbClient.openSession(false)) {
- for (QProfileDto profileDto : profiles) {
- List<ProjectQprofileAssociationDto> associationDtos = dbClient.qualityProfileDao().selectSelectedProjects(dbSession, profileDto, null);
- for (ProjectQprofileAssociationDto associationDto : associationDtos) {
- projectKeys.add(associationDto.getProjectKey());
- }
- }
- return projectKeys;
- }
- }
-
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/RuleActivationContext.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/RuleActivationContext.java
deleted file mode 100644
index 458926e98bd..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/RuleActivationContext.java
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.ListMultimap;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.stream.Collectors;
-import javax.annotation.CheckForNull;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.db.qualityprofile.ActiveRuleDto;
-import org.sonar.db.qualityprofile.ActiveRuleKey;
-import org.sonar.db.qualityprofile.ActiveRuleParamDto;
-import org.sonar.db.qualityprofile.QProfileDto;
-import org.sonar.db.qualityprofile.RulesProfileDto;
-import org.sonar.db.rule.RuleDefinitionDto;
-import org.sonar.db.rule.RuleParamDto;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-import static java.util.Objects.requireNonNull;
-import static org.sonar.core.util.stream.MoreCollectors.index;
-import static org.sonar.core.util.stream.MoreCollectors.toArrayList;
-import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
-import static org.sonar.server.exceptions.BadRequestException.checkRequest;
-
-/**
- * Cache of the data required to activate/deactivate
- * multiple rules on a Quality profile, including
- * the rule definitions, the rule parameters, the tree
- * of profiles hierarchy and its related active rules.
- */
-class RuleActivationContext {
-
- private final long date;
-
- // The profile that is initially targeted by the operation
- private final RulesProfileDto baseRulesProfile;
-
- private final Map<String, QProfileDto> profilesByUuid = new HashMap<>();
- private final ListMultimap<String, QProfileDto> profilesByParentUuid = ArrayListMultimap.create();
-
- // The rules/active rules involved in the group of activations/de-activations
- private final Map<String, RuleWrapper> rulesByUuid = new HashMap<>();
- private final Map<ActiveRuleKey, ActiveRuleWrapper> activeRulesByKey = new HashMap<>();
-
- // Cursors used to move in the rules and in the tree of profiles.
-
- private RulesProfileDto currentRulesProfile;
- // Cardinality is zero-to-many when cursor is on a built-in rules profile,
- // otherwise it's always one, and only one (cursor on descendants or on non-built-in base profile).
- private Collection<QProfileDto> currentProfiles;
- private RuleWrapper currentRule;
- private ActiveRuleWrapper currentActiveRule;
- private ActiveRuleWrapper currentParentActiveRule;
-
- private boolean descendantsLoaded = false;
- private final DescendantProfilesSupplier descendantProfilesSupplier;
-
- private RuleActivationContext(Builder builder) {
- this.date = builder.date;
- this.descendantProfilesSupplier = builder.descendantProfilesSupplier;
-
- ListMultimap<String, RuleParamDto> paramsByRuleId = builder.ruleParams.stream().collect(index(RuleParamDto::getRuleUuid));
- for (RuleDefinitionDto rule : builder.rules) {
- RuleWrapper wrapper = new RuleWrapper(rule, paramsByRuleId.get(rule.getUuid()));
- rulesByUuid.put(rule.getUuid(), wrapper);
- }
-
- this.baseRulesProfile = builder.baseRulesProfile;
- register(builder.profiles);
- register(builder.activeRules, builder.activeRuleParams);
- }
-
- private void register(Collection<QProfileDto> profiles) {
- for (QProfileDto profile : profiles) {
- profilesByUuid.put(profile.getKee(), profile);
- if (profile.getParentKee() != null) {
- profilesByParentUuid.put(profile.getParentKee(), profile);
- }
- }
- }
-
- private void register(Collection<ActiveRuleDto> activeRules, Collection<ActiveRuleParamDto> activeRuleParams) {
- ListMultimap<String, ActiveRuleParamDto> paramsByActiveRuleUuid = activeRuleParams.stream().collect(index(ActiveRuleParamDto::getActiveRuleUuid));
- for (ActiveRuleDto activeRule : activeRules) {
- ActiveRuleWrapper wrapper = new ActiveRuleWrapper(activeRule, paramsByActiveRuleUuid.get(activeRule.getUuid()));
- this.activeRulesByKey.put(activeRule.getKey(), wrapper);
- }
- }
-
- long getDate() {
- return date;
- }
-
- /**
- * The rule currently selected.
- */
- RuleWrapper getRule() {
- checkState(currentRule != null, "Rule has not been set yet");
- return currentRule;
- }
-
- @CheckForNull
- String getRequestedParamValue(RuleActivation request, String key) {
- if (currentRule.rule.isCustomRule()) {
- return null;
- }
- return request.getParameter(key);
- }
-
- boolean hasRequestedParamValue(RuleActivation request, String key) {
- return request.hasParameter(key);
- }
-
- /**
- * The rules profile being selected.
- */
- RulesProfileDto getRulesProfile() {
- checkState(currentRulesProfile != null, "Rule profile has not been set yet");
- return currentRulesProfile;
- }
-
- /**
- * The active rule related to the selected profile and rule.
- * @return null if the selected rule is not activated on the selected profile.
- * @see #getRulesProfile()
- * @see #getRule()
- */
- @CheckForNull
- ActiveRuleWrapper getActiveRule() {
- return currentActiveRule;
- }
-
- /**
- * The active rule related to the rule and the parent of the selected profile.
- * @return null if the selected rule is not activated on the parent profile.
- * @see #getRule()
- */
- @CheckForNull
- ActiveRuleWrapper getParentActiveRule() {
- return currentParentActiveRule;
- }
-
- /**
- * Whether the profile cursor is on the base profile or not.
- */
- boolean isCascading() {
- return currentRulesProfile != null && !currentRulesProfile.getUuid().equals(baseRulesProfile.getUuid());
- }
-
- /**
- * The profiles being selected. Can be zero or many if {@link #getRulesProfile()} is built-in.
- * Else the collection always contains a single profile.
- */
- Collection<QProfileDto> getProfiles() {
- checkState(currentProfiles != null, "Profiles have not been set yet");
- return currentProfiles;
- }
-
- /**
- * The children of {@link #getProfiles()}
- */
- Collection<QProfileDto> getChildProfiles() {
- loadDescendants();
- return getProfiles().stream()
- .flatMap(p -> profilesByParentUuid.get(p.getKee()).stream())
- .collect(Collectors.toList());
- }
-
- private void loadDescendants() {
- if (descendantsLoaded) {
- return;
- }
- Collection<QProfileDto> baseProfiles = profilesByUuid.values().stream()
- .filter(p -> p.getRulesProfileUuid().equals(baseRulesProfile.getUuid()))
- .collect(toArrayList(profilesByUuid.size()));
- DescendantProfilesSupplier.Result result = descendantProfilesSupplier.get(baseProfiles, rulesByUuid.keySet());
- register(result.getProfiles());
- register(result.getActiveRules(), result.getActiveRuleParams());
- descendantsLoaded = true;
- }
-
- /**
- * Move the cursor to the given rule and back to the base profile.
- */
- public void reset(String ruleUuid) {
- doSwitch(this.baseRulesProfile, ruleUuid);
- }
-
- /**
- * Moves cursor to a child profile
- */
- void selectChild(QProfileDto to) {
- checkState(!to.isBuiltIn());
- QProfileDto qp = requireNonNull(this.profilesByUuid.get(to.getKee()), () -> "No profile with uuid " + to.getKee());
-
- RulesProfileDto ruleProfile = RulesProfileDto.from(qp);
- doSwitch(ruleProfile, getRule().get().getUuid());
- }
-
- private void doSwitch(RulesProfileDto ruleProfile, String ruleUuid) {
- this.currentRule = rulesByUuid.get(ruleUuid);
- checkRequest(this.currentRule != null, "Rule with UUID %s not found", ruleUuid);
- RuleKey ruleKey = currentRule.get().getKey();
-
- this.currentRulesProfile = ruleProfile;
- this.currentProfiles = profilesByUuid.values().stream()
- .filter(p -> p.getRulesProfileUuid().equals(ruleProfile.getUuid()))
- .collect(Collectors.toList());
- this.currentActiveRule = this.activeRulesByKey.get(ActiveRuleKey.of(ruleProfile, ruleKey));
- this.currentParentActiveRule = this.currentProfiles.stream()
- .map(QProfileDto::getParentKee)
- .filter(Objects::nonNull)
- .map(profilesByUuid::get)
- .filter(Objects::nonNull)
- .findFirst()
- .map(profile -> activeRulesByKey.get(ActiveRuleKey.of(profile, ruleKey)))
- .orElse(null);
- }
-
- static final class Builder {
- private long date = System.currentTimeMillis();
- private RulesProfileDto baseRulesProfile;
- private Collection<RuleDefinitionDto> rules;
- private Collection<RuleParamDto> ruleParams;
- private Collection<QProfileDto> profiles;
- private Collection<ActiveRuleDto> activeRules;
- private Collection<ActiveRuleParamDto> activeRuleParams;
- private DescendantProfilesSupplier descendantProfilesSupplier;
-
- Builder setDate(long l) {
- this.date = l;
- return this;
- }
-
- Builder setBaseProfile(RulesProfileDto p) {
- this.baseRulesProfile = p;
- return this;
- }
-
- Builder setRules(Collection<RuleDefinitionDto> rules) {
- this.rules = rules;
- return this;
- }
-
- Builder setRuleParams(Collection<RuleParamDto> ruleParams) {
- this.ruleParams = ruleParams;
- return this;
- }
-
- /**
- * All the profiles involved in the activation workflow, including the
- * parent profile, even if it's not updated.
- */
- Builder setProfiles(Collection<QProfileDto> profiles) {
- this.profiles = profiles;
- return this;
- }
-
- Builder setActiveRules(Collection<ActiveRuleDto> activeRules) {
- this.activeRules = activeRules;
- return this;
- }
-
- Builder setActiveRuleParams(Collection<ActiveRuleParamDto> activeRuleParams) {
- this.activeRuleParams = activeRuleParams;
- return this;
- }
-
- Builder setDescendantProfilesSupplier(DescendantProfilesSupplier d) {
- this.descendantProfilesSupplier = d;
- return this;
- }
-
- RuleActivationContext build() {
- checkArgument(date > 0, "date is not set");
- requireNonNull(baseRulesProfile, "baseRulesProfile is null");
- requireNonNull(rules, "rules is null");
- requireNonNull(ruleParams, "ruleParams is null");
- requireNonNull(profiles, "profiles is null");
- requireNonNull(activeRules, "activeRules is null");
- requireNonNull(activeRuleParams, "activeRuleParams is null");
- requireNonNull(descendantProfilesSupplier, "descendantProfilesSupplier is null");
- return new RuleActivationContext(this);
- }
- }
-
- static final class RuleWrapper {
- private final RuleDefinitionDto rule;
- private final Map<String, RuleParamDto> paramsByKey;
-
- private RuleWrapper(RuleDefinitionDto rule, Collection<RuleParamDto> params) {
- this.rule = rule;
- this.paramsByKey = params.stream().collect(uniqueIndex(RuleParamDto::getName));
- }
-
- RuleDefinitionDto get() {
- return rule;
- }
-
- Collection<RuleParamDto> getParams() {
- return paramsByKey.values();
- }
-
- @CheckForNull
- RuleParamDto getParam(String key) {
- return paramsByKey.get(key);
- }
-
- @CheckForNull
- String getParamDefaultValue(String key) {
- RuleParamDto param = getParam(key);
- return param != null ? param.getDefaultValue() : null;
- }
- }
-
- static final class ActiveRuleWrapper {
- private final ActiveRuleDto activeRule;
- private final Map<String, ActiveRuleParamDto> paramsByKey;
-
- private ActiveRuleWrapper(ActiveRuleDto activeRule, Collection<ActiveRuleParamDto> params) {
- this.activeRule = activeRule;
- this.paramsByKey = params.stream().collect(uniqueIndex(ActiveRuleParamDto::getKey));
- }
-
- ActiveRuleDto get() {
- return activeRule;
- }
-
- Collection<ActiveRuleParamDto> getParams() {
- return paramsByKey.values();
- }
-
- @CheckForNull
- ActiveRuleParamDto getParam(String key) {
- return paramsByKey.get(key);
- }
-
- @CheckForNull
- String getParamValue(String key) {
- ActiveRuleParamDto param = paramsByKey.get(key);
- return param != null ? param.getValue() : null;
- }
- }
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java
deleted file mode 100644
index 713ae6ce9ab..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import com.google.common.base.Splitter;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Stream;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.server.ServerSide;
-import org.sonar.api.server.rule.RuleParamType;
-import org.sonar.api.utils.System2;
-import org.sonar.core.util.stream.MoreCollectors;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.qualityprofile.ActiveRuleDao;
-import org.sonar.db.qualityprofile.ActiveRuleDto;
-import org.sonar.db.qualityprofile.ActiveRuleKey;
-import org.sonar.db.qualityprofile.ActiveRuleParamDto;
-import org.sonar.db.qualityprofile.OrgQProfileDto;
-import org.sonar.db.qualityprofile.QProfileDto;
-import org.sonar.db.qualityprofile.RulesProfileDto;
-import org.sonar.db.rule.RuleDefinitionDto;
-import org.sonar.db.rule.RuleParamDto;
-import org.sonar.server.qualityprofile.RuleActivationContext.ActiveRuleWrapper;
-import org.sonar.server.qualityprofile.RuleActivationContext.RuleWrapper;
-import org.sonar.server.user.UserSession;
-import org.sonar.server.util.TypeValidations;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static java.util.stream.Collectors.toList;
-import static org.sonar.server.exceptions.BadRequestException.checkRequest;
-
-/**
- * Activation and deactivation of rules in Quality profiles
- */
-@ServerSide
-public class RuleActivator {
-
- private final System2 system2;
- private final DbClient db;
- private final TypeValidations typeValidations;
- private final UserSession userSession;
-
- public RuleActivator(System2 system2, DbClient db, TypeValidations typeValidations, UserSession userSession) {
- this.system2 = system2;
- this.db = db;
- this.typeValidations = typeValidations;
- this.userSession = userSession;
- }
-
-
- public List<ActiveRuleChange> activate(DbSession dbSession, Collection<RuleActivation> activations, RuleActivationContext context) {
- return activations.stream().map(a -> activate(dbSession, a, context))
- .flatMap(List::stream)
- .collect(toList());
- }
-
- public List<ActiveRuleChange> activate(DbSession dbSession, RuleActivation activation, RuleActivationContext context) {
- context.reset(activation.getRuleUuid());
- List<ActiveRuleChange> activeRuleChanges = doActivate(dbSession, activation, context);
- return activeRuleChanges;
- }
-
- private List<ActiveRuleChange> doActivate(DbSession dbSession, RuleActivation activation, RuleActivationContext context) {
- RuleDefinitionDto rule = context.getRule().get();
- checkRequest(RuleStatus.REMOVED != rule.getStatus(), "Rule was removed: %s", rule.getKey());
- checkRequest(!rule.isTemplate(), "Rule template can't be activated on a Quality profile: %s", rule.getKey());
- checkRequest(context.getRulesProfile().getLanguage().equals(rule.getLanguage()),
- "%s rule %s cannot be activated on %s profile %s", rule.getLanguage(), rule.getKey(), context.getRulesProfile().getLanguage(),context.getRulesProfile().getName());
- List<ActiveRuleChange> changes = new ArrayList<>();
- ActiveRuleChange change;
- boolean stopCascading = false;
-
- ActiveRuleWrapper activeRule = context.getActiveRule();
- ActiveRuleKey activeRuleKey = ActiveRuleKey.of(context.getRulesProfile(), rule.getKey());
- if (activeRule == null) {
- if (activation.isReset()) {
- // ignore reset when rule is not activated
- return changes;
- }
- // new activation
- change = new ActiveRuleChange(ActiveRuleChange.Type.ACTIVATED, activeRuleKey, rule);
- applySeverityAndParamToChange(activation, context, change);
- if (context.isCascading() || isSameAsParent(change, context)) {
- change.setInheritance(ActiveRuleInheritance.INHERITED);
- }
- } else {
- // already activated
- if (context.isCascading() && activeRule.get().doesOverride()) {
- // propagating to descendants, but child profile already overrides rule -> stop propagation
- return changes;
- }
- change = new ActiveRuleChange(ActiveRuleChange.Type.UPDATED, activeRuleKey, rule);
- if (context.isCascading() && activeRule.get().getInheritance() == null) {
- // activate on child, then on parent -> mark child as overriding parent
- change.setInheritance(ActiveRuleInheritance.OVERRIDES);
- change.setSeverity(activeRule.get().getSeverityString());
- for (ActiveRuleParamDto activeParam : activeRule.getParams()) {
- change.setParameter(activeParam.getKey(), activeParam.getValue());
- }
- stopCascading = true;
- } else {
- applySeverityAndParamToChange(activation, context, change);
- if (!context.isCascading() && context.getParentActiveRule() != null) {
- // override rule which is already declared on parents
- change.setInheritance(isSameAsParent(change, context) ? ActiveRuleInheritance.INHERITED : ActiveRuleInheritance.OVERRIDES);
- }
- }
- if (isSame(change, activeRule)) {
- change = null;
- stopCascading = true;
- }
- }
-
- if (change != null) {
- changes.add(change);
- persist(change, context, dbSession);
- }
-
- if (!changes.isEmpty()) {
- updateProfileDates(dbSession, context);
- }
-
- if (!stopCascading) {
- changes.addAll(propagateActivationToDescendants(dbSession, activation, context));
- }
-
- return changes;
- }
-
- private void updateProfileDates(DbSession dbSession, RuleActivationContext context) {
- RulesProfileDto ruleProfile = context.getRulesProfile();
- ruleProfile.setRulesUpdatedAtAsDate(new Date(context.getDate()));
- db.qualityProfileDao().update(dbSession, ruleProfile);
-
- if (userSession.isLoggedIn()) {
- context.getProfiles().forEach(p -> db.qualityProfileDao().update(dbSession, OrgQProfileDto.from(p).setUserUpdatedAt(context.getDate())));
- }
- }
-
- /**
- * Update severity and params
- */
- private void applySeverityAndParamToChange(RuleActivation request, RuleActivationContext context, ActiveRuleChange change) {
- RuleWrapper rule = context.getRule();
- ActiveRuleWrapper activeRule = context.getActiveRule();
- ActiveRuleWrapper parentActiveRule = context.getParentActiveRule();
-
- if (request.isReset()) {
- applySeverityAndParamsWhenResetRequested(change, rule, parentActiveRule);
- } else if (context.getRulesProfile().isBuiltIn()) {
- applySeverityAndParamsWhenBuiltInProfile(request, context, change, rule);
- } else {
- applySeverityAndParamsWhenNonBuiltInProfile(request, context, change, rule, activeRule, parentActiveRule);
- }
- }
-
- private void applySeverityAndParamsWhenResetRequested(ActiveRuleChange change, RuleWrapper rule, @Nullable ActiveRuleWrapper parentActiveRule) {
- String severity = firstNonNull(
- parentActiveRule != null ? parentActiveRule.get().getSeverityString() : null,
- rule.get().getSeverityString());
- change.setSeverity(severity);
-
- for (RuleParamDto ruleParamDto : rule.getParams()) {
- String paramKey = ruleParamDto.getName();
- // load params from parent profile, else from default values
- String paramValue = firstNonNull(
- parentActiveRule != null ? parentActiveRule.getParamValue(paramKey) : null,
- rule.getParamDefaultValue(paramKey));
-
- change.setParameter(paramKey, validateParam(ruleParamDto, paramValue));
- }
- }
-
- private void applySeverityAndParamsWhenBuiltInProfile(RuleActivation request, RuleActivationContext context, ActiveRuleChange change,
- RuleWrapper rule) {
- // for builtin quality profiles, the severity from profile, when null use the default severity of the rule
- String severity = firstNonNull(request.getSeverity(), rule.get().getSeverityString());
- change.setSeverity(severity);
-
- for (RuleParamDto ruleParamDto : rule.getParams()) {
- String paramKey = ruleParamDto.getName();
- // use the value defined in the profile definition, else the rule default value
- String paramValue = firstNonNull(
- context.getRequestedParamValue(request, paramKey),
- rule.getParamDefaultValue(paramKey));
- change.setParameter(paramKey, validateParam(ruleParamDto, paramValue));
- }
- }
-
- /**
- * 1. apply requested severity and param
- * 2. if rule activated and overridden - apply user value
- * 3. apply parent value
- * 4. apply defaults
- */
- private void applySeverityAndParamsWhenNonBuiltInProfile(RuleActivation request, RuleActivationContext context, ActiveRuleChange change,
- RuleWrapper rule, @Nullable ActiveRuleWrapper activeRule, @Nullable ActiveRuleWrapper parentActiveRule) {
- String severity = getSeverityForNonBuiltInProfile(request, rule, activeRule, parentActiveRule);
- change.setSeverity(severity);
-
- for (RuleParamDto ruleParamDto : rule.getParams()) {
- String paramKey = ruleParamDto.getName();
- String parentValue = parentActiveRule != null ? parentActiveRule.getParamValue(paramKey) : null;
- String paramValue;
- if (context.hasRequestedParamValue(request, paramKey)) {
- // If the request contains the parameter then we're using either value from request, or parent value, or default value
- paramValue = firstNonNull(
- context.getRequestedParamValue(request, paramKey),
- parentValue,
- rule.getParamDefaultValue(paramKey));
- } else if (activeRule != null) {
- // If the request doesn't contain the parameter, then we're using either user value from db, or parent value if rule inherited, or default
- // value
- paramValue = firstNonNull(
- activeRule.get().doesOverride() ? activeRule.getParamValue(paramKey) : null,
- parentValue == null ? activeRule.getParamValue(paramKey) : parentValue,
- rule.getParamDefaultValue(paramKey));
- } else {
- paramValue = firstNonNull(
- parentValue,
- rule.getParamDefaultValue(paramKey));
- }
- change.setParameter(paramKey, validateParam(ruleParamDto, paramValue));
- }
- }
-
- private static String getSeverityForNonBuiltInProfile(RuleActivation request, RuleWrapper rule, @Nullable ActiveRuleWrapper activeRule,
- @Nullable ActiveRuleWrapper parentActiveRule) {
- String severity;
- if (activeRule != null) {
- ActiveRuleDto activeRuleDto = activeRule.get();
- // load severity from request, else keep existing one (if overridden), else from parent if rule inherited, else from default
- severity = firstNonNull(
- request.getSeverity(),
- activeRuleDto.doesOverride() ? activeRuleDto.getSeverityString() : null,
- parentActiveRule != null ? parentActiveRule.get().getSeverityString() : activeRuleDto.getSeverityString(),
- rule.get().getSeverityString());
- } else {
- // load severity from request, else from parent, else from default
- severity = firstNonNull(
- request.getSeverity(),
- parentActiveRule != null ? parentActiveRule.get().getSeverityString() : null,
- rule.get().getSeverityString());
- }
- return severity;
- }
-
- private List<ActiveRuleChange> propagateActivationToDescendants(DbSession dbSession, RuleActivation activation, RuleActivationContext context) {
- List<ActiveRuleChange> changes = new ArrayList<>();
-
- // get all inherited profiles
- context.getChildProfiles().forEach(child -> {
- context.selectChild(child);
- changes.addAll(doActivate(dbSession, activation, context));
- });
- return changes;
- }
-
- private void persist(ActiveRuleChange change, RuleActivationContext context, DbSession dbSession) {
- ActiveRuleDto activeRule = null;
- if (change.getType() == ActiveRuleChange.Type.ACTIVATED) {
- activeRule = doInsert(change, context, dbSession);
- } else if (change.getType() == ActiveRuleChange.Type.DEACTIVATED) {
- ActiveRuleDao dao = db.activeRuleDao();
- activeRule = dao.delete(dbSession, change.getKey()).orElse(null);
-
- } else if (change.getType() == ActiveRuleChange.Type.UPDATED) {
- activeRule = doUpdate(change, context, dbSession);
- }
- change.setActiveRule(activeRule);
- db.qProfileChangeDao().insert(dbSession, change.toDto(userSession.getUuid()));
- }
-
- private ActiveRuleDto doInsert(ActiveRuleChange change, RuleActivationContext context, DbSession dbSession) {
- ActiveRuleDao dao = db.activeRuleDao();
- RuleWrapper rule = context.getRule();
-
- ActiveRuleDto activeRule = new ActiveRuleDto();
- activeRule.setProfileUuid(context.getRulesProfile().getUuid());
- activeRule.setRuleUuid(rule.get().getUuid());
- activeRule.setKey(ActiveRuleKey.of(context.getRulesProfile(), rule.get().getKey()));
- String severity = change.getSeverity();
- if (severity != null) {
- activeRule.setSeverity(severity);
- }
- ActiveRuleInheritance inheritance = change.getInheritance();
- if (inheritance != null) {
- activeRule.setInheritance(inheritance.name());
- }
- activeRule.setUpdatedAt(system2.now());
- activeRule.setCreatedAt(system2.now());
- dao.insert(dbSession, activeRule);
- for (Map.Entry<String, String> param : change.getParameters().entrySet()) {
- if (param.getValue() != null) {
- ActiveRuleParamDto paramDto = ActiveRuleParamDto.createFor(rule.getParam(param.getKey()));
- paramDto.setValue(param.getValue());
- dao.insertParam(dbSession, activeRule, paramDto);
- }
- }
- return activeRule;
- }
-
- private ActiveRuleDto doUpdate(ActiveRuleChange change, RuleActivationContext context, DbSession dbSession) {
- ActiveRuleWrapper activeRule = context.getActiveRule();
- if (activeRule == null) {
- return null;
- }
- ActiveRuleDao dao = db.activeRuleDao();
- String severity = change.getSeverity();
- if (severity != null) {
- activeRule.get().setSeverity(severity);
- }
- ActiveRuleInheritance inheritance = change.getInheritance();
- if (inheritance != null) {
- activeRule.get().setInheritance(inheritance.name());
- }
- activeRule.get().setUpdatedAt(system2.now());
- dao.update(dbSession, activeRule.get());
-
- for (Map.Entry<String, String> param : change.getParameters().entrySet()) {
- ActiveRuleParamDto activeRuleParamDto = activeRule.getParam(param.getKey());
- if (activeRuleParamDto == null) {
- // did not exist
- if (param.getValue() != null) {
- activeRuleParamDto = ActiveRuleParamDto.createFor(context.getRule().getParam(param.getKey()));
- activeRuleParamDto.setValue(param.getValue());
- dao.insertParam(dbSession, activeRule.get(), activeRuleParamDto);
- }
- } else {
- if (param.getValue() != null) {
- activeRuleParamDto.setValue(param.getValue());
- dao.updateParam(dbSession, activeRuleParamDto);
- } else {
- dao.deleteParam(dbSession, activeRuleParamDto);
- }
- }
- }
- return activeRule.get();
- }
-
- public List<ActiveRuleChange> deactivate(DbSession dbSession, RuleActivationContext context, String ruleUuid, boolean force) {
- context.reset(ruleUuid);
- List<ActiveRuleChange> activeRuleChanges = doDeactivate(dbSession, context, force);
- return activeRuleChanges;
- }
-
- private List<ActiveRuleChange> doDeactivate(DbSession dbSession, RuleActivationContext context, boolean force) {
- List<ActiveRuleChange> changes = new ArrayList<>();
- ActiveRuleWrapper activeRule = context.getActiveRule();
- if (activeRule == null) {
- return changes;
- }
-
- ActiveRuleChange change;
- checkRequest(force || context.isCascading() || activeRule.get().getInheritance() == null, "Cannot deactivate inherited rule '%s'", context.getRule().get().getKey());
- change = new ActiveRuleChange(ActiveRuleChange.Type.DEACTIVATED, activeRule.get(), context.getRule().get());
- changes.add(change);
- persist(change, context, dbSession);
-
- // get all inherited profiles (they are not built-in by design)
- context.getChildProfiles().forEach(child -> {
- context.selectChild(child);
- changes.addAll(doDeactivate(dbSession, context, force));
- });
-
- if (!changes.isEmpty()) {
- updateProfileDates(dbSession, context);
- }
-
- return changes;
- }
-
- @CheckForNull
- private String validateParam(RuleParamDto ruleParam, @Nullable String value) {
- if (value != null) {
- RuleParamType ruleParamType = RuleParamType.parse(ruleParam.getType());
- if (ruleParamType.multiple()) {
- List<String> values = Splitter.on(",").splitToList(value);
- typeValidations.validate(values, ruleParamType.type(), ruleParamType.values());
- } else {
- typeValidations.validate(value, ruleParamType.type(), ruleParamType.values());
- }
- }
- return value;
- }
-
- public RuleActivationContext createContextForBuiltInProfile(DbSession dbSession, RulesProfileDto builtInProfile, Collection<String> ruleUuids) {
- checkArgument(builtInProfile.isBuiltIn(), "Rules profile with UUID %s is not built-in", builtInProfile.getUuid());
-
- RuleActivationContext.Builder builder = new RuleActivationContext.Builder();
- builder.setDescendantProfilesSupplier(createDescendantProfilesSupplier(dbSession));
-
- // load rules
- completeWithRules(dbSession, builder, ruleUuids);
-
- // load org profiles. Their parents are null by nature.
- List<QProfileDto> profiles = db.qualityProfileDao().selectQProfilesByRuleProfile(dbSession, builtInProfile);
- builder.setProfiles(profiles);
- builder.setBaseProfile(builtInProfile);
-
- // load active rules
- Collection<String> ruleProfileUuids = Stream
- .concat(Stream.of(builtInProfile.getUuid()), profiles.stream().map(QProfileDto::getRulesProfileUuid))
- .collect(MoreCollectors.toHashSet(profiles.size() + 1));
- completeWithActiveRules(dbSession, builder, ruleUuids, ruleProfileUuids);
- return builder.build();
- }
-
- public RuleActivationContext createContextForUserProfile(DbSession dbSession, QProfileDto profile, Collection<String> ruleUuids) {
- checkArgument(!profile.isBuiltIn(), "Profile with UUID %s is built-in", profile.getKee());
- RuleActivationContext.Builder builder = new RuleActivationContext.Builder();
- builder.setDescendantProfilesSupplier(createDescendantProfilesSupplier(dbSession));
-
- // load rules
- completeWithRules(dbSession, builder, ruleUuids);
-
- // load profiles
- List<QProfileDto> profiles = new ArrayList<>();
- profiles.add(profile);
- if (profile.getParentKee() != null) {
- profiles.add(db.qualityProfileDao().selectByUuid(dbSession, profile.getParentKee()));
- }
- builder.setProfiles(profiles);
- builder.setBaseProfile(RulesProfileDto.from(profile));
-
- // load active rules
- Collection<String> ruleProfileUuids = profiles.stream()
- .map(QProfileDto::getRulesProfileUuid)
- .collect(MoreCollectors.toHashSet(profiles.size()));
- completeWithActiveRules(dbSession, builder, ruleUuids, ruleProfileUuids);
-
- return builder.build();
- }
-
- DescendantProfilesSupplier createDescendantProfilesSupplier(DbSession dbSession) {
- return (parents, ruleUuids) -> {
- Collection<QProfileDto> profiles = db.qualityProfileDao().selectDescendants(dbSession, parents);
- Set<String> ruleProfileUuids = profiles.stream()
- .map(QProfileDto::getRulesProfileUuid)
- .collect(MoreCollectors.toHashSet());
- Collection<ActiveRuleDto> activeRules = db.activeRuleDao().selectByRulesAndRuleProfileUuids(dbSession, ruleUuids, ruleProfileUuids);
- List<String> activeRuleUuids = activeRules.stream().map(ActiveRuleDto::getUuid).collect(MoreCollectors.toArrayList(activeRules.size()));
- List<ActiveRuleParamDto> activeRuleParams = db.activeRuleDao().selectParamsByActiveRuleUuids(dbSession, activeRuleUuids);
- return new DescendantProfilesSupplier.Result(profiles, activeRules, activeRuleParams);
- };
- }
-
- private void completeWithRules(DbSession dbSession, RuleActivationContext.Builder builder, Collection<String> ruleUuids) {
- List<RuleDefinitionDto> rules = db.ruleDao().selectDefinitionByUuids(dbSession, ruleUuids);
- builder.setRules(rules);
- builder.setRuleParams(db.ruleDao().selectRuleParamsByRuleUuids(dbSession, ruleUuids));
- }
-
- private void completeWithActiveRules(DbSession dbSession, RuleActivationContext.Builder builder, Collection<String> ruleUuids, Collection<String> ruleProfileUuids) {
- Collection<ActiveRuleDto> activeRules = db.activeRuleDao().selectByRulesAndRuleProfileUuids(dbSession, ruleUuids, ruleProfileUuids);
- builder.setActiveRules(activeRules);
- List<String> activeRuleUuids = activeRules.stream().map(ActiveRuleDto::getUuid).collect(MoreCollectors.toArrayList(activeRules.size()));
- builder.setActiveRuleParams(db.activeRuleDao().selectParamsByActiveRuleUuids(dbSession, activeRuleUuids));
- }
-
- private static boolean isSame(ActiveRuleChange change, ActiveRuleWrapper activeRule) {
- ActiveRuleInheritance inheritance = change.getInheritance();
- if (inheritance != null && !inheritance.name().equals(activeRule.get().getInheritance())) {
- return false;
- }
- String severity = change.getSeverity();
- if (severity != null && !severity.equals(activeRule.get().getSeverityString())) {
- return false;
- }
- for (Map.Entry<String, String> changeParam : change.getParameters().entrySet()) {
- String activeParamValue = activeRule.getParamValue(changeParam.getKey());
- if (changeParam.getValue() == null && activeParamValue != null) {
- return false;
- }
- if (changeParam.getValue() != null && (activeParamValue == null || !StringUtils.equals(changeParam.getValue(), activeParamValue))) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * True if trying to override an inherited rule but with exactly the same values
- */
- private static boolean isSameAsParent(ActiveRuleChange change, RuleActivationContext context) {
- ActiveRuleWrapper parentActiveRule = context.getParentActiveRule();
- if (parentActiveRule == null) {
- return false;
- }
- if (!StringUtils.equals(change.getSeverity(), parentActiveRule.get().getSeverityString())) {
- return false;
- }
- for (Map.Entry<String, String> entry : change.getParameters().entrySet()) {
- if (entry.getValue() != null && !entry.getValue().equals(parentActiveRule.getParamValue(entry.getKey()))) {
- return false;
- }
- }
- return true;
- }
-
- @CheckForNull
- private static String firstNonNull(String... strings) {
- for (String s : strings) {
- if (s != null) {
- return s;
- }
- }
- return null;
- }
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/RuleActivatorEventsDistributor.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/RuleActivatorEventsDistributor.java
deleted file mode 100644
index d41f1a5abd1..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/RuleActivatorEventsDistributor.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import org.sonar.core.util.RuleActivationListener;
-import org.sonar.core.util.RuleSetChangeEvent;
-
-public interface RuleActivatorEventsDistributor {
-
- void subscribe(RuleActivationListener listener);
-
- void pushEvent(RuleSetChangeEvent event);
-} \ No newline at end of file
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/StandaloneRuleActivatorEventsDistributor.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/StandaloneRuleActivatorEventsDistributor.java
deleted file mode 100644
index 43fc97da319..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/StandaloneRuleActivatorEventsDistributor.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.sonar.api.server.ServerSide;
-import org.sonar.core.util.RuleActivationListener;
-import org.sonar.core.util.RuleSetChangeEvent;
-
-@ServerSide
-public class StandaloneRuleActivatorEventsDistributor implements RuleActivatorEventsDistributor {
-
- private List<RuleActivationListener> listeners = new ArrayList<>();
-
- @Override
- public void subscribe(RuleActivationListener listener) {
- listeners.add(listener);
- }
-
- @Override
- public void pushEvent(RuleSetChangeEvent event) {
- listeners.forEach(l -> l.listen(event));
- }
-}
diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/package-info.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/package-info.java
deleted file mode 100644
index 0b1a410c6a3..00000000000
--- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/qualityprofile/package-info.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.server.qualityprofile;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationHandlerTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationHandlerTest.java
deleted file mode 100644
index c178ab5ffcc..00000000000
--- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationHandlerTest.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import java.util.Random;
-import java.util.Set;
-import java.util.stream.IntStream;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.EmailSubscriberDto;
-import org.sonar.db.permission.AuthorizationDao;
-import org.sonar.server.notification.email.EmailNotificationChannel;
-
-import static java.util.Collections.emptySet;
-import static java.util.stream.Collectors.toSet;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-public class BuiltInQPChangeNotificationHandlerTest {
- private DbClient dbClient = mock(DbClient.class);
- private DbSession dbSession = mock(DbSession.class);
- private AuthorizationDao authorizationDao = mock(AuthorizationDao.class);
- private EmailNotificationChannel emailNotificationChannel = mock(EmailNotificationChannel.class);
-
- private BuiltInQPChangeNotificationHandler underTest = new BuiltInQPChangeNotificationHandler(dbClient, emailNotificationChannel);
-
- @Before
- public void wire_mocks() {
- when(dbClient.openSession(false)).thenReturn(dbSession);
- when(dbClient.authorizationDao()).thenReturn(authorizationDao);
- }
-
- @Test
- public void getMetadata_returns_empty() {
- assertThat(underTest.getMetadata()).isEmpty();
- }
-
- @Test
- public void getNotificationClass_is_BuiltInQPChangeNotification() {
- assertThat(underTest.getNotificationClass()).isEqualTo(BuiltInQPChangeNotification.class);
- }
-
- @Test
- public void deliver_has_no_effect_if_emailNotificationChannel_is_disabled() {
- when(emailNotificationChannel.isActivated()).thenReturn(false);
- Set<BuiltInQPChangeNotification> notifications = IntStream.range(0, 1 + new Random().nextInt(10))
- .mapToObj(i -> mock(BuiltInQPChangeNotification.class))
- .collect(toSet());
-
- int deliver = underTest.deliver(notifications);
-
- assertThat(deliver).isZero();
- verify(emailNotificationChannel).isActivated();
- verifyNoMoreInteractions(emailNotificationChannel);
- verifyZeroInteractions(dbClient);
- notifications.forEach(Mockito::verifyZeroInteractions);
- }
-
- @Test
- public void deliver_has_no_effect_if_there_is_no_global_administer_email_subscriber() {
- when(emailNotificationChannel.isActivated()).thenReturn(true);
- Set<BuiltInQPChangeNotification> notifications = IntStream.range(0, 1 + new Random().nextInt(10))
- .mapToObj(i -> mock(BuiltInQPChangeNotification.class))
- .collect(toSet());
- when(authorizationDao.selectQualityProfileAdministratorLogins(dbSession))
- .thenReturn(emptySet());
-
- int deliver = underTest.deliver(notifications);
-
- assertThat(deliver).isZero();
- verify(emailNotificationChannel).isActivated();
- verifyNoMoreInteractions(emailNotificationChannel);
- verify(dbClient).openSession(false);
- verify(dbClient).authorizationDao();
- verifyNoMoreInteractions(dbClient);
- verify(authorizationDao).selectQualityProfileAdministratorLogins(dbSession);
- verifyNoMoreInteractions(authorizationDao);
- notifications.forEach(Mockito::verifyZeroInteractions);
- }
-
- @Test
- public void deliver_create_emailRequest_for_each_notification_and_for_each_global_administer_email_subscriber() {
- when(emailNotificationChannel.isActivated()).thenReturn(true);
- Set<BuiltInQPChangeNotification> notifications = IntStream.range(0, 1 + new Random().nextInt(10))
- .mapToObj(i -> mock(BuiltInQPChangeNotification.class))
- .collect(toSet());
- Set<EmailSubscriberDto> emailSubscribers = IntStream.range(0, 1 + new Random().nextInt(10))
- .mapToObj(i -> EmailSubscriberDto.create("login_" + i, true, "login_" + i + "@foo"))
- .collect(toSet());
- when(authorizationDao.selectQualityProfileAdministratorLogins(dbSession))
- .thenReturn(emailSubscribers);
- Set<EmailNotificationChannel.EmailDeliveryRequest> expectedRequests = notifications.stream()
- .flatMap(notification -> emailSubscribers.stream().map(subscriber -> new EmailNotificationChannel.EmailDeliveryRequest(subscriber.getEmail(), notification)))
- .collect(toSet());
- int deliveries = new Random().nextInt(expectedRequests.size());
- when(emailNotificationChannel.deliverAll(expectedRequests)).thenReturn(deliveries);
-
- int deliver = underTest.deliver(notifications);
-
- assertThat(deliver).isEqualTo(deliveries);
- verify(emailNotificationChannel).isActivated();
- verify(emailNotificationChannel).deliverAll(expectedRequests);
- verifyNoMoreInteractions(emailNotificationChannel);
- verify(dbClient).openSession(false);
- verify(dbClient).authorizationDao();
- verifyNoMoreInteractions(dbClient);
- verify(authorizationDao).selectQualityProfileAdministratorLogins(dbSession);
- verifyNoMoreInteractions(authorizationDao);
- notifications.forEach(Mockito::verifyZeroInteractions);
- }
-
-}
diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationTemplateTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationTemplateTest.java
deleted file mode 100644
index 6cf1581ff45..00000000000
--- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationTemplateTest.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import java.util.Date;
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.platform.Server;
-import org.sonar.server.issue.notification.EmailMessage;
-import org.sonar.server.qualityprofile.BuiltInQPChangeNotificationBuilder.Profile;
-
-import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.sonar.api.utils.DateUtils.formatDate;
-
-public class BuiltInQPChangeNotificationTemplateTest {
-
- private Server server = mock(Server.class);
-
- private BuiltInQPChangeNotificationTemplate underTest = new BuiltInQPChangeNotificationTemplate(server);
-
- @Before
- public void setUp() {
- when(server.getPublicRootUrl()).thenReturn("http://" + randomAlphanumeric(10));
- }
-
- @Test
- public void notification_contains_a_subject() {
- String profileName = newProfileName();
- String languageKey = newLanguageKey();
- String languageName = newLanguageName();
- BuiltInQPChangeNotificationBuilder notification = new BuiltInQPChangeNotificationBuilder()
- .addProfile(Profile.newBuilder()
- .setProfileName(profileName)
- .setLanguageKey(languageKey)
- .setLanguageName(languageName)
- .setNewRules(2)
- .build());
-
- EmailMessage emailMessage = underTest.format(notification.build());
-
- assertThat(emailMessage.getSubject()).isEqualTo("Built-in quality profiles have been updated");
- }
-
- @Test
- public void notification_contains_count_of_new_rules() {
- String profileName = newProfileName();
- String languageKey = newLanguageKey();
- String languageName = newLanguageName();
- BuiltInQPChangeNotificationBuilder notification = new BuiltInQPChangeNotificationBuilder()
- .addProfile(Profile.newBuilder()
- .setProfileName(profileName)
- .setLanguageKey(languageKey)
- .setLanguageName(languageName)
- .setNewRules(2)
- .build());
-
- EmailMessage emailMessage = underTest.format(notification.build());
-
- assertMessage(emailMessage, "\n 2 new rules\n");
- }
-
- @Test
- public void notification_contains_count_of_updated_rules() {
- String profileName = newProfileName();
- String languageKey = newLanguageKey();
- String languageName = newLanguageName();
- BuiltInQPChangeNotificationBuilder notification = new BuiltInQPChangeNotificationBuilder()
- .addProfile(Profile.newBuilder()
- .setProfileName(profileName)
- .setLanguageKey(languageKey)
- .setLanguageName(languageName)
- .setUpdatedRules(2)
- .build());
-
- EmailMessage emailMessage = underTest.format(notification.build());
-
- assertMessage(emailMessage, "\n 2 rules have been updated\n");
- }
-
- @Test
- public void notification_contains_count_of_removed_rules() {
- String profileName = newProfileName();
- String languageKey = newLanguageKey();
- String languageName = newLanguageName();
- BuiltInQPChangeNotificationBuilder notification = new BuiltInQPChangeNotificationBuilder()
- .addProfile(Profile.newBuilder()
- .setProfileName(profileName)
- .setLanguageKey(languageKey)
- .setLanguageName(languageName)
- .setRemovedRules(2)
- .build());
-
- EmailMessage emailMessage = underTest.format(notification.build());
-
- assertMessage(emailMessage, "\n 2 rules removed\n");
- }
-
- @Test
- public void notification_supports_grammar_for_single_rule_added_removed_or_updated() {
- String profileName = newProfileName();
- String languageKey = newLanguageKey();
- String languageName = newLanguageName();
- BuiltInQPChangeNotificationBuilder notification = new BuiltInQPChangeNotificationBuilder()
- .addProfile(Profile.newBuilder()
- .setProfileName(profileName)
- .setLanguageKey(languageKey)
- .setLanguageName(languageName)
- .setNewRules(1)
- .setUpdatedRules(1)
- .setRemovedRules(1)
- .build());
-
- EmailMessage emailMessage = underTest.format(notification.build());
-
- assertThat(emailMessage.getMessage())
- .contains("\n 1 new rule\n")
- .contains("\n 1 rule has been updated\n")
- .contains("\n 1 rule removed\n");
- }
-
- @Test
- public void notification_contains_list_of_new_updated_and_removed_rules() {
- String profileName = newProfileName();
- String languageKey = newLanguageKey();
- String languageName = newLanguageName();
- BuiltInQPChangeNotificationBuilder notification = new BuiltInQPChangeNotificationBuilder()
- .addProfile(Profile.newBuilder()
- .setProfileName(profileName)
- .setLanguageKey(languageKey)
- .setLanguageName(languageName)
- .setNewRules(2)
- .setUpdatedRules(3)
- .setRemovedRules(4)
- .build());
-
- EmailMessage emailMessage = underTest.format(notification.build());
-
- assertMessage(emailMessage,
- "\n" +
- " 2 new rules\n" +
- " 3 rules have been updated\n" +
- " 4 rules removed\n");
- }
-
- @Test
- public void notification_contains_many_profiles() {
- String profileName1 = "profile1_" + randomAlphanumeric(20);
- String languageKey1 = "langkey1_" + randomAlphanumeric(20);
- String languageName1 = "langName1_" + randomAlphanumeric(20);
- String profileName2 = "profile2_" + randomAlphanumeric(20);
- String languageKey2 = "langkey2_" + randomAlphanumeric(20);
- String languageName2 = "langName2_" + randomAlphanumeric(20);
- BuiltInQPChangeNotificationBuilder notification = new BuiltInQPChangeNotificationBuilder()
- .addProfile(Profile.newBuilder()
- .setProfileName(profileName1)
- .setLanguageKey(languageKey1)
- .setLanguageName(languageName1)
- .setNewRules(2)
- .build())
- .addProfile(Profile.newBuilder()
- .setProfileName(profileName2)
- .setLanguageKey(languageKey2)
- .setLanguageName(languageName2)
- .setNewRules(13)
- .build());
-
- EmailMessage emailMessage = underTest.format(notification.build());
-
- assertThat(emailMessage.getMessage()).containsSubsequence("The following built-in profiles have been updated:\n",
- profileTitleText(profileName1, languageKey1, languageName1),
- " 2 new rules\n",
- profileTitleText(profileName2, languageKey2, languageName2),
- " 13 new rules\n",
- "This is a good time to review your quality profiles and update them to benefit from the latest evolutions: " + server.getPublicRootUrl() + "/profiles");
- }
-
- @Test
- public void notification_contains_profiles_sorted_by_language_then_by_profile_name() {
- String languageKey1 = "langkey1_" + randomAlphanumeric(20);
- String languageName1 = "langName1_" + randomAlphanumeric(20);
- String languageKey2 = "langKey2_" + randomAlphanumeric(20);
- String languageName2 = "langName2_" + randomAlphanumeric(20);
- String profileName1 = "profile1_" + randomAlphanumeric(20);
- String profileName2 = "profile2_" + randomAlphanumeric(20);
- String profileName3 = "profile3_" + randomAlphanumeric(20);
- BuiltInQPChangeNotificationBuilder notification = new BuiltInQPChangeNotificationBuilder()
- .addProfile(Profile.newBuilder().setProfileName(profileName3).setLanguageKey(languageKey2).setLanguageName(languageName2).build())
- .addProfile(Profile.newBuilder().setProfileName(profileName2).setLanguageKey(languageKey1).setLanguageName(languageName1).build())
- .addProfile(Profile.newBuilder().setProfileName(profileName1).setLanguageKey(languageKey2).setLanguageName(languageName2).build());
-
- EmailMessage emailMessage = underTest.format(notification.build());
-
- assertThat(emailMessage.getMessage()).containsSubsequence(
- "\"" + profileName2 + "\" - " + languageName1,
- "\"" + profileName1 + "\" - " + languageName2,
- "\"" + profileName3 + "\" - " + languageName2);
- }
-
- @Test
- public void notification_contains_encoded_profile_name() {
- BuiltInQPChangeNotificationBuilder notification = new BuiltInQPChangeNotificationBuilder()
- .addProfile(Profile.newBuilder()
- .setProfileName("Sonar Way")
- .setLanguageKey("java")
- .setLanguageName(newLanguageName())
- .build());
-
- EmailMessage emailMessage = underTest.format(notification.build());
-
- assertThat(emailMessage.getMessage()).contains(server.getPublicRootUrl() + "/profiles/changelog?language=java&name=Sonar+Way");
- }
-
- @Test
- public void notification_contains_from_and_to_date() {
- String profileName = newProfileName();
- String languageKey = newLanguageKey();
- String languageName = newLanguageName();
- long startDate = 1_000_000_000_000L;
- long endDate = startDate + 1_100_000_000_000L;
- BuiltInQPChangeNotificationBuilder notification = new BuiltInQPChangeNotificationBuilder()
- .addProfile(Profile.newBuilder()
- .setProfileName(profileName)
- .setLanguageKey(languageKey)
- .setLanguageName(languageName)
- .setStartDate(startDate)
- .setEndDate(endDate)
- .build());
-
- EmailMessage emailMessage = underTest.format(notification.build());
-
- assertMessage(emailMessage,
- profileTitleText(profileName, languageKey, languageName, formatDate(new Date(startDate)), formatDate(new Date(endDate))));
- }
-
- private void assertMessage(EmailMessage emailMessage, String expectedProfileDetails) {
- assertThat(emailMessage.getMessage())
- .containsSubsequence(
- "The following built-in profiles have been updated:\n\n",
- expectedProfileDetails,
- "\nThis is a good time to review your quality profiles and update them to benefit from the latest evolutions: " + server.getPublicRootUrl() + "/profiles");
- }
-
- private String profileTitleText(String profileName, String languageKey, String languageName) {
- return "\"" + profileName + "\" - " + languageName + ": " + server.getPublicRootUrl() + "/profiles/changelog?language=" + languageKey + "&name=" + profileName;
- }
-
- private String profileTitleText(String profileName, String languageKey, String languageName, String startDate, String endDate) {
- return "\"" + profileName + "\" - " + languageName + ": " + server.getPublicRootUrl() + "/profiles/changelog?language=" + languageKey + "&name=" + profileName +
- "&since=" + startDate + "&to=" + endDate + "\n";
- }
-
- private static String newProfileName() {
- return "profileName_" + randomAlphanumeric(20);
- }
-
- private static String newLanguageName() {
- return "languageName_" + randomAlphanumeric(20);
- }
-
- private static String newLanguageKey() {
- return "languageKey_" + randomAlphanumeric(20);
- }
-}
diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationTest.java
deleted file mode 100644
index 6341e3acb28..00000000000
--- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQPChangeNotificationTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import java.util.Random;
-import org.junit.Test;
-import org.sonar.api.notifications.Notification;
-import org.sonar.server.qualityprofile.BuiltInQPChangeNotificationBuilder.Profile;
-
-import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.assertj.core.api.Assertions.tuple;
-
-public class BuiltInQPChangeNotificationTest {
-
- private static final Random RANDOM = new Random();
-
-
- @Test
- public void serialize_and_parse_no_profile() {
- Notification notification = new BuiltInQPChangeNotificationBuilder().build();
-
- BuiltInQPChangeNotificationBuilder result = BuiltInQPChangeNotificationBuilder.parse(notification);
-
- assertThat(result.getProfiles()).isEmpty();
- }
-
- @Test
- public void serialize_and_parse_single_profile() {
- String profileName = randomAlphanumeric(20);
- String languageKey = randomAlphanumeric(20);
- String languageName = randomAlphanumeric(20);
- int newRules = RANDOM.nextInt(5000);
- int updatedRules = RANDOM.nextInt(5000);
- int removedRules = RANDOM.nextInt(5000);
- long startDate = RANDOM.nextInt(5000);
- long endDate = startDate + RANDOM.nextInt(5000);
-
- BuiltInQPChangeNotification notification = new BuiltInQPChangeNotificationBuilder()
- .addProfile(Profile.newBuilder()
- .setProfileName(profileName)
- .setLanguageKey(languageKey)
- .setLanguageName(languageName)
- .setNewRules(newRules)
- .setUpdatedRules(updatedRules)
- .setRemovedRules(removedRules)
- .setStartDate(startDate)
- .setEndDate(endDate)
- .build())
- .build();
- BuiltInQPChangeNotificationBuilder result = BuiltInQPChangeNotificationBuilder.parse(notification);
-
- assertThat(result.getProfiles())
- .extracting(Profile::getProfileName, Profile::getLanguageKey, Profile::getLanguageName, Profile::getNewRules, Profile::getUpdatedRules, Profile::getRemovedRules,
- Profile::getStartDate, Profile::getEndDate)
- .containsExactlyInAnyOrder(tuple(profileName, languageKey, languageName, newRules, updatedRules, removedRules, startDate, endDate));
- }
-
- @Test
- public void serialize_and_parse_multiple_profiles() {
- String profileName1 = randomAlphanumeric(20);
- String languageKey1 = randomAlphanumeric(20);
- String languageName1 = randomAlphanumeric(20);
- String profileName2 = randomAlphanumeric(20);
- String languageKey2 = randomAlphanumeric(20);
- String languageName2 = randomAlphanumeric(20);
-
- BuiltInQPChangeNotification notification = new BuiltInQPChangeNotificationBuilder()
- .addProfile(Profile.newBuilder()
- .setProfileName(profileName1)
- .setLanguageKey(languageKey1)
- .setLanguageName(languageName1)
- .build())
- .addProfile(Profile.newBuilder()
- .setProfileName(profileName2)
- .setLanguageKey(languageKey2)
- .setLanguageName(languageName2)
- .build())
- .build();
- BuiltInQPChangeNotificationBuilder result = BuiltInQPChangeNotificationBuilder.parse(notification);
-
- assertThat(result.getProfiles()).extracting(Profile::getProfileName, Profile::getLanguageKey, Profile::getLanguageName)
- .containsExactlyInAnyOrder(tuple(profileName1, languageKey1, languageName1), tuple(profileName2, languageKey2, languageName2));
- }
-
- @Test
- public void serialize_and_parse_max_values() {
- String profileName = randomAlphanumeric(20);
- String languageKey = randomAlphanumeric(20);
- String languageName = randomAlphanumeric(20);
- int newRules = Integer.MAX_VALUE;
- int updatedRules = Integer.MAX_VALUE;
- int removedRules = Integer.MAX_VALUE;
- long startDate = Long.MAX_VALUE;
- long endDate = Long.MAX_VALUE;
-
- BuiltInQPChangeNotification notification = new BuiltInQPChangeNotificationBuilder()
- .addProfile(Profile.newBuilder()
- .setProfileName(profileName)
- .setLanguageKey(languageKey)
- .setLanguageName(languageName)
- .setNewRules(newRules)
- .setUpdatedRules(updatedRules)
- .setRemovedRules(removedRules)
- .setStartDate(startDate)
- .setEndDate(endDate)
- .build())
- .build();
- BuiltInQPChangeNotificationBuilder result = BuiltInQPChangeNotificationBuilder.parse(notification);
-
- assertThat(result.getProfiles())
- .extracting(Profile::getProfileName, Profile::getLanguageKey, Profile::getLanguageName, Profile::getNewRules, Profile::getUpdatedRules, Profile::getRemovedRules,
- Profile::getStartDate, Profile::getEndDate)
- .containsExactlyInAnyOrder(tuple(profileName, languageKey, languageName, newRules, updatedRules, removedRules, startDate, endDate));
- }
-
- @Test
- public void fail_with_ISE_when_parsing_empty_notification() {
- assertThatThrownBy(() -> BuiltInQPChangeNotificationBuilder.parse(new Notification(BuiltInQPChangeNotification.TYPE)))
- .isInstanceOf(IllegalStateException.class)
- .hasMessage("Could not read the built-in quality profile notification");
- }
-}
diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImplTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImplTest.java
deleted file mode 100644
index cfa001ff1b8..00000000000
--- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImplTest.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import java.util.Arrays;
-import java.util.List;
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.Test;
-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.api.server.profile.BuiltInQualityProfilesDefinition.NewBuiltInQualityProfile;
-import org.sonar.api.utils.System2;
-import org.sonar.core.util.SequenceUuidFactory;
-import org.sonar.core.util.UuidFactory;
-import org.sonar.db.DbSession;
-import org.sonar.db.DbTester;
-import org.sonar.db.qualityprofile.ActiveRuleDto;
-import org.sonar.db.qualityprofile.ActiveRuleKey;
-import org.sonar.db.qualityprofile.ActiveRuleParamDto;
-import org.sonar.db.qualityprofile.QProfileChangeDto;
-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.singletonList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class BuiltInQProfileInsertImplTest {
-
- @Rule
- public BuiltInQProfileRepositoryRule builtInQProfileRepository = new BuiltInQProfileRepositoryRule();
- @Rule
- public DbTester db = DbTester.create();
-
- 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() {
- batchDbSession.close();
- }
-
- @Test
- public void insert_active_rules_and_changelog() {
- RuleDefinitionDto rule1 = db.rules().insert(r -> r.setLanguage("xoo"));
- RuleDefinitionDto rule2 = db.rules().insert(r -> r.setLanguage("xoo"));
-
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("the name", "xoo");
-
- newQp.activateRule(rule1.getRepositoryKey(), rule1.getRuleKey()).overrideSeverity(Severity.CRITICAL);
- newQp.activateRule(rule2.getRepositoryKey(), rule2.getRuleKey()).overrideSeverity(Severity.MAJOR);
- newQp.done();
-
- BuiltInQProfile builtIn = builtInQProfileRepository.create(context.profile("xoo", "the name"), rule1, rule2);
- 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();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("the name", "xoo").setDefault(true);
- newQp.done();
-
- BuiltInQProfile builtIn = builtInQProfileRepository.create(context.profile("xoo", "the name"));
-
- call(builtIn);
-
- QProfileDto profile = verifyProfileInDb(builtIn);
- QProfileDto defaultProfile = db.getDbClient().qualityProfileDao().selectDefaultProfile(dbSession, "xoo");
- assertThat(defaultProfile.getKee()).isEqualTo(profile.getKee());
- }
-
- @Test
- public void existing_default_profile_must_not_be_changed() {
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("the name", "xoo").setDefault(true);
- newQp.done();
- BuiltInQProfile builtIn = builtInQProfileRepository.create(context.profile("xoo", "the name"));
-
- QProfileDto currentDefault = db.qualityProfiles().insert(p -> p.setLanguage("xoo"));
- db.qualityProfiles().setAsDefault(currentDefault);
-
- call(builtIn);
-
- QProfileDto defaultProfile = db.getDbClient().qualityProfileDao().selectDefaultProfile(dbSession, "xoo");
- assertThat(defaultProfile.getKee()).isEqualTo(currentDefault.getKee());
- verifyTableSize("rules_profiles", 2);
- }
-
- @Test
- public void dont_flag_profile_as_default_if_not_declared_as_default_by_api() {
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("the name", "xoo").setDefault(false);
- newQp.done();
- BuiltInQProfile builtIn = builtInQProfileRepository.create(context.profile("xoo", "the name"));
-
- call(builtIn);
-
- QProfileDto defaultProfile = db.getDbClient().qualityProfileDao().selectDefaultProfile(dbSession, "xoo");
- assertThat(defaultProfile).isNull();
- }
-
- // TODO test lot of active_rules, params, orgas
-
- 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.doesOverride()).isFalse();
- assertThat(activeRule.getRuleUuid()).isEqualTo(rule.getUuid());
- assertThat(activeRule.getProfileUuid()).isEqualTo(profile.getRulesProfileUuid());
- assertThat(activeRule.getSeverityString()).isEqualTo(expectedSeverity);
- assertThat(activeRule.getCreatedAt()).isPositive();
- assertThat(activeRule.getUpdatedAt()).isPositive();
-
- List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleUuid(dbSession, activeRule.getUuid());
- 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()
- .filter(c -> c.getDataAsMap().get("ruleUuid").equals(rule.getUuid()))
- .findFirst()
- .get();
- assertThat(change.getChangeType()).isEqualTo(ActiveRuleChange.Type.ACTIVATED.name());
- assertThat(change.getCreatedAt()).isPositive();
- assertThat(change.getUuid()).isNotEmpty();
- assertThat(change.getUserUuid()).isNull();
- assertThat(change.getRulesProfileUuid()).isEqualTo(profile.getRulesProfileUuid());
- assertThat(change.getDataAsMap()).containsEntry("severity", expectedSeverity);
- }
-
- private QProfileDto verifyProfileInDb(BuiltInQProfile builtIn) {
- QProfileDto profileOnOrg1 = db.getDbClient().qualityProfileDao().selectByNameAndLanguage(dbSession, builtIn.getName(), builtIn.getLanguage());
- assertThat(profileOnOrg1.getLanguage()).isEqualTo(builtIn.getLanguage());
- assertThat(profileOnOrg1.getName()).isEqualTo(builtIn.getName());
- assertThat(profileOnOrg1.getParentKee()).isNull();
- assertThat(profileOnOrg1.getLastUsed()).isNull();
- assertThat(profileOnOrg1.getUserUpdatedAt()).isNull();
- assertThat(profileOnOrg1.getRulesUpdatedAt()).isNotEmpty();
- assertThat(profileOnOrg1.getKee()).isNotEqualTo(profileOnOrg1.getRulesProfileUuid());
- assertThat(profileOnOrg1.getRulesProfileUuid()).isNotNull();
- return profileOnOrg1;
- }
-
- private void verifyTableSize(String table, int expectedSize) {
- assertThat(db.countRowsOfTable(dbSession, table)).as("table " + table).isEqualTo(expectedSize);
- }
-
- private void call(BuiltInQProfile builtIn) {
- underTest.create(dbSession, builtIn);
- dbSession.commit();
- batchDbSession.commit();
- }
-
-}
diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileLoaderTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileLoaderTest.java
deleted file mode 100644
index 6e2ab84fd31..00000000000
--- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileLoaderTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import org.junit.Rule;
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class BuiltInQProfileLoaderTest {
- @Rule
- public BuiltInQProfileRepositoryRule builtInQProfileRepositoryRule = new BuiltInQProfileRepositoryRule();
-
- private BuiltInQProfileLoader underTest = new BuiltInQProfileLoader(builtInQProfileRepositoryRule);
-
- @Test
- public void start_initializes_DefinedQProfileRepository() {
- underTest.start();
-
- assertThat(builtInQProfileRepositoryRule.isInitialized()).isTrue();
- }
-}
diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImplTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImplTest.java
deleted file mode 100644
index 4672e429f8f..00000000000
--- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImplTest.java
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import java.util.List;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
-import org.sonar.db.DbClient;
-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;
-import static java.util.Collections.singletonList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.assertj.core.groups.Tuple.tuple;
-import static org.mockito.Mockito.mock;
-import static org.sonar.db.rule.RuleTesting.EXTERNAL_XOO;
-import static org.sonar.server.qualityprofile.BuiltInQProfile.ActiveRule;
-
-public class BuiltInQProfileRepositoryImplTest {
- private static final Language FOO_LANGUAGE = LanguageTesting.newLanguage("foo", "foo", "foo");
- private static final String SONAR_WAY_QP_NAME = "Sonar way";
-
- @Rule
- public DbTester db = DbTester.create();
-
- 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();
- 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();
-
- assertThat(underTest.get())
- .extracting(BuiltInQProfile::getName)
- .containsExactlyInAnyOrder("foo");
- assertThat(underTest.get().get(0).getActiveRules())
- .extracting(ActiveRule::getRuleUuid, ActiveRule::getRuleKey)
- .containsExactlyInAnyOrder(
- tuple(rule1.getUuid(), rule1.getKey()),
- tuple(rule2.getUuid(), rule2.getKey()));
- }
-
- @Test
- public void make_single_profile_of_a_language_default_even_if_not_flagged_as_so() {
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE),
- new DummyProfileDefinition("foo", "foo1", false));
-
- underTest.initialize();
-
- assertThat(underTest.get())
- .extracting(BuiltInQProfile::getLanguage, BuiltInQProfile::isDefault)
- .containsExactly(tuple(FOO_LANGUAGE.getKey(), true));
- }
-
- @Test
- public void make_single_profile_of_a_language_default_even_if_flagged_as_so() {
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE),
- new DummyProfileDefinition("foo", "foo1", true));
-
- underTest.initialize();
-
- assertThat(underTest.get())
- .extracting(BuiltInQProfile::getLanguage, BuiltInQProfile::isDefault)
- .containsExactly(tuple(FOO_LANGUAGE.getKey(), true));
- }
-
- @Test
- public void make_first_profile_of_a_language_default_when_none_flagged_as_so() {
- 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();
-
- assertThat(underTest.get())
- .extracting(BuiltInQProfile::getName, BuiltInQProfile::isDefault)
- .containsExactlyInAnyOrder(tuple(firstName, true), tuple(secondName, false));
- }
-
- @Test
- public void create_profile_Sonar_Way_as_default_if_none_other_is_defined_default_for_a_given_language() {
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(
- 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));
-
- underTest.initialize();
-
- assertThat(underTest.get())
- .filteredOn(b -> FOO_LANGUAGE.getKey().equals(b.getLanguage()))
- .filteredOn(BuiltInQProfile::isDefault)
- .extracting(BuiltInQProfile::getName)
- .containsExactly(SONAR_WAY_QP_NAME);
- }
-
- @Test
- public void do_not_create_Sonar_Way_as_default_if_other_profile_is_defined_as_default() {
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(
- dbClient, ruleFinder, new Languages(FOO_LANGUAGE),
- new DummyProfileDefinition("foo", SONAR_WAY_QP_NAME, false), new DummyProfileDefinition("foo", "goo", true));
-
- underTest.initialize();
-
- assertThat(underTest.get())
- .filteredOn(b -> FOO_LANGUAGE.getKey().equals(b.getLanguage()))
- .filteredOn(BuiltInQProfile::isDefault)
- .extracting(BuiltInQProfile::getName)
- .containsExactly("goo");
- }
-
- @Test
- public void match_Sonar_Way_default_with_case_sensitivity() {
- String sonarWayInOtherCase = SONAR_WAY_QP_NAME.toUpperCase();
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(
- dbClient, ruleFinder, new Languages(FOO_LANGUAGE),
- new DummyProfileDefinition("foo", "goo", false), new DummyProfileDefinition("foo", sonarWayInOtherCase, false));
-
- underTest.initialize();
-
- assertThat(underTest.get())
- .filteredOn(b -> FOO_LANGUAGE.getKey().equals(b.getLanguage()))
- .filteredOn(BuiltInQProfile::isDefault)
- .extracting(BuiltInQProfile::getName)
- .containsExactly("goo");
- }
-
- @Test
- public void create_no_BuiltInQProfile_when_all_definitions_apply_to_non_defined_languages() {
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), ruleFinder, new Languages(),
- new DummyProfileDefinition("foo", "P1", false));
-
- underTest.initialize();
-
- assertThat(underTest.get()).isEmpty();
- }
-
- @Test
- public void create_qprofile_with_deprecated_rule() {
- RuleDefinitionDto rule1 = db.rules().insert();
- db.rules().insertDeprecatedKey(d -> d.setRuleUuid(rule1.getUuid()).setOldRepositoryKey("oldRepo").setOldRuleKey("oldKey"));
- RuleDefinitionDto rule2 = db.rules().insert();
- 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();
-
- assertThat(underTest.get())
- .extracting(BuiltInQProfile::getName)
- .containsExactlyInAnyOrder("foo");
- assertThat(underTest.get().get(0).getActiveRules())
- .extracting(ActiveRule::getRuleUuid, ActiveRule::getRuleKey)
- .containsExactlyInAnyOrder(
- tuple(rule1.getUuid(), rule1.getKey()),
- tuple(rule2.getUuid(), rule2.getKey()));
- }
-
- @Test
- public void fail_with_ISE_when_rule_does_not_exist() {
- DummyProfileDefinition[] definitions = new DummyProfileDefinition[] {new DummyProfileDefinition("foo", "foo", false, singletonList(EXTERNAL_XOO))};
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE), definitions);
-
-
- }
-
- @Test
- public void fail_with_ISE_when_two_profiles_with_different_name_are_default_for_the_same_language() {
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE),
- new DummyProfileDefinition("foo", "foo1", true), new DummyProfileDefinition("foo", "foo2", true));
-
- assertThatThrownBy(underTest::initialize)
- .isInstanceOf(IllegalStateException.class)
- .hasMessage("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), ruleFinder, new Languages());
-
- assertThatThrownBy(underTest::get)
- .isInstanceOf(IllegalStateException.class)
- .hasMessage("initialize must be called first");
- }
-
- @Test
- public void initialize_throws_ISE_if_called_twice() {
- BuiltInQProfileRepositoryImpl underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), ruleFinder, new Languages());
- underTest.initialize();
-
- assertThatThrownBy(underTest::initialize)
- .isInstanceOf(IllegalStateException.class)
- .hasMessage("initialize must be called only once");
- }
-
- @Test
- public void initialize_throws_ISE_if_language_has_no_builtin_qp() {
- BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), ruleFinder, new Languages(FOO_LANGUAGE));
-
- assertThatThrownBy(underTest::initialize)
- .isInstanceOf(IllegalStateException.class)
- .hasMessage("The following languages have no built-in quality profiles: foo");
- }
-
- private static final class DummyProfileDefinition implements BuiltInQualityProfilesDefinition {
- private final String language;
- private final String name;
- private final boolean defaultProfile;
- private final List<RuleKey> activeRuleKeys;
-
- private DummyProfileDefinition(String language, String name, boolean defaultProfile, List<RuleKey> activeRuleKeys) {
- this.language = language;
- this.name = name;
- this.defaultProfile = defaultProfile;
- this.activeRuleKeys = activeRuleKeys;
- }
-
- private DummyProfileDefinition(String language, String name, boolean defaultProfile) {
- this(language, name, defaultProfile, emptyList());
- }
-
- @Override
- public void define(Context context) {
- NewBuiltInQualityProfile builtInQualityProfile = context.createBuiltInQualityProfile(name, language);
- activeRuleKeys.forEach(activeRuleKey -> builtInQualityProfile.activateRule(activeRuleKey.repository(), activeRuleKey.rule()));
- builtInQualityProfile.setDefault(defaultProfile);
- builtInQualityProfile.done();
- }
-
- String getName() {
- return name;
- }
-
- }
-
-}
diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImplTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImplTest.java
deleted file mode 100644
index 024de98b39f..00000000000
--- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImplTest.java
+++ /dev/null
@@ -1,554 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import javax.annotation.Nullable;
-import org.assertj.core.groups.Tuple;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.impl.utils.TestSystem2;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
-import org.sonar.api.rules.RulePriority;
-import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
-import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.NewBuiltInQualityProfile;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbSession;
-import org.sonar.db.DbTester;
-import org.sonar.db.qualityprofile.ActiveRuleDto;
-import org.sonar.db.qualityprofile.ActiveRuleKey;
-import org.sonar.db.qualityprofile.ActiveRuleParamDto;
-import org.sonar.db.qualityprofile.OrgActiveRuleDto;
-import org.sonar.db.qualityprofile.QProfileDto;
-import org.sonar.db.qualityprofile.RulesProfileDto;
-import org.sonar.db.rule.RuleDefinitionDto;
-import org.sonar.db.rule.RuleParamDto;
-import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.util.IntegerTypeValidation;
-import org.sonar.server.util.StringTypeValidation;
-import org.sonar.server.util.TypeValidations;
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.emptyMap;
-import static java.util.Collections.singletonList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.groups.Tuple.tuple;
-import static org.mockito.ArgumentMatchers.any;
-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.verifyNoMoreInteractions;
-import static org.sonar.api.rules.RulePriority.BLOCKER;
-import static org.sonar.api.rules.RulePriority.CRITICAL;
-import static org.sonar.api.rules.RulePriority.MAJOR;
-import static org.sonar.api.rules.RulePriority.MINOR;
-import static org.sonar.db.qualityprofile.QualityProfileTesting.newRuleProfileDto;
-import static org.sonar.server.qualityprofile.ActiveRuleInheritance.INHERITED;
-
-public class BuiltInQProfileUpdateImplTest {
-
- private static final long NOW = 1_000;
- private static final long PAST = NOW - 100;
-
- @Rule
- public BuiltInQProfileRepositoryRule builtInProfileRepository = new BuiltInQProfileRepositoryRule();
- @Rule
- public DbTester db = DbTester.create();
- @Rule
- public UserSessionRule userSession = UserSessionRule.standalone();
- private System2 system2 = new TestSystem2().setNow(NOW);
- private ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class);
- private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation()));
- private QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class);
- private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession);
-
- private BuiltInQProfileUpdateImpl underTest = new BuiltInQProfileUpdateImpl(db.getDbClient(), ruleActivator, activeRuleIndexer,
- qualityProfileChangeEventService);
-
- private RulesProfileDto persistedProfile;
-
- @Before
- public void setUp() {
- persistedProfile = newRuleProfileDto(rp -> rp
- .setIsBuiltIn(true)
- .setLanguage("xoo")
- .setRulesUpdatedAt(null));
- db.getDbClient().qualityProfileDao().insert(db.getSession(), persistedProfile);
- db.commit();
- }
-
- @Test
- public void activate_new_rules() {
- RuleDefinitionDto rule1 = db.rules().insert(r -> r.setLanguage("xoo"));
- RuleDefinitionDto rule2 = db.rules().insert(r -> r.setLanguage("xoo"));
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", "xoo");
- newQp.activateRule(rule1.getRepositoryKey(), rule1.getRuleKey()).overrideSeverity(Severity.CRITICAL);
- newQp.activateRule(rule2.getRepositoryKey(), rule2.getRuleKey()).overrideSeverity(Severity.MAJOR);
- newQp.done();
- BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule1, rule2);
-
- List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile);
-
- List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
- assertThat(activeRules).hasSize(2);
- assertThatRuleIsNewlyActivated(activeRules, rule1, CRITICAL);
- assertThatRuleIsNewlyActivated(activeRules, rule2, MAJOR);
- assertThatProfileIsMarkedAsUpdated(persistedProfile);
- verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
- }
-
- @Test
- public void already_activated_rule_is_updated_in_case_of_differences() {
- RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo"));
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", "xoo");
- newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey()).overrideSeverity(Severity.CRITICAL);
- newQp.done();
- BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule);
-
- activateRuleInDb(persistedProfile, rule, BLOCKER);
-
- List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile);
-
- List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
- assertThat(activeRules).hasSize(1);
- assertThatRuleIsUpdated(activeRules, rule, CRITICAL);
- assertThatProfileIsMarkedAsUpdated(persistedProfile);
- verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
- }
-
- @Test
- public void already_activated_rule_is_not_touched_if_no_differences() {
- RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo"));
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", "xoo");
- newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey()).overrideSeverity(Severity.CRITICAL);
- newQp.done();
- BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule);
-
- activateRuleInDb(persistedProfile, rule, CRITICAL);
-
- underTest.update(db.getSession(), builtIn, persistedProfile);
-
- List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
- assertThat(activeRules).hasSize(1);
- assertThatRuleIsUntouched(activeRules, rule, CRITICAL);
- assertThatProfileIsNotMarkedAsUpdated(persistedProfile);
- verifyNoInteractions(qualityProfileChangeEventService);
- }
-
- @Test
- public void deactivate_rule_that_is_not_in_built_in_definition_anymore() {
- RuleDefinitionDto rule1 = db.rules().insert(r -> r.setLanguage("xoo"));
- RuleDefinitionDto rule2 = db.rules().insert(r -> r.setLanguage("xoo"));
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", "xoo");
- newQp.activateRule(rule2.getRepositoryKey(), rule2.getRuleKey()).overrideSeverity(Severity.MAJOR);
- newQp.done();
- BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule1, rule2);
-
- // built-in definition contains only rule2
- // so rule1 must be deactivated
- activateRuleInDb(persistedProfile, rule1, CRITICAL);
-
- List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile);
-
- List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
- assertThat(activeRules).hasSize(1);
- assertThatRuleIsDeactivated(activeRules, rule1);
- assertThatProfileIsMarkedAsUpdated(persistedProfile);
- verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
- }
-
- @Test
- public void activate_deactivate_and_update_three_rules_at_the_same_time() {
- RuleDefinitionDto rule1 = db.rules().insert(r -> r.setLanguage("xoo"));
- RuleDefinitionDto rule2 = db.rules().insert(r -> r.setLanguage("xoo"));
- RuleDefinitionDto rule3 = db.rules().insert(r -> r.setLanguage("xoo"));
-
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", "xoo");
- newQp.activateRule(rule1.getRepositoryKey(), rule1.getRuleKey()).overrideSeverity(Severity.CRITICAL);
- newQp.activateRule(rule2.getRepositoryKey(), rule2.getRuleKey()).overrideSeverity(Severity.MAJOR);
- newQp.done();
- BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule1, rule2);
-
- // rule1 must be updated (blocker to critical)
- // rule2 must be activated
- // rule3 must be deactivated
- activateRuleInDb(persistedProfile, rule1, BLOCKER);
- activateRuleInDb(persistedProfile, rule3, BLOCKER);
-
- List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile);
-
- List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
- assertThat(activeRules).hasSize(2);
- assertThatRuleIsUpdated(activeRules, rule1, CRITICAL);
- assertThatRuleIsNewlyActivated(activeRules, rule2, MAJOR);
- assertThatRuleIsDeactivated(activeRules, rule3);
- assertThatProfileIsMarkedAsUpdated(persistedProfile);
- verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
- }
-
- // SONAR-10473
- @Test
- public void activate_rule_on_built_in_profile_resets_severity_to_default_if_not_overridden() {
- RuleDefinitionDto rule = db.rules().insert(r -> r.setSeverity(Severity.MAJOR).setLanguage("xoo"));
-
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", "xoo");
- newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey());
- newQp.done();
- BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule);
- underTest.update(db.getSession(), builtIn, persistedProfile);
-
- List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
- assertThatRuleIsNewlyActivated(activeRules, rule, MAJOR);
-
- // emulate an upgrade of analyzer that changes the default severity of the rule
- rule.setSeverity(Severity.MINOR);
- db.rules().update(rule);
-
- List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile);
- activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
- assertThatRuleIsNewlyActivated(activeRules, rule, MINOR);
- verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
- }
-
- @Test
- public void activate_rule_on_built_in_profile_resets_params_to_default_if_not_overridden() {
- RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo"));
- RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10"));
-
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", rule.getLanguage());
- newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey());
- newQp.done();
- BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile(newQp.language(), newQp.name()), rule);
- List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, persistedProfile);
-
- List<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
- assertThat(activeRules).hasSize(1);
- assertThatRuleHasParams(db, activeRules.get(0), tuple("min", "10"));
- verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
-
- // emulate an upgrade of analyzer that changes the default value of parameter min
- ruleParam.setDefaultValue("20");
- db.getDbClient().ruleDao().updateRuleParam(db.getSession(), rule, ruleParam);
-
- changes = underTest.update(db.getSession(), builtIn, persistedProfile);
- activeRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), persistedProfile);
- assertThat(activeRules).hasSize(1);
- assertThatRuleHasParams(db, activeRules.get(0), tuple("min", "20"));
- verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
- }
-
- @Test
- public void propagate_activation_to_descendant_profiles() {
- RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo"));
-
- QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
- QProfileDto childProfile = createChildProfile(profile);
- QProfileDto grandchildProfile = createChildProfile(childProfile);
-
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile(profile.getName(), profile.getLanguage());
- newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey());
- newQp.done();
- BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile(profile.getLanguage(), profile.getName()), rule);
- List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, RulesProfileDto.from(profile));
-
- assertThat(changes).hasSize(3);
- assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, emptyMap());
- assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
- assertThatRuleIsActivated(grandchildProfile, rule, changes, rule.getSeverityString(), INHERITED, emptyMap());
- verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
- }
-
- // SONAR-14559
- @Test
- public void propagate_rule_update_to_descendant_active_rule() {
- RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo").setSeverity(Severity.BLOCKER));
-
- QProfileDto parentProfile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
- activateRuleInDb(RulesProfileDto.from(parentProfile), rule, RulePriority.valueOf(Severity.MINOR), null);
-
- QProfileDto childProfile = createChildProfile(parentProfile);
- activateRuleInDb(RulesProfileDto.from(childProfile), rule, RulePriority.valueOf(Severity.MINOR), INHERITED);
-
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile(parentProfile.getName(), parentProfile.getLanguage());
- newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey());
- newQp.done();
- BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile(parentProfile.getLanguage(), parentProfile.getName()), rule);
- List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, RulesProfileDto.from(parentProfile));
-
- assertThat(changes).hasSize(2);
-
- List<ActiveRuleDto> parentActiveRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), RulesProfileDto.from(parentProfile));
- assertThatRuleIsUpdated(parentActiveRules, rule, RulePriority.BLOCKER, null);
-
- List<ActiveRuleDto> childActiveRules = db.getDbClient().activeRuleDao().selectByRuleProfile(db.getSession(), RulesProfileDto.from(childProfile));
- assertThatRuleIsUpdated(childActiveRules, rule, RulePriority.BLOCKER, INHERITED);
- verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
- }
-
- @Test
- public void propagate_rule_param_update_to_descendant_active_rule_params() {
- RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo").setSeverity(Severity.BLOCKER));
- RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10"));
-
- QProfileDto parentProfile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
- ActiveRuleDto parentActiveRuleDto = activateRuleInDb(RulesProfileDto.from(parentProfile), rule,
- RulePriority.valueOf(Severity.MINOR), null);
- activateRuleParamInDb(parentActiveRuleDto, ruleParam, "20");
-
- QProfileDto childProfile = createChildProfile(parentProfile);
- ActiveRuleDto childActiveRuleDto = activateRuleInDb(RulesProfileDto.from(childProfile), rule,
- RulePriority.valueOf(Severity.MINOR), INHERITED);
- activateRuleParamInDb(childActiveRuleDto, ruleParam, "20");
-
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile(parentProfile.getName(), parentProfile.getLanguage());
- newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey());
- newQp.done();
- BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile(parentProfile.getLanguage(), parentProfile.getName()), rule);
- List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, RulesProfileDto.from(parentProfile));
-
- assertThat(changes).hasSize(2);
-
- assertThatRuleHasParams(db, parentActiveRuleDto, tuple("min", "10"));
- assertThatRuleHasParams(db, childActiveRuleDto, tuple("min", "10"));
- verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
- }
-
- @Test
- public void do_not_load_descendants_if_no_changes() {
- RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo"));
-
- QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
- QProfileDto childProfile = createChildProfile(profile);
-
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile(profile.getName(), profile.getLanguage());
- newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey());
- newQp.done();
-
- // first run
- BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile(profile.getLanguage(), profile.getName()), rule);
- List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, RulesProfileDto.from(profile));
- assertThat(changes).hasSize(2).extracting(ActiveRuleChange::getType).containsOnly(ActiveRuleChange.Type.ACTIVATED);
- verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
-
- // second run, without any input changes
- RuleActivator ruleActivatorWithoutDescendants = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession) {
- @Override
- DescendantProfilesSupplier createDescendantProfilesSupplier(DbSession dbSession) {
- return (profiles, ruleIds) -> {
- throw new IllegalStateException("BOOM - descendants should not be loaded");
- };
- }
- };
- changes = new BuiltInQProfileUpdateImpl(db.getDbClient(), ruleActivatorWithoutDescendants, activeRuleIndexer, qualityProfileChangeEventService)
- .update(db.getSession(), builtIn, RulesProfileDto.from(profile));
- assertThat(changes).isEmpty();
- verifyNoMoreInteractions(qualityProfileChangeEventService);
- }
-
- @Test
- public void propagate_deactivation_to_descendant_profiles() {
- RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo"));
-
- QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
- QProfileDto childProfile = createChildProfile(profile);
- QProfileDto grandChildProfile = createChildProfile(childProfile);
-
- BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile(profile.getName(), profile.getLanguage());
- newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey());
- newQp.done();
-
- // first run to activate the rule
- BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile(profile.getLanguage(), profile.getName()), rule);
- List<ActiveRuleChange> changes = underTest.update(db.getSession(), builtIn, RulesProfileDto.from(profile));
- assertThat(changes).hasSize(3).extracting(ActiveRuleChange::getType).containsOnly(ActiveRuleChange.Type.ACTIVATED);
- verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
-
- // second run to deactivate the rule
- context = new BuiltInQualityProfilesDefinition.Context();
- NewBuiltInQualityProfile updatedQp = context.createBuiltInQualityProfile(profile.getName(), profile.getLanguage());
- updatedQp.done();
- builtIn = builtInProfileRepository.create(context.profile(profile.getLanguage(), profile.getName()), rule);
- changes = underTest.update(db.getSession(), builtIn, RulesProfileDto.from(profile));
- assertThat(changes).hasSize(3).extracting(ActiveRuleChange::getType).containsOnly(ActiveRuleChange.Type.DEACTIVATED);
- verify(qualityProfileChangeEventService).distributeRuleChangeEvent(any(), eq(changes), eq(persistedProfile.getLanguage()));
-
- assertThatRuleIsDeactivated(profile, rule);
- assertThatRuleIsDeactivated(childProfile, rule);
- assertThatRuleIsDeactivated(grandChildProfile, rule);
- }
-
- private QProfileDto createChildProfile(QProfileDto parent) {
- return db.qualityProfiles().insert(p -> p
- .setLanguage(parent.getLanguage())
- .setParentKee(parent.getKee())
- .setName("Child of " + parent.getName()))
- .setIsBuiltIn(false);
- }
-
- private void assertThatRuleIsActivated(QProfileDto profile, RuleDefinitionDto rule, @Nullable List<ActiveRuleChange> changes,
- String expectedSeverity, @Nullable ActiveRuleInheritance expectedInheritance, Map<String, String> expectedParams) {
- OrgActiveRuleDto activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)
- .stream()
- .filter(ar -> ar.getRuleKey().equals(rule.getKey()))
- .findFirst()
- .orElseThrow(IllegalStateException::new);
-
- assertThat(activeRule.getSeverityString()).isEqualTo(expectedSeverity);
- assertThat(activeRule.getInheritance()).isEqualTo(expectedInheritance != null ? expectedInheritance.name() : null);
-
- List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleUuid(db.getSession(), activeRule.getUuid());
- assertThat(params).hasSize(expectedParams.size());
-
- if (changes != null) {
- ActiveRuleChange change = changes.stream()
- .filter(c -> c.getActiveRule().getUuid().equals(activeRule.getUuid()))
- .findFirst().orElseThrow(IllegalStateException::new);
- assertThat(change.getInheritance()).isEqualTo(expectedInheritance);
- assertThat(change.getSeverity()).isEqualTo(expectedSeverity);
- assertThat(change.getType()).isEqualTo(ActiveRuleChange.Type.ACTIVATED);
- }
- }
-
- private static void assertThatRuleHasParams(DbTester db, ActiveRuleDto activeRule, Tuple... expectedParams) {
- assertThat(db.getDbClient().activeRuleDao().selectParamsByActiveRuleUuid(db.getSession(), activeRule.getUuid()))
- .extracting(ActiveRuleParamDto::getKey, ActiveRuleParamDto::getValue)
- .containsExactlyInAnyOrder(expectedParams);
- }
-
- private static void assertThatRuleIsNewlyActivated(List<ActiveRuleDto> activeRules, RuleDefinitionDto rule, RulePriority severity) {
- ActiveRuleDto activeRule = findRule(activeRules, rule).get();
-
- assertThat(activeRule.getInheritance()).isNull();
- assertThat(activeRule.getSeverityString()).isEqualTo(severity.name());
- assertThat(activeRule.getCreatedAt()).isEqualTo(NOW);
- assertThat(activeRule.getUpdatedAt()).isEqualTo(NOW);
- }
-
- private static void assertThatRuleIsUpdated(List<ActiveRuleDto> activeRules, RuleDefinitionDto rule, RulePriority severity, @Nullable ActiveRuleInheritance expectedInheritance) {
- ActiveRuleDto activeRule = findRule(activeRules, rule).get();
-
- if (expectedInheritance != null) {
- assertThat(activeRule.getInheritance()).isEqualTo(expectedInheritance.name());
- } else {
- assertThat(activeRule.getInheritance()).isNull();
- }
- assertThat(activeRule.getSeverityString()).isEqualTo(severity.name());
- assertThat(activeRule.getCreatedAt()).isEqualTo(PAST);
- assertThat(activeRule.getUpdatedAt()).isEqualTo(NOW);
- }
-
- private static void assertThatRuleIsUpdated(List<ActiveRuleDto> activeRules, RuleDefinitionDto rule, RulePriority severity) {
- assertThatRuleIsUpdated(activeRules, rule, severity, null);
- }
-
- private static void assertThatRuleIsUpdated(ActiveRuleDto activeRules, RuleDefinitionDto rule, RulePriority severity, @Nullable ActiveRuleInheritance expectedInheritance) {
- assertThatRuleIsUpdated(singletonList(activeRules), rule, severity, expectedInheritance);
- }
-
- private static void assertThatRuleIsUntouched(List<ActiveRuleDto> activeRules, RuleDefinitionDto rule, RulePriority severity) {
- ActiveRuleDto activeRule = findRule(activeRules, rule).get();
-
- assertThat(activeRule.getInheritance()).isNull();
- assertThat(activeRule.getSeverityString()).isEqualTo(severity.name());
- assertThat(activeRule.getCreatedAt()).isEqualTo(PAST);
- assertThat(activeRule.getUpdatedAt()).isEqualTo(PAST);
- }
-
- private void assertThatRuleIsDeactivated(QProfileDto profile, RuleDefinitionDto rule) {
- Collection<ActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByRulesAndRuleProfileUuids(
- db.getSession(), singletonList(rule.getUuid()), singletonList(profile.getRulesProfileUuid()));
- assertThat(activeRules).isEmpty();
- }
-
- private static void assertThatRuleIsDeactivated(List<ActiveRuleDto> activeRules, RuleDefinitionDto rule) {
- assertThat(findRule(activeRules, rule)).isEmpty();
- }
-
- private void assertThatProfileIsMarkedAsUpdated(RulesProfileDto dto) {
- RulesProfileDto reloaded = db.getDbClient().qualityProfileDao().selectBuiltInRuleProfiles(db.getSession())
- .stream()
- .filter(p -> p.getUuid().equals(dto.getUuid()))
- .findFirst()
- .get();
- assertThat(reloaded.getRulesUpdatedAt()).isNotEmpty();
- }
-
- private void assertThatProfileIsNotMarkedAsUpdated(RulesProfileDto dto) {
- RulesProfileDto reloaded = db.getDbClient().qualityProfileDao().selectBuiltInRuleProfiles(db.getSession())
- .stream()
- .filter(p -> p.getUuid().equals(dto.getUuid()))
- .findFirst()
- .get();
- assertThat(reloaded.getRulesUpdatedAt()).isNull();
- }
-
- private static Optional<ActiveRuleDto> findRule(List<ActiveRuleDto> activeRules, RuleDefinitionDto rule) {
- return activeRules.stream()
- .filter(ar -> ar.getRuleKey().equals(rule.getKey()))
- .findFirst();
- }
-
- private ActiveRuleDto activateRuleInDb(RulesProfileDto profile, RuleDefinitionDto rule, RulePriority severity) {
- return activateRuleInDb(profile, rule, severity, null);
- }
-
- private ActiveRuleDto activateRuleInDb(RulesProfileDto ruleProfile, RuleDefinitionDto rule, RulePriority severity, @Nullable ActiveRuleInheritance inheritance) {
- ActiveRuleDto dto = new ActiveRuleDto()
- .setKey(ActiveRuleKey.of(ruleProfile, RuleKey.of(rule.getRepositoryKey(), rule.getRuleKey())))
- .setProfileUuid(ruleProfile.getUuid())
- .setSeverity(severity.name())
- .setRuleUuid(rule.getUuid())
- .setInheritance(inheritance != null ? inheritance.name() : null)
- .setCreatedAt(PAST)
- .setUpdatedAt(PAST);
- db.getDbClient().activeRuleDao().insert(db.getSession(), dto);
- db.commit();
- return dto;
- }
-
- private void activateRuleParamInDb(ActiveRuleDto activeRuleDto, RuleParamDto ruleParamDto, String value) {
- ActiveRuleParamDto dto = new ActiveRuleParamDto()
- .setActiveRuleUuid(activeRuleDto.getUuid())
- .setRulesParameterUuid(ruleParamDto.getUuid())
- .setKey(ruleParamDto.getName())
- .setValue(value);
- db.getDbClient().activeRuleDao().insertParam(db.getSession(), activeRuleDto, dto);
- db.commit();
- }
-}
diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesUpdateListenerTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesUpdateListenerTest.java
deleted file mode 100644
index 2f6fc1719d1..00000000000
--- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/BuiltInQualityProfilesUpdateListenerTest.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Multimap;
-import org.assertj.core.groups.Tuple;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.notifications.Notification;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Languages;
-import org.sonar.core.util.Uuids;
-import org.sonar.db.qualityprofile.ActiveRuleKey;
-import org.sonar.db.rule.RuleDefinitionDto;
-import org.sonar.server.notification.NotificationManager;
-import org.sonar.server.qualityprofile.BuiltInQPChangeNotificationBuilder.Profile;
-
-import static java.util.Arrays.asList;
-import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.tuple;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.sonar.core.config.CorePropertyDefinitions.DISABLE_NOTIFICATION_ON_BUILT_IN_QPROFILES;
-import static org.sonar.server.language.LanguageTesting.newLanguage;
-import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.ACTIVATED;
-import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.DEACTIVATED;
-import static org.sonar.server.qualityprofile.ActiveRuleChange.Type.UPDATED;
-
-public class BuiltInQualityProfilesUpdateListenerTest {
-
- private NotificationManager notificationManager = mock(NotificationManager.class);
- private MapSettings settings = new MapSettings();
-
- @Test
- public void add_profile_to_notification_for_added_rules() {
- enableNotificationInGlobalSettings();
- Multimap<QProfileName, ActiveRuleChange> profiles = ArrayListMultimap.create();
- Languages languages = new Languages();
- Tuple expectedTuple = addProfile(profiles, languages, ACTIVATED);
-
- BuiltInQualityProfilesUpdateListener underTest = new BuiltInQualityProfilesUpdateListener(notificationManager, languages, settings.asConfig());
- underTest.onChange(profiles, 0, 1);
-
- ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class);
- verify(notificationManager).scheduleForSending(notificationArgumentCaptor.capture());
- verifyNoMoreInteractions(notificationManager);
- assertThat(BuiltInQPChangeNotificationBuilder.parse(notificationArgumentCaptor.getValue()).getProfiles())
- .extracting(Profile::getProfileName, Profile::getLanguageKey, Profile::getLanguageName, Profile::getNewRules)
- .containsExactlyInAnyOrder(expectedTuple);
- }
-
- @Test
- public void add_profile_to_notification_for_updated_rules() {
- enableNotificationInGlobalSettings();
- Multimap<QProfileName, ActiveRuleChange> profiles = ArrayListMultimap.create();
- Languages languages = new Languages();
- Tuple expectedTuple = addProfile(profiles, languages, UPDATED);
-
- BuiltInQualityProfilesUpdateListener underTest = new BuiltInQualityProfilesUpdateListener(notificationManager, languages, settings.asConfig());
- underTest.onChange(profiles, 0, 1);
-
- ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class);
- verify(notificationManager).scheduleForSending(notificationArgumentCaptor.capture());
- verifyNoMoreInteractions(notificationManager);
- assertThat(BuiltInQPChangeNotificationBuilder.parse(notificationArgumentCaptor.getValue()).getProfiles())
- .extracting(Profile::getProfileName, Profile::getLanguageKey, Profile::getLanguageName, Profile::getUpdatedRules)
- .containsExactlyInAnyOrder(expectedTuple);
- }
-
- @Test
- public void add_profile_to_notification_for_removed_rules() {
- enableNotificationInGlobalSettings();
- Multimap<QProfileName, ActiveRuleChange> profiles = ArrayListMultimap.create();
- Languages languages = new Languages();
- Tuple expectedTuple = addProfile(profiles, languages, DEACTIVATED);
-
- BuiltInQualityProfilesUpdateListener underTest = new BuiltInQualityProfilesUpdateListener(notificationManager, languages, settings.asConfig());
- underTest.onChange(profiles, 0, 1);
-
- ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class);
- verify(notificationManager).scheduleForSending(notificationArgumentCaptor.capture());
- verifyNoMoreInteractions(notificationManager);
- assertThat(BuiltInQPChangeNotificationBuilder.parse(notificationArgumentCaptor.getValue()).getProfiles())
- .extracting(Profile::getProfileName, Profile::getLanguageKey, Profile::getLanguageName, Profile::getRemovedRules)
- .containsExactlyInAnyOrder(expectedTuple);
- }
-
- @Test
- public void add_multiple_profiles_to_notification() {
- enableNotificationInGlobalSettings();
- Multimap<QProfileName, ActiveRuleChange> profiles = ArrayListMultimap.create();
- Languages languages = new Languages();
- Tuple expectedTuple1 = addProfile(profiles, languages, ACTIVATED);
- Tuple expectedTuple2 = addProfile(profiles, languages, ACTIVATED);
-
- BuiltInQualityProfilesUpdateListener underTest = new BuiltInQualityProfilesUpdateListener(notificationManager, languages, settings.asConfig());
- underTest.onChange(profiles, 0, 1);
-
- ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class);
- verify(notificationManager).scheduleForSending(notificationArgumentCaptor.capture());
- verifyNoMoreInteractions(notificationManager);
- assertThat(BuiltInQPChangeNotificationBuilder.parse(notificationArgumentCaptor.getValue()).getProfiles())
- .extracting(Profile::getProfileName, Profile::getLanguageKey, Profile::getLanguageName, Profile::getNewRules)
- .containsExactlyInAnyOrder(expectedTuple1, expectedTuple2);
- }
-
- @Test
- public void add_start_and_end_dates_to_notification() {
- enableNotificationInGlobalSettings();
- Multimap<QProfileName, ActiveRuleChange> profiles = ArrayListMultimap.create();
- Languages languages = new Languages();
- addProfile(profiles, languages, ACTIVATED);
- long startDate = 10_000_000_000L;
- long endDate = 15_000_000_000L;
-
- BuiltInQualityProfilesUpdateListener underTest = new BuiltInQualityProfilesUpdateListener(notificationManager, languages, settings.asConfig());
- underTest.onChange(profiles, startDate, endDate);
-
- ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class);
- verify(notificationManager).scheduleForSending(notificationArgumentCaptor.capture());
- verifyNoMoreInteractions(notificationManager);
- assertThat(BuiltInQPChangeNotificationBuilder.parse(notificationArgumentCaptor.getValue()).getProfiles())
- .extracting(Profile::getStartDate, Profile::getEndDate)
- .containsExactlyInAnyOrder(tuple(startDate, endDate));
- }
-
- @Test
- public void avoid_notification_if_configured_in_settings() {
- settings.setProperty(DISABLE_NOTIFICATION_ON_BUILT_IN_QPROFILES, true);
- Multimap<QProfileName, ActiveRuleChange> profiles = ArrayListMultimap.create();
- Languages languages = new Languages();
- addProfile(profiles, languages, ACTIVATED);
-
- BuiltInQualityProfilesUpdateListener underTest = new BuiltInQualityProfilesUpdateListener(notificationManager, languages, settings.asConfig());
- underTest.onChange(profiles, 0, 1);
-
- verifyZeroInteractions(notificationManager);
- }
-
- private Tuple addProfile(Multimap<QProfileName, ActiveRuleChange> profiles, Languages languages, ActiveRuleChange.Type type) {
- String profileName = randomLowerCaseText();
- String ruleUuid1 = Uuids.createFast();
- String ruleUuid2 = Uuids.createFast();
- Language language = newLanguage(randomLowerCaseText(), randomLowerCaseText());
- languages.add(language);
- profiles.putAll(new QProfileName(language.getKey(), profileName),
- asList(new ActiveRuleChange(
- type,
- ActiveRuleKey.parse("qp:repo:rule1"), new RuleDefinitionDto().setUuid(ruleUuid1)),
- new ActiveRuleChange(type, ActiveRuleKey.parse("qp:repo:rule2"), new RuleDefinitionDto().setUuid(ruleUuid2))));
- return tuple(profileName, language.getKey(), language.getName(), 2);
- }
-
- private static String randomLowerCaseText() {
- return randomAlphanumeric(20).toLowerCase();
- }
-
- private void enableNotificationInGlobalSettings() {
- settings.setProperty(DISABLE_NOTIFICATION_ON_BUILT_IN_QPROFILES, false);
- }
-}
diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/RuleActivatorTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/RuleActivatorTest.java
deleted file mode 100644
index cdcd4fa41e2..00000000000
--- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/qualityprofile/RuleActivatorTest.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import com.google.common.collect.ImmutableMap;
-import java.util.List;
-import javax.annotation.Nullable;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.impl.utils.TestSystem2;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
-import org.sonar.api.rules.RulePriority;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbSession;
-import org.sonar.db.DbTester;
-import org.sonar.db.qualityprofile.ActiveRuleDto;
-import org.sonar.db.qualityprofile.ActiveRuleKey;
-import org.sonar.db.qualityprofile.ActiveRuleParamDto;
-import org.sonar.db.qualityprofile.QProfileDto;
-import org.sonar.db.qualityprofile.RulesProfileDto;
-import org.sonar.db.rule.RuleDefinitionDto;
-import org.sonar.db.rule.RuleParamDto;
-import org.sonar.server.exceptions.BadRequestException;
-import org.sonar.server.qualityprofile.DescendantProfilesSupplier.Result;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.util.IntegerTypeValidation;
-import org.sonar.server.util.StringTypeValidation;
-import org.sonar.server.util.TypeValidations;
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.emptyList;
-import static java.util.Collections.singletonList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.assertThrows;
-import static org.mockito.Mockito.mock;
-import static org.sonar.server.qualityprofile.ActiveRuleInheritance.INHERITED;
-import static org.sonar.server.qualityprofile.ActiveRuleInheritance.OVERRIDES;
-
-/**
- * Class org.sonar.server.qualityprofile.RuleActivator is mostly covered in
- * org.sonar.server.qualityprofile.BuiltInQProfileUpdateImplTest
- */
-public class RuleActivatorTest {
- @Rule
- public final DbTester db = DbTester.create();
-
- @Rule
- public final UserSessionRule userSession = UserSessionRule.standalone();
-
- private static final long NOW = 1_000;
- private static final long PAST = NOW - 100;
- private final System2 system2 = new TestSystem2().setNow(NOW);
- private final TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation()));
-
- private final QualityProfileChangeEventService qualityProfileChangeEventService = mock(QualityProfileChangeEventService.class);
- private final RuleActivator underTest = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession);
-
- @Test
- public void reset_overridden_active_rule() {
- RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo").setSeverity(Severity.BLOCKER));
- RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10"));
-
- QProfileDto parentProfile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
- ActiveRuleDto parentActiveRuleDto = activateRuleInDb(RulesProfileDto.from(parentProfile), rule,
- RulePriority.valueOf(Severity.BLOCKER), null);
- ActiveRuleParamDto parentActiveRuleParam = activateRuleParamInDb(parentActiveRuleDto, ruleParam, "10");
-
- QProfileDto childProfile = createChildProfile(parentProfile);
- ActiveRuleDto childActiveRuleDto = activateRuleInDb(RulesProfileDto.from(childProfile), rule,
- RulePriority.valueOf(Severity.MINOR), OVERRIDES);
- ActiveRuleParamDto childActiveRuleParam = activateRuleParamInDb(childActiveRuleDto, ruleParam, "15");
-
- DbSession session = db.getSession();
- RuleActivation resetRequest = RuleActivation.createReset(rule.getUuid());
- RuleActivationContext context = new RuleActivationContext.Builder()
- .setProfiles(asList(parentProfile, childProfile))
- .setBaseProfile(RulesProfileDto.from(childProfile))
- .setDate(NOW)
- .setDescendantProfilesSupplier((profiles, ruleUuids) -> new Result(emptyList(), emptyList(), emptyList()))
- .setRules(singletonList(rule))
- .setRuleParams(singletonList(ruleParam))
- .setActiveRules(asList(parentActiveRuleDto, childActiveRuleDto))
- .setActiveRuleParams(asList(parentActiveRuleParam, childActiveRuleParam))
- .build();
-
- List<ActiveRuleChange> result = underTest.activate(session, resetRequest, context);
-
- assertThat(result).hasSize(1);
- assertThat(result.get(0).getParameters()).containsEntry("min", "10");
- assertThat(result.get(0).getSeverity()).isEqualTo(Severity.BLOCKER);
- assertThat(result.get(0).getInheritance()).isEqualTo(ActiveRuleInheritance.INHERITED);
- }
-
- @Test
- public void request_new_severity_and_param_for_child_rule() {
- RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo").setSeverity(Severity.BLOCKER));
- RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10"));
-
- QProfileDto parentProfile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
- ActiveRuleDto parentActiveRuleDto = activateRuleInDb(RulesProfileDto.from(parentProfile), rule,
- RulePriority.valueOf(Severity.BLOCKER), null);
- ActiveRuleParamDto parentActiveRuleParam = activateRuleParamInDb(parentActiveRuleDto, ruleParam, "10");
-
- QProfileDto childProfile = createChildProfile(parentProfile);
- ActiveRuleDto childActiveRuleDto = activateRuleInDb(RulesProfileDto.from(childProfile), rule,
- RulePriority.valueOf(Severity.BLOCKER), INHERITED);
- ActiveRuleParamDto childActiveRuleParam = activateRuleParamInDb(childActiveRuleDto, ruleParam, "10");
-
- DbSession session = db.getSession();
- RuleActivation resetRequest = RuleActivation.create(rule.getUuid(), Severity.MINOR, ImmutableMap.of("min", "15"));
- RuleActivationContext context = new RuleActivationContext.Builder()
- .setProfiles(asList(parentProfile, childProfile))
- .setBaseProfile(RulesProfileDto.from(childProfile))
- .setDate(NOW)
- .setDescendantProfilesSupplier((profiles, ruleUuids) -> new Result(emptyList(), emptyList(), emptyList()))
- .setRules(singletonList(rule))
- .setRuleParams(singletonList(ruleParam))
- .setActiveRules(asList(parentActiveRuleDto, childActiveRuleDto))
- .setActiveRuleParams(asList(parentActiveRuleParam, childActiveRuleParam))
- .build();
-
- List<ActiveRuleChange> result = underTest.activate(session, resetRequest, context);
-
- assertThat(result).hasSize(1);
- assertThat(result.get(0).getParameters()).containsEntry("min", "15");
- assertThat(result.get(0).getSeverity()).isEqualTo(Severity.MINOR);
- assertThat(result.get(0).getInheritance()).isEqualTo(OVERRIDES);
- }
-
- @Test
- public void set_severity_and_param_for_child_rule_when_activating() {
- RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo").setSeverity(Severity.BLOCKER));
- RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10"));
-
- QProfileDto parentProfile = db.qualityProfiles().insert(p -> p.setLanguage(rule.getLanguage()).setIsBuiltIn(true));
-
- QProfileDto childProfile = createChildProfile(parentProfile);
-
- DbSession session = db.getSession();
- RuleActivation resetRequest = RuleActivation.create(rule.getUuid());
- RuleActivationContext context = new RuleActivationContext.Builder()
- .setProfiles(asList(parentProfile, childProfile))
- .setBaseProfile(RulesProfileDto.from(childProfile))
- .setDate(NOW)
- .setDescendantProfilesSupplier((profiles, ruleUuids) -> new Result(emptyList(), emptyList(), emptyList()))
- .setRules(singletonList(rule))
- .setRuleParams(singletonList(ruleParam))
- .setActiveRules(emptyList())
- .setActiveRuleParams(emptyList())
- .build();
-
- List<ActiveRuleChange> result = underTest.activate(session, resetRequest, context);
-
- assertThat(result).hasSize(1);
- assertThat(result.get(0).getParameters()).containsEntry("min", "10");
- assertThat(result.get(0).getSeverity()).isEqualTo(Severity.BLOCKER);
- assertThat(result.get(0).getInheritance()).isNull();
- }
-
- @Test
- public void fail_if_rule_language_doesnt_match_qp() {
- RuleDefinitionDto rule = db.rules().insert(r -> r.setLanguage("xoo")
- .setRepositoryKey("repo")
- .setRuleKey("rule")
- .setSeverity(Severity.BLOCKER));
- QProfileDto qp = db.qualityProfiles().insert(p -> p.setLanguage("xoo2").setKee("qp").setIsBuiltIn(true));
-
- DbSession session = db.getSession();
- RuleActivation resetRequest = RuleActivation.create(rule.getUuid());
- RuleActivationContext context = new RuleActivationContext.Builder()
- .setProfiles(singletonList(qp))
- .setBaseProfile(RulesProfileDto.from(qp))
- .setDate(NOW)
- .setDescendantProfilesSupplier((profiles, ruleUuids) -> new Result(emptyList(), emptyList(), emptyList()))
- .setRules(singletonList(rule))
- .setRuleParams(emptyList())
- .setActiveRules(emptyList())
- .setActiveRuleParams(emptyList())
- .build();
-
-
- assertThrows("xoo rule repo:rule cannot be activated on xoo2 profile qp", BadRequestException.class,
- () -> underTest.activate(session, resetRequest, context));
- }
-
-
- private ActiveRuleDto activateRuleInDb(RulesProfileDto ruleProfile, RuleDefinitionDto rule, RulePriority severity, @Nullable ActiveRuleInheritance inheritance) {
- ActiveRuleDto dto = new ActiveRuleDto()
- .setKey(ActiveRuleKey.of(ruleProfile, RuleKey.of(rule.getRepositoryKey(), rule.getRuleKey())))
- .setProfileUuid(ruleProfile.getUuid())
- .setSeverity(severity.name())
- .setRuleUuid(rule.getUuid())
- .setInheritance(inheritance != null ? inheritance.name() : null)
- .setCreatedAt(PAST)
- .setUpdatedAt(PAST);
- db.getDbClient().activeRuleDao().insert(db.getSession(), dto);
- db.commit();
- return dto;
- }
-
- private ActiveRuleParamDto activateRuleParamInDb(ActiveRuleDto activeRuleDto, RuleParamDto ruleParamDto, String value) {
- ActiveRuleParamDto dto = new ActiveRuleParamDto()
- .setActiveRuleUuid(activeRuleDto.getUuid())
- .setRulesParameterUuid(ruleParamDto.getUuid())
- .setKey(ruleParamDto.getName())
- .setValue(value);
- db.getDbClient().activeRuleDao().insertParam(db.getSession(), activeRuleDto, dto);
- db.commit();
- return dto;
- }
-
- private QProfileDto createChildProfile(QProfileDto parent) {
- return db.qualityProfiles().insert(p -> p
- .setLanguage(parent.getLanguage())
- .setParentKee(parent.getKee())
- .setName("Child of " + parent.getName()))
- .setIsBuiltIn(false);
- }
-}
diff --git a/server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryRule.java b/server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryRule.java
deleted file mode 100644
index c7e2b2a9a01..00000000000
--- a/server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryRule.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.qualityprofile;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import org.junit.rules.ExternalResource;
-import org.sonar.api.resources.Language;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
-import org.sonar.core.util.stream.MoreCollectors;
-import org.sonar.db.rule.RuleDefinitionDto;
-
-import static com.google.common.base.Preconditions.checkState;
-
-public class BuiltInQProfileRepositoryRule extends ExternalResource implements BuiltInQProfileRepository {
- private boolean initializeCalled = false;
- private List<BuiltInQProfile> profiles = new ArrayList<>();
-
- @Override
- protected void before() {
- this.initializeCalled = false;
- this.profiles.clear();
- }
-
- @Override
- public void initialize() {
- checkState(!initializeCalled, "initialize must be called only once");
- this.initializeCalled = true;
- }
-
- @Override
- public List<BuiltInQProfile> get() {
- checkState(initializeCalled, "initialize must be called first");
-
- return ImmutableList.copyOf(profiles);
- }
-
- public boolean isInitialized() {
- return initializeCalled;
- }
-
- public BuiltInQProfile add(Language language, String profileName) {
- return add(language, profileName, false);
- }
-
- public BuiltInQProfile add(Language language, String profileName, boolean isDefault) {
- return add(language, profileName, isDefault, new BuiltInQProfile.ActiveRule[0]);
- }
-
- public BuiltInQProfile add(Language language, String profileName, boolean isDefault, BuiltInQProfile.ActiveRule... rules) {
- BuiltInQProfile builtIn = create(language, profileName, isDefault, rules);
- profiles.add(builtIn);
- return builtIn;
- }
-
- public BuiltInQProfile create(Language language, String profileName, boolean isDefault, BuiltInQProfile.ActiveRule... rules) {
- BuiltInQProfile.Builder builder = new BuiltInQProfile.Builder()
- .setLanguage(language.getKey())
- .setName(profileName)
- .setDeclaredDefault(isDefault);
- Arrays.stream(rules).forEach(builder::addRule);
- return builder.build();
- }
-
- public BuiltInQProfile create(BuiltInQualityProfilesDefinition.BuiltInQualityProfile api, RuleDefinitionDto... rules) {
- BuiltInQProfile.Builder builder = new BuiltInQProfile.Builder()
- .setLanguage(api.language())
- .setName(api.name())
- .setDeclaredDefault(api.isDefault());
- Map<RuleKey, RuleDefinitionDto> rulesByRuleKey = Arrays.stream(rules)
- .collect(MoreCollectors.uniqueIndex(RuleDefinitionDto::getKey));
- api.rules().forEach(rule -> {
- RuleKey ruleKey = RuleKey.of(rule.repoKey(), rule.ruleKey());
- RuleDefinitionDto ruleDefinition = rulesByRuleKey.get(ruleKey);
- Preconditions.checkState(ruleDefinition != null, "Rule '%s' not found", ruleKey);
- builder.addRule(new BuiltInQProfile.ActiveRule(ruleDefinition.getUuid(), rule));
- });
- return builder
- .build();
- }
-}