aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2014-10-14 10:16:08 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2014-10-14 10:16:08 +0200
commitbb621a7a349ddf4568d3ab592fe5a40d0297e6be (patch)
tree0cf7ab245cb6487b134be7a93e6c5452730a10b2
parentd65c9957139e4b0da94f5cf797dfe98cfd62ce77 (diff)
parent3ac8de59552f3d38f9b952079cbffa8572840731 (diff)
downloadsonarqube-bb621a7a349ddf4568d3ab592fe5a40d0297e6be.tar.gz
sonarqube-bb621a7a349ddf4568d3ab592fe5a40d0297e6be.zip
Merge remote-tracking branch 'origin/branch-4.5'
Conflicts: plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java sonar-application/src/main/assembly/conf/sonar.properties sonar-application/src/test/java/org/sonar/application/JdbcSettingsTest.java sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql
-rw-r--r--plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java19
-rw-r--r--plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeExporter.java55
-rw-r--r--plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeImporter.java50
-rw-r--r--plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeImporterWithMessages.java47
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/db/migrations/SelectImpl.java7
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java1
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java73
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileName.java4
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRepositoryExporter.java139
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResult.java8
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileService.java16
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java5
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivatorContextFactory.java14
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileExportersTest.java130
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRepositoryExporterTest.java224
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileServiceMediumTest.java89
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java23
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/components_controller.rb6
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb12
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb9
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/views/profiles/_create_form.html.erb2
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb6
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/db/migrate/602_remove_duplication_in_group_roles.rb44
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/lib/need_authentication.rb70
-rw-r--r--sonar-application/src/main/assembly/conf/sonar.properties2
-rw-r--r--sonar-application/src/main/java/org/sonar/application/JdbcSettings.java1
-rw-r--r--sonar-application/src/test/java/org/sonar/application/JdbcSettingsTest.java4
-rw-r--r--sonar-core/src/main/resources/org/sonar/core/permission/PermissionTemplateMapper.xml1
-rw-r--r--sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql1
-rw-r--r--sonar-core/src/test/java/org/sonar/core/permission/UserWithPermissionTemplateDaoTest.java21
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/permission/UserWithPermissionTemplateDaoTest/select_only_enable_users.xml14
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/permission/UserWithPermissionTemplateDaoTest/users_with_permissions.xml6
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/permission/UserWithPermissionTemplateDaoTest/users_with_permissions_should_be_sorted_by_user_name.xml6
33 files changed, 652 insertions, 457 deletions
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java
index 148a6df0b7c..d28dc487dec 100644
--- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java
+++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java
@@ -20,17 +20,8 @@
package org.sonar.xoo;
import org.sonar.api.SonarPlugin;
-import org.sonar.xoo.lang.CoveragePerTestSensor;
-import org.sonar.xoo.lang.MeasureSensor;
-import org.sonar.xoo.lang.SymbolReferencesSensor;
-import org.sonar.xoo.lang.SyntaxHighlightingSensor;
-import org.sonar.xoo.lang.TestCaseSensor;
-import org.sonar.xoo.lang.XooTokenizerSensor;
-import org.sonar.xoo.rule.CreateIssueByInternalKeySensor;
-import org.sonar.xoo.rule.OneIssueOnDirPerFileSensor;
-import org.sonar.xoo.rule.OneIssuePerLineSensor;
-import org.sonar.xoo.rule.XooQualityProfile;
-import org.sonar.xoo.rule.XooRulesDefinition;
+import org.sonar.xoo.lang.*;
+import org.sonar.xoo.rule.*;
import org.sonar.xoo.scm.XooBlameCommand;
import org.sonar.xoo.scm.XooScmProvider;
@@ -52,6 +43,10 @@ public class XooPlugin extends SonarPlugin {
XooRulesDefinition.class,
XooQualityProfile.class,
+ XooFakeExporter.class,
+ XooFakeImporter.class,
+ XooFakeImporterWithMessages.class,
+
// SCM
XooScmProvider.class,
XooBlameCommand.class,
@@ -67,7 +62,7 @@ public class XooPlugin extends SonarPlugin {
OneIssuePerLineSensor.class,
OneIssueOnDirPerFileSensor.class,
CreateIssueByInternalKeySensor.class
- );
+ );
}
}
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeExporter.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeExporter.java
new file mode 100644
index 00000000000..b8375db463f
--- /dev/null
+++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeExporter.java
@@ -0,0 +1,55 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.xoo.rule;
+
+import org.sonar.api.profiles.ProfileExporter;
+import org.sonar.api.profiles.RulesProfile;
+import org.sonar.xoo.Xoo;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Fake exporter just for test
+ */
+public class XooFakeExporter extends ProfileExporter {
+ public XooFakeExporter() {
+ super("XooFakeExporter", "Xoo Fake Exporter");
+ }
+
+ @Override
+ public String[] getSupportedLanguages() {
+ return new String[]{Xoo.KEY};
+ }
+
+ @Override
+ public String getMimeType() {
+ return "plain/custom";
+ }
+
+ @Override
+ public void exportProfile(RulesProfile profile, Writer writer) {
+ try {
+ writer.write("xoo -> " + profile.getName() + " -> " + profile.getActiveRules().size());
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+}
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeImporter.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeImporter.java
new file mode 100644
index 00000000000..867c11100dc
--- /dev/null
+++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeImporter.java
@@ -0,0 +1,50 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.xoo.rule;
+
+import org.sonar.api.profiles.ProfileImporter;
+import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RulePriority;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.xoo.Xoo;
+
+import java.io.Reader;
+
+/**
+ * Fake importer just for test, it will NOT take into account the given file but will create some hard-coded rules
+ */
+public class XooFakeImporter extends ProfileImporter {
+ public XooFakeImporter() {
+ super("XooProfileImporter", "Xoo Profile Importer");
+ }
+
+ @Override
+ public String[] getSupportedLanguages() {
+ return new String[] {Xoo.KEY};
+ }
+
+ @Override
+ public RulesProfile importProfile(Reader reader, ValidationMessages messages) {
+ RulesProfile rulesProfile = RulesProfile.create();
+ rulesProfile.activateRule(Rule.create(XooRulesDefinition.XOO_REPOSITORY, "x1"), RulePriority.CRITICAL);
+ return rulesProfile;
+ }
+}
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeImporterWithMessages.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeImporterWithMessages.java
new file mode 100644
index 00000000000..a11e3a2cca0
--- /dev/null
+++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeImporterWithMessages.java
@@ -0,0 +1,47 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.xoo.rule;
+
+import org.sonar.api.profiles.ProfileImporter;
+import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.utils.ValidationMessages;
+
+import java.io.Reader;
+
+/**
+ * Fake importer just for test, it will NOT take into account the given file but will display some info and warning messages
+ */
+public class XooFakeImporterWithMessages extends ProfileImporter {
+ public XooFakeImporterWithMessages() {
+ super("XooFakeImporterWithMessages", "Xoo Profile Importer With Messages");
+ }
+
+ @Override
+ public String[] getSupportedLanguages() {
+ return new String[] {};
+ }
+
+ @Override
+ public RulesProfile importProfile(Reader reader, ValidationMessages messages) {
+ messages.addWarningText("a warning");
+ messages.addInfoText("an info");
+ return RulesProfile.create();
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/SelectImpl.java b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/SelectImpl.java
index b49fc88edee..d0724aaa813 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/SelectImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/SelectImpl.java
@@ -21,7 +21,6 @@ package org.sonar.server.db.migrations;
import org.apache.commons.dbutils.DbUtils;
import org.sonar.core.persistence.Database;
-import org.sonar.core.persistence.dialect.MySql;
import java.sql.Connection;
import java.sql.PreparedStatement;
@@ -83,11 +82,7 @@ class SelectImpl extends BaseSqlStatement<Select> implements Select {
static SelectImpl create(Database db, Connection connection, String sql) throws SQLException {
PreparedStatement pstmt = connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
- if (db.getDialect().getId().equals(MySql.ID)) {
- pstmt.setFetchSize(Integer.MIN_VALUE);
- } else {
- pstmt.setFetchSize(1000);
- }
+ pstmt.setFetchSize(1000);
return new SelectImpl(pstmt);
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
index 2a917a3c4ad..381586b49fd 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
@@ -357,7 +357,6 @@ class ServerComponents {
pico.addSingleton(QProfileLookup.class);
pico.addSingleton(QProfileProjectOperations.class);
pico.addSingleton(QProfileProjectLookup.class);
- pico.addSingleton(QProfileRepositoryExporter.class);
pico.addSingleton(BuiltInProfiles.class);
pico.addSingleton(QProfileRestoreBuiltInAction.class);
pico.addSingleton(QProfilesWs.class);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java
index d8a224f8957..0651346fcd4 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java
@@ -20,15 +20,22 @@
package org.sonar.server.qualityprofile;
import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.StringUtils;
import org.sonar.api.ServerComponent;
import org.sonar.api.profiles.ProfileExporter;
+import org.sonar.api.profiles.ProfileImporter;
import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.rules.ActiveRuleParam;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RulePriority;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.core.persistence.DbSession;
import org.sonar.core.qualityprofile.db.QualityProfileDto;
+import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
+import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
@@ -39,16 +46,20 @@ public class QProfileExporters implements ServerComponent {
private final QProfileLoader loader;
private final RuleFinder ruleFinder;
+ private final RuleActivator ruleActivator;
private final ProfileExporter[] exporters;
+ private final ProfileImporter[] importers;
- public QProfileExporters(QProfileLoader loader, RuleFinder ruleFinder, ProfileExporter[] exporters) {
+ public QProfileExporters(QProfileLoader loader, RuleFinder ruleFinder, RuleActivator ruleActivator, ProfileExporter[] exporters, ProfileImporter[] importers) {
this.loader = loader;
this.ruleFinder = ruleFinder;
+ this.ruleActivator = ruleActivator;
this.exporters = exporters;
+ this.importers = importers;
}
- public QProfileExporters(QProfileLoader loader, RuleFinder ruleFinder) {
- this(loader, ruleFinder, new ProfileExporter[0]);
+ public QProfileExporters(QProfileLoader loader, RuleFinder ruleFinder, RuleActivator ruleActivator) {
+ this(loader, ruleFinder, ruleActivator, new ProfileExporter[0], new ProfileImporter[0]);
}
public List<ProfileExporter> exportersForLanguage(String language) {
@@ -104,4 +115,60 @@ public class QProfileExporters implements ServerComponent {
}
throw new NotFoundException("Unknown quality profile exporter: " + exporterKey);
}
+
+ /**
+ * Used by rails
+ */
+ public List<ProfileImporter> findProfileImportersForLanguage(String language) {
+ List<ProfileImporter> result = new ArrayList<ProfileImporter>();
+ for (ProfileImporter importer : importers) {
+ if (importer.getSupportedLanguages() == null || importer.getSupportedLanguages().length == 0 || ArrayUtils.contains(importer.getSupportedLanguages(), language)) {
+ result.add(importer);
+ }
+ }
+ return result;
+ }
+
+ public QProfileResult importXml(QualityProfileDto profileDto, String importerKey, String xml, DbSession dbSession) {
+ QProfileResult result = new QProfileResult();
+ ValidationMessages messages = ValidationMessages.create();
+ ProfileImporter importer = getProfileImporter(importerKey);
+ RulesProfile rulesProfile = importer.importProfile(new StringReader(xml), messages);
+ importProfile(profileDto, rulesProfile, dbSession);
+ processValidationMessages(messages, result);
+ return result;
+ }
+
+ private void importProfile(QualityProfileDto profileDto, RulesProfile rulesProfile, DbSession dbSession) {
+ for (org.sonar.api.rules.ActiveRule activeRule : rulesProfile.getActiveRules()) {
+ ruleActivator.activate(dbSession, toRuleActivation(activeRule), profileDto);
+ }
+ }
+
+ private ProfileImporter getProfileImporter(String importerKey) {
+ for (ProfileImporter importer : importers) {
+ if (StringUtils.equals(importerKey, importer.getKey())) {
+ return importer;
+ }
+ }
+ throw new BadRequestException("No such importer : " + importerKey);
+ }
+
+ private void processValidationMessages(ValidationMessages messages, QProfileResult result) {
+ if (!messages.getErrors().isEmpty()) {
+ throw new BadRequestException(messages);
+ }
+ result.addWarnings(messages.getWarnings());
+ result.addInfos(messages.getInfos());
+ }
+
+ private RuleActivation toRuleActivation(org.sonar.api.rules.ActiveRule activeRule) {
+ RuleActivation ruleActivation = new RuleActivation(activeRule.getRule().ruleKey());
+ ruleActivation.setSeverity(activeRule.getSeverity().name());
+ for (ActiveRuleParam activeRuleParam : activeRule.getActiveRuleParams()) {
+ ruleActivation.setParameter(activeRuleParam.getKey(), activeRuleParam.getValue());
+ }
+ return ruleActivation;
+ }
+
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileName.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileName.java
index ae09c899cd5..d794058ea97 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileName.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileName.java
@@ -37,6 +37,10 @@ public class QProfileName {
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) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRepositoryExporter.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRepositoryExporter.java
deleted file mode 100644
index 883d05675c7..00000000000
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRepositoryExporter.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.Lists;
-import com.google.common.collect.Multimap;
-import org.apache.commons.lang.ArrayUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.ibatis.session.SqlSession;
-import org.sonar.api.ServerComponent;
-import org.sonar.api.profiles.ProfileImporter;
-import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.rules.ActiveRule;
-import org.sonar.api.rules.ActiveRuleParam;
-import org.sonar.api.rules.RulePriority;
-import org.sonar.api.utils.ValidationMessages;
-import org.sonar.core.qualityprofile.db.ActiveRuleDao;
-import org.sonar.core.qualityprofile.db.ActiveRuleDto;
-import org.sonar.core.qualityprofile.db.ActiveRuleParamDto;
-import org.sonar.server.exceptions.BadRequestException;
-
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-/**
- * Used through ruby code <pre>Internal.profile_exporter</pre>
- */
-public class QProfileRepositoryExporter implements ServerComponent {
-
- private final ActiveRuleDao activeRuleDao;
- private final List<ProfileImporter> importers;
-
- /**
- * Used by pico when no plugin provide profile exporter / importer
- */
- public QProfileRepositoryExporter(ActiveRuleDao activeRuleDao) {
- this(activeRuleDao, Lists.<ProfileImporter>newArrayList());
- }
-
- public QProfileRepositoryExporter(ActiveRuleDao activeRuleDao, List<ProfileImporter> importers) {
- this.activeRuleDao = activeRuleDao;
- this.importers = importers;
- }
-
- public QProfileResult importXml(QProfile profile, String pluginKey, String xml, SqlSession session) {
- QProfileResult result = new QProfileResult();
- ValidationMessages messages = ValidationMessages.create();
- ProfileImporter importer = getProfileImporter(pluginKey);
- RulesProfile rulesProfile = importer.importProfile(new StringReader(xml), messages);
- importProfile(profile.id(), rulesProfile, session);
- processValidationMessages(messages, result);
- return result;
- }
-
- private void importProfile(int profileId, RulesProfile rulesProfile, SqlSession sqlSession) {
- List<ActiveRuleDto> activeRuleDtos = newArrayList();
- Multimap<Integer, ActiveRuleParamDto> paramsByActiveRule = ArrayListMultimap.create();
- for (ActiveRule activeRule : rulesProfile.getActiveRules()) {
- ActiveRuleDto activeRuleDto = toActiveRuleDto(activeRule, profileId);
- activeRuleDao.insert(activeRuleDto, sqlSession);
- activeRuleDtos.add(activeRuleDto);
- for (ActiveRuleParam activeRuleParam : activeRule.getActiveRuleParams()) {
- ActiveRuleParamDto activeRuleParamDto = toActiveRuleParamDto(activeRuleParam, activeRuleDto);
- activeRuleDao.insert(activeRuleParamDto, sqlSession);
- paramsByActiveRule.put(activeRuleDto.getId(), activeRuleParamDto);
- }
- }
- // TODO use RuleActivator to benefit from changelog and preview cache cleanup
- }
-
- private void processValidationMessages(ValidationMessages messages, QProfileResult result) {
- if (!messages.getErrors().isEmpty()) {
- throw new BadRequestException(messages);
- }
- result.addWarnings(messages.getWarnings());
- result.addInfos(messages.getInfos());
- }
-
- private ActiveRuleDto toActiveRuleDto(ActiveRule activeRule, int profileId) {
- return new ActiveRuleDto()
- .setProfileId(profileId)
- .setRuleId(activeRule.getRule().getId())
- .setSeverity(toSeverityLevel(activeRule.getSeverity()));
- }
-
- private String toSeverityLevel(RulePriority rulePriority) {
- return rulePriority.name();
- }
-
- private ActiveRuleParamDto toActiveRuleParamDto(ActiveRuleParam activeRuleParam, ActiveRuleDto activeRuleDto) {
- return new ActiveRuleParamDto()
- .setActiveRuleId(activeRuleDto.getId())
- .setRulesParameterId(activeRuleParam.getRuleParam().getId())
- .setKey(activeRuleParam.getKey())
- .setValue(activeRuleParam.getValue());
- }
-
- private ProfileImporter getProfileImporter(String importerKey) {
- for (ProfileImporter importer : importers) {
- if (StringUtils.equals(importerKey, importer.getKey())) {
- return importer;
- }
- }
- throw new BadRequestException("No such importer : " + importerKey);
- }
-
- public List<ProfileImporter> getProfileImportersForLanguage(String language) {
- List<ProfileImporter> result = new ArrayList<ProfileImporter>();
- for (ProfileImporter importer : importers) {
- if (importer.getSupportedLanguages() == null || importer.getSupportedLanguages().length == 0 || ArrayUtils.contains(importer.getSupportedLanguages(), language)) {
- result.add(importer);
- }
- }
- return result;
- }
-
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResult.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResult.java
index 81fbb63faa3..5873862f58d 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResult.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResult.java
@@ -20,6 +20,8 @@
package org.sonar.server.qualityprofile;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
+
import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
@@ -29,7 +31,7 @@ public class QProfileResult {
private List<String> warnings;
private List<String> infos;
- private QProfile profile;
+ private QualityProfileDto profile;
public QProfileResult() {
warnings = newArrayList();
@@ -54,11 +56,11 @@ public class QProfileResult {
return this;
}
- public QProfile profile() {
+ public QualityProfileDto profile() {
return profile;
}
- public QProfileResult setProfile(QProfile profile) {
+ public QProfileResult setProfile(QualityProfileDto profile) {
this.profile = profile;
return this;
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileService.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileService.java
index 43a10b1ed6b..0e0a7acb4ac 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileService.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileService.java
@@ -48,6 +48,7 @@ import java.io.StringWriter;
import java.io.Writer;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
public class QProfileService implements ServerComponent {
@@ -58,9 +59,10 @@ public class QProfileService implements ServerComponent {
private final QProfileBackuper backuper;
private final QProfileCopier copier;
private final QProfileReset reset;
+ private final QProfileExporters exporters;
public QProfileService(DbClient db, IndexClient index, RuleActivator ruleActivator, QProfileFactory factory,
- QProfileBackuper backuper, QProfileCopier copier, QProfileReset reset) {
+ QProfileBackuper backuper, QProfileCopier copier, QProfileReset reset, QProfileExporters exporters) {
this.db = db;
this.index = index;
this.ruleActivator = ruleActivator;
@@ -68,15 +70,23 @@ public class QProfileService implements ServerComponent {
this.backuper = backuper;
this.copier = copier;
this.reset = reset;
+ this.exporters = exporters;
}
- public QualityProfileDto create(QProfileName name) {
+ public QProfileResult create(QProfileName name, @Nullable Map<String, String> xmlQProfilesByPlugin) {
verifyAdminPermission();
DbSession dbSession = db.openSession(false);
try {
+ QProfileResult result = new QProfileResult();
QualityProfileDto profile = factory.create(dbSession, name);
+ result.setProfile(profile);
+ if (xmlQProfilesByPlugin != null) {
+ for (Map.Entry<String, String> entry : xmlQProfilesByPlugin.entrySet()) {
+ result.add(exporters.importXml(profile, entry.getKey(), entry.getValue(), dbSession));
+ }
+ }
dbSession.commit();
- return profile;
+ return result;
} finally {
dbSession.close();
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java
index 6bf1db54f80..89e8e6631a6 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java
@@ -88,6 +88,11 @@ public class RuleActivator implements ServerComponent {
return doActivate(dbSession, activation, context);
}
+ List<ActiveRuleChange> activate(DbSession dbSession, RuleActivation activation, QualityProfileDto profileDto) {
+ RuleActivatorContext context = contextFactory.create(profileDto, activation.getRuleKey(), dbSession);
+ return doActivate(dbSession, activation, context);
+ }
+
private List<ActiveRuleChange> doActivate(DbSession dbSession, RuleActivation activation, RuleActivatorContext context) {
context.verifyForActivation();
List<ActiveRuleChange> changes = Lists.newArrayList();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivatorContextFactory.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivatorContextFactory.java
index 1854942476b..184d3fdf187 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivatorContextFactory.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivatorContextFactory.java
@@ -47,7 +47,7 @@ public class RuleActivatorContextFactory implements ServerComponent {
throw new BadRequestException("Quality profile not found: " + profileKey);
}
context.setProfile(profile);
- return create(profile, ruleKey, session, context);
+ return create(ruleKey, session, context);
}
RuleActivatorContext create(QProfileName profileName, RuleKey ruleKey, DbSession session) {
@@ -57,13 +57,17 @@ public class RuleActivatorContextFactory implements ServerComponent {
throw new BadRequestException("Quality profile not found: " + profileName);
}
context.setProfile(profile);
- return create(profile, ruleKey, session, context);
+ return create(ruleKey, session, context);
}
- private RuleActivatorContext create(QualityProfileDto profile, RuleKey ruleKey, DbSession session, RuleActivatorContext context) {
+ RuleActivatorContext create(QualityProfileDto profile, RuleKey ruleKey, DbSession session) {
+ return create(ruleKey, session, new RuleActivatorContext().setProfile(profile));
+ }
+
+ private RuleActivatorContext create(RuleKey ruleKey, DbSession session, RuleActivatorContext context) {
initRule(ruleKey, context, session);
- initActiveRules(profile.getKey(), ruleKey, context, session, false);
- String parentKee = profile.getParentKee();
+ initActiveRules(context.profile().getKey(), ruleKey, context, session, false);
+ String parentKee = context.profile().getParentKee();
if (parentKee != null) {
initActiveRules(parentKee, ruleKey, context, session, true);
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileExportersTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileExportersTest.java
index fd8a87a9dd2..8c0f19312c8 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileExportersTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileExportersTest.java
@@ -19,23 +19,32 @@
*/
package org.sonar.server.qualityprofile;
+import org.junit.After;
+import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.sonar.api.profiles.ProfileDefinition;
import org.sonar.api.profiles.ProfileExporter;
+import org.sonar.api.profiles.ProfileImporter;
import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.api.utils.ValidationMessages;
+import org.sonar.core.persistence.DbSession;
import org.sonar.core.qualityprofile.db.QualityProfileDto;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.tester.ServerTester;
import java.io.IOException;
+import java.io.Reader;
import java.io.Writer;
+import java.util.List;
import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;
@@ -45,9 +54,26 @@ public class QProfileExportersTest {
@ClassRule
public static ServerTester tester = new ServerTester().addXoo().addComponents(
XooRulesDefinition.class, XooProfileDefinition.class,
- XooExporter.class, StandardExporter.class);
+ XooExporter.class, StandardExporter.class,
+ XooProfileImporter.class, XooProfileImporterWithMessages.class, XooProfileImporterWithError.class);
- QProfileExporters exporters = tester.get(QProfileExporters.class);
+ DbClient db;
+ DbSession dbSession;
+ QProfileExporters exporters;
+ QProfileLoader loader;
+
+ @Before
+ public void before() {
+ db = tester.get(DbClient.class);
+ dbSession = db.openSession(false);
+ exporters = tester.get(QProfileExporters.class);
+ loader = tester.get(QProfileLoader.class);
+ }
+
+ @After
+ public void after() throws Exception {
+ dbSession.close();
+ }
@Test
public void exportersForLanguage() throws Exception {
@@ -92,6 +118,58 @@ public class QProfileExportersTest {
}
}
+ @Test
+ public void profile_importers_for_language() throws Exception {
+ assertThat(exporters.findProfileImportersForLanguage("xoo")).hasSize(3);
+ }
+
+ @Test
+ public void import_xml() throws Exception {
+ QualityProfileDto profileDto = QProfileTesting.newDto(QProfileName.createFor("xoo", "import_xml"), "import_xml");
+ db.qualityProfileDao().insert(dbSession, profileDto);
+ dbSession.commit();
+
+ assertThat(loader.findActiveRulesByProfile(profileDto.getKey())).isEmpty();
+
+ exporters.importXml(profileDto, "XooProfileImporter", "<xml/>", dbSession);
+ dbSession.commit();
+
+ List<ActiveRule> activeRules = loader.findActiveRulesByProfile(profileDto.getKey());
+ assertThat(activeRules).hasSize(1);
+ ActiveRule activeRule = activeRules.get(0);
+ assertThat(activeRule.key().ruleKey()).isEqualTo(RuleKey.of("xoo", "R1"));
+ assertThat(activeRule.severity()).isEqualTo(Severity.CRITICAL);
+ }
+
+ @Test
+ public void import_xml_return_messages() throws Exception {
+ QProfileResult result = exporters.importXml(QProfileTesting.newXooP1(), "XooProfileImporterWithMessages", "<xml/>", dbSession);
+ dbSession.commit();
+
+ assertThat(result.infos()).containsOnly("an info");
+ assertThat(result.warnings()).containsOnly("a warning");
+ }
+
+ @Test
+ public void fail_to_import_xml_when_error_in_importer() throws Exception {
+ try {
+ exporters.importXml(QProfileTesting.newXooP1(), "XooProfileImporterWithError", "<xml/>", dbSession);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("error!");
+ }
+ }
+
+ @Test
+ public void fail_to_import_xml_on_unknown_importer() throws Exception {
+ try {
+ exporters.importXml(QProfileTesting.newXooP1(), "Unknown", "<xml/>", dbSession);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("No such importer : Unknown");
+ }
+ }
+
public static class XooExporter extends ProfileExporter {
public XooExporter() {
super("xootool", "Xoo Tool");
@@ -157,4 +235,52 @@ public class QProfileExportersTest {
}
}
+ public static class XooProfileImporter extends ProfileImporter {
+ public XooProfileImporter() {
+ super("XooProfileImporter", "Xoo Profile Importer");
+ }
+
+ @Override
+ public String[] getSupportedLanguages() {
+ return new String[] {"xoo"};
+ }
+
+ @Override
+ public RulesProfile importProfile(Reader reader, ValidationMessages messages) {
+ RulesProfile rulesProfile = RulesProfile.create();
+ rulesProfile.activateRule(Rule.create("xoo", "R1"), RulePriority.CRITICAL);
+ return rulesProfile;
+ }
+ }
+
+ public static class XooProfileImporterWithMessages extends ProfileImporter {
+ public XooProfileImporterWithMessages() {
+ super("XooProfileImporterWithMessages", "Xoo Profile Importer With Message");
+ }
+
+ @Override
+ public String[] getSupportedLanguages() {
+ return new String[] {};
+ }
+
+ @Override
+ public RulesProfile importProfile(Reader reader, ValidationMessages messages) {
+ messages.addWarningText("a warning");
+ messages.addInfoText("an info");
+ return RulesProfile.create();
+ }
+ }
+
+ public static class XooProfileImporterWithError extends ProfileImporter {
+ public XooProfileImporterWithError() {
+ super("XooProfileImporterWithError", "Xoo Profile Importer With Error");
+ }
+
+ @Override
+ public RulesProfile importProfile(Reader reader, ValidationMessages messages) {
+ messages.addErrorText("error!");
+ return RulesProfile.create();
+ }
+ }
+
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRepositoryExporterTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRepositoryExporterTest.java
deleted file mode 100644
index cdbc9cad7aa..00000000000
--- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRepositoryExporterTest.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.apache.ibatis.session.SqlSession;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.mockito.stubbing.Answer;
-import org.sonar.api.database.DatabaseSession;
-import org.sonar.api.profiles.ProfileImporter;
-import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.rule.Severity;
-import org.sonar.api.rules.ActiveRule;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RulePriority;
-import org.sonar.api.utils.ValidationMessages;
-import org.sonar.core.qualityprofile.db.ActiveRuleDao;
-import org.sonar.core.qualityprofile.db.ActiveRuleDto;
-import org.sonar.core.qualityprofile.db.ActiveRuleParamDto;
-import org.sonar.server.exceptions.BadRequestException;
-
-import java.io.Reader;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class QProfileRepositoryExporterTest {
-
- @Mock
- SqlSession session;
-
- @Mock
- DatabaseSession hibernateSession;
-
- @Mock
- ActiveRuleDao activeRuleDao;
-
- List<ProfileImporter> importers = newArrayList();
-
- Integer currentId = 1;
-
- QProfileRepositoryExporter operations;
-
- @Before
- public void setUp() throws Exception {
- // Associate an id when inserting an object to simulate the db id generator
- doAnswer(new Answer() {
- public Object answer(InvocationOnMock invocation) {
- Object[] args = invocation.getArguments();
- ActiveRuleDto dto = (ActiveRuleDto) args[0];
- dto.setId(currentId++);
- return null;
- }
- }).when(activeRuleDao).insert(any(ActiveRuleDto.class), any(SqlSession.class));
-
- operations = new QProfileRepositoryExporter(activeRuleDao, importers);
- }
-
- @Test
- public void import_from_xml_plugin() throws Exception {
- RulesProfile profile = RulesProfile.create("Default", "java");
- Rule rule = Rule.create("pmd", "rule1");
- rule.createParameter("max");
- rule.setId(10);
- ActiveRule activeRule = profile.activateRule(rule, RulePriority.BLOCKER);
- activeRule.setParameter("max", "10");
-
- ProfileImporter importer = mock(ProfileImporter.class);
- when(importer.getKey()).thenReturn("pmd");
- when(importer.importProfile(any(Reader.class), any(ValidationMessages.class))).thenReturn(profile);
- importers.add(importer);
-
- operations.importXml(new QProfile().setId(1), "pmd", "<xml/>", session);
-
- verify(importer).importProfile(any(Reader.class), any(ValidationMessages.class));
-
- ArgumentCaptor<ActiveRuleDto> activeRuleArgument = ArgumentCaptor.forClass(ActiveRuleDto.class);
- verify(activeRuleDao).insert(activeRuleArgument.capture(), eq(session));
- assertThat(activeRuleArgument.getValue().getRuleId()).isEqualTo(10);
- assertThat(activeRuleArgument.getValue().getSeverityString()).isEqualTo(Severity.BLOCKER);
-
- ArgumentCaptor<ActiveRuleParamDto> activeRuleParamArgument = ArgumentCaptor.forClass(ActiveRuleParamDto.class);
- verify(activeRuleDao).insert(activeRuleParamArgument.capture(), eq(session));
- assertThat(activeRuleParamArgument.getValue().getKey()).isEqualTo("max");
- assertThat(activeRuleParamArgument.getValue().getValue()).isEqualTo("10");
- }
-
- @Test
- public void import_from_xml_plugin_add_infos_and_warnings() throws Exception {
- final RulesProfile profile = RulesProfile.create("Default", "java");
- Rule rule = Rule.create("pmd", "rule1");
- rule.createParameter("max");
- rule.setId(10);
- ActiveRule activeRule = profile.activateRule(rule, RulePriority.BLOCKER);
- activeRule.setParameter("max", "10");
-
- ProfileImporter importer = mock(ProfileImporter.class);
- when(importer.getKey()).thenReturn("pmd");
- doAnswer(new Answer() {
- public Object answer(InvocationOnMock invocation) {
- Object[] args = invocation.getArguments();
- ValidationMessages validationMessages = (ValidationMessages) args[1];
- validationMessages.addInfoText("an info message");
- validationMessages.addWarningText("a warning message");
- return profile;
- }
- }).when(importer).importProfile(any(Reader.class), any(ValidationMessages.class));
- importers.add(importer);
-
- QProfileResult result = operations.importXml(new QProfile().setId(1), "pmd", "<xml/>", session);
- ;
- assertThat(result.infos()).hasSize(1);
- assertThat(result.warnings()).hasSize(1);
- }
-
- @Test
- public void fail_to_import_profile_from_xml_plugin_if_error() throws Exception {
- final RulesProfile profile = RulesProfile.create("Default", "java");
- Rule rule = Rule.create("pmd", "rule1");
- rule.createParameter("max");
- rule.setId(10);
- ActiveRule activeRule = profile.activateRule(rule, RulePriority.BLOCKER);
- activeRule.setParameter("max", "10");
-
- ProfileImporter importer = mock(ProfileImporter.class);
- when(importer.getKey()).thenReturn("pmd");
- importers.add(importer);
-
- doAnswer(new Answer() {
- public Object answer(InvocationOnMock invocation) {
- Object[] args = invocation.getArguments();
- ValidationMessages validationMessages = (ValidationMessages) args[1];
- validationMessages.addErrorText("error!");
- return profile;
- }
- }).when(importer).importProfile(any(Reader.class), any(ValidationMessages.class));
-
- try {
- operations.importXml(new QProfile().setId(1), "pmd", "<xml/>", session);
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(BadRequestException.class);
- }
- }
-
- @Test
- public void fail_to_import_profile_when_missing_importer() throws Exception {
- final RulesProfile profile = RulesProfile.create("Default", "java");
- Rule rule = Rule.create("pmd", "rule1");
- rule.createParameter("max");
- rule.setId(10);
- ActiveRule activeRule = profile.activateRule(rule, RulePriority.BLOCKER);
- activeRule.setParameter("max", "10");
-
- ProfileImporter importer = mock(ProfileImporter.class);
- when(importer.getKey()).thenReturn("pmd");
- importers.add(importer);
-
- when(importer.importProfile(any(Reader.class), any(ValidationMessages.class))).thenReturn(profile);
-
- try {
- operations.importXml(new QProfile().setId(1), "unknown", "<xml/>", session);
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("No such importer : unknown");
- }
- verify(importer, never()).importProfile(any(Reader.class), any(ValidationMessages.class));
- }
-
- @Test
- public void get_profile_importers_for_language() throws Exception {
- // 2 importers not declaring supported languages -> match all languages -> to be include in result
- ProfileImporter importersWithEmptySupportedLanguagesList = mock(ProfileImporter.class);
- when(importersWithEmptySupportedLanguagesList.getSupportedLanguages()).thenReturn(new String[] {});
- importers.add(importersWithEmptySupportedLanguagesList);
- importers.add(mock(ProfileImporter.class));
-
- // 1 importers supporting the java language -> to be include in result
- ProfileImporter importerSupportingJava = mock(ProfileImporter.class);
- when(importerSupportingJava.getSupportedLanguages()).thenReturn(new String[] {"java"});
- importers.add(importerSupportingJava);
-
- // 1 importers supporting another language -> not to be include in result
- ProfileImporter importerSupportingAnotherLanguage = mock(ProfileImporter.class);
- when(importerSupportingAnotherLanguage.getSupportedLanguages()).thenReturn(new String[] {"js"});
- importers.add(importerSupportingAnotherLanguage);
-
- assertThat(operations.getProfileImportersForLanguage("java")).hasSize(3);
- }
-
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileServiceMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileServiceMediumTest.java
index b39658b17f1..73387e8481a 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileServiceMediumTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileServiceMediumTest.java
@@ -19,19 +19,27 @@
*/
package org.sonar.server.qualityprofile;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
+import org.sonar.api.profiles.ProfileExporter;
+import org.sonar.api.profiles.ProfileImporter;
+import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RulePriority;
+import org.sonar.api.utils.ValidationMessages;
import org.sonar.core.activity.Activity;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.qualityprofile.db.ActiveRuleKey;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
import org.sonar.core.rule.RuleDto;
import org.sonar.core.user.UserDto;
import org.sonar.server.activity.ActivityService;
@@ -44,6 +52,9 @@ import org.sonar.server.search.Result;
import org.sonar.server.tester.ServerTester;
import org.sonar.server.user.MockUserSession;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -55,7 +66,7 @@ import static org.sonar.server.qualityprofile.QProfileTesting.XOO_P2_KEY;
public class QProfileServiceMediumTest {
@ClassRule
- public static ServerTester tester = new ServerTester();
+ public static ServerTester tester = new ServerTester().addComponents(XooProfileImporter.class, XooExporter.class);
DbClient db;
DbSession dbSession;
@@ -88,6 +99,35 @@ public class QProfileServiceMediumTest {
}
@Test
+ public void create_profile() throws Exception {
+ MockUserSession.set().setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN).setLogin("me");
+
+ QualityProfileDto profile = service.create(QProfileName.createFor("xoo", "New Profile"), null).profile();
+
+ assertThat(loader.getByKey(profile.getKey())).isNotNull();
+ assertThat(loader.getByKey(profile.getKey()).getLanguage()).isEqualTo("xoo");
+ assertThat(loader.getByKey(profile.getKey()).getName()).isEqualTo("New Profile");
+ }
+
+ @Test
+ public void create_profile_with_xml() throws Exception {
+ MockUserSession.set().setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN).setLogin("me");
+
+ db.ruleDao().insert(dbSession, RuleTesting.newDto(RuleKey.of("xoo", "R1")).setLanguage("xoo").setSeverity("MINOR"));
+ dbSession.commit();
+
+ QProfileResult result = service.create(QProfileName.createFor("xoo", "New Profile"), ImmutableMap.of("XooProfileImporter", "<xml/>"));
+ QualityProfileDto profile = result.profile();
+
+ assertThat(loader.getByKey(profile.getKey())).isNotNull();
+ assertThat(loader.getByKey(profile.getKey()).getLanguage()).isEqualTo("xoo");
+ assertThat(loader.getByKey(profile.getKey()).getName()).isEqualTo("New Profile");
+
+ List<ActiveRule> activeRules = loader.findActiveRulesByProfile(profile.getKey());
+ assertThat(activeRules).hasSize(1);
+ }
+
+ @Test
public void count_by_all_profiles() throws Exception {
MockUserSession.set().setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN).setLogin("me");
@@ -294,4 +334,51 @@ public class QProfileServiceMediumTest {
assertThat(service.getDefault("xoo").getKey()).isEqualTo(XOO_P1_KEY);
}
+
+ public static class XooExporter extends ProfileExporter {
+ public XooExporter() {
+ super("xootool", "Xoo Tool");
+ }
+
+ @Override
+ public String[] getSupportedLanguages() {
+ return new String[]{"xoo"};
+ }
+
+ @Override
+ public String getMimeType() {
+ return "plain/custom";
+ }
+
+ @Override
+ public void exportProfile(RulesProfile profile, Writer writer) {
+ try {
+ writer.write("xoo -> " + profile.getName() + " -> " + profile.getActiveRules().size());
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+ public static class XooProfileImporter extends ProfileImporter {
+ public XooProfileImporter() {
+ super("XooProfileImporter", "Xoo Profile Importer");
+ }
+
+ @Override
+ public String[] getSupportedLanguages() {
+ return new String[]{"xoo"};
+ }
+
+ @Override
+ public RulesProfile importProfile(Reader reader, ValidationMessages messages) {
+ RulesProfile rulesProfile = RulesProfile.create();
+ Rule rule = Rule.create("xoo", "R1");
+ rule.createParameter("acceptWhitespace");
+ org.sonar.api.rules.ActiveRule activeRule = rulesProfile.activateRule(rule, RulePriority.CRITICAL);
+ activeRule.setParameter("acceptWhitespace", "true");
+ return rulesProfile;
+ }
+ }
+
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java
index ae5dc30e6ce..34e453b1f2d 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java
@@ -32,6 +32,7 @@ import org.sonar.core.persistence.DbSession;
import org.sonar.core.qualityprofile.db.ActiveRuleDto;
import org.sonar.core.qualityprofile.db.ActiveRuleKey;
import org.sonar.core.qualityprofile.db.ActiveRuleParamDto;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
import org.sonar.core.rule.RuleDto;
import org.sonar.core.rule.RuleParamDto;
import org.sonar.server.db.DbClient;
@@ -69,6 +70,8 @@ public class RuleActivatorMediumTest {
RuleActivator ruleActivator;
ActiveRuleIndex index;
+ QualityProfileDto profileDto;
+
@Before
public void before() {
tester.clearDbAndIndexes();
@@ -100,7 +103,8 @@ public class RuleActivatorMediumTest {
.setName("format").setDefaultValue("txt").setType(RuleParamType.STRING.type()));
// create pre-defined profile P1
- db.qualityProfileDao().insert(dbSession, QProfileTesting.newXooP1());
+ profileDto = QProfileTesting.newXooP1();
+ db.qualityProfileDao().insert(dbSession, profileDto);
dbSession.commit();
dbSession.clearCache();
}
@@ -128,6 +132,23 @@ public class RuleActivatorMediumTest {
}
@Test
+ public void activate_with_profile_dto() throws Exception {
+ RuleActivation activation = new RuleActivation(RuleTesting.XOO_X1);
+ activation.setSeverity(Severity.BLOCKER);
+ activation.setParameter("max", "7");
+ activation.setParameter("min", "3");
+ List<ActiveRuleChange> changes = ruleActivator.activate(dbSession, activation, profileDto);
+ dbSession.commit();
+ dbSession.clearCache();
+
+ assertThat(countActiveRules(XOO_P1_KEY)).isEqualTo(1);
+ verifyHasActiveRule(ActiveRuleKey.of(XOO_P1_KEY, RuleTesting.XOO_X1), Severity.BLOCKER, null,
+ ImmutableMap.of("max", "7", "min", "3"));
+ assertThat(changes).hasSize(1);
+ assertThat(changes.get(0).getType()).isEqualTo(ActiveRuleChange.Type.ACTIVATED);
+ }
+
+ @Test
public void activate_with_default_severity_and_parameter() throws Exception {
activate(new RuleActivation(RuleTesting.XOO_X1), XOO_P1_KEY);
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/components_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/components_controller.rb
index a080bc1881d..410d59f601f 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/components_controller.rb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/components_controller.rb
@@ -27,9 +27,13 @@ class Api::ComponentsController < Api::ApiController
search = params[:s]
bad_request("Minimum search is #{ResourceIndex::MIN_SEARCH_SIZE} characters") if search.empty? || search.to_s.size<ResourceIndex::MIN_SEARCH_SIZE
+ # SONAR-5198 Escape '_' on Oracle and MsSQL
+ dialect = java_facade.getDatabase().getDialect().getId()
+ additional_escape = dialect == 'oracle' || dialect == 'mssql' ? "ESCAPE '\\'" : ''
+
key = escape_like(search).downcase
results = ResourceIndex.all(:select => 'distinct(resource_id),root_project_id,qualifier,name_size', # optimization to not load unused columns like 'kee'
- :conditions => ['kee like ?', key + '%'],
+ :conditions => ['kee like ? ' + additional_escape, key + '%'],
:order => 'name_size')
results = select_authorized(:user, results)
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb
index 9f1be3c76b2..887e8e63797 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb
@@ -170,7 +170,7 @@ class IssuesController < ApplicationController
new_params = params.clone
new_params.delete('controller')
new_params.delete('action')
- translate_unassigned(new_params)
+ new_params
end
def init_params
@@ -181,16 +181,6 @@ class IssuesController < ApplicationController
Internal.issues.sanitizeFilterQuery(params).to_hash
end
- def translate_unassigned(issues_query_params)
- if issues_query_params.has_key?(:assignees) && issues_query_params[:assignees] == '<unassigned>'
- issues_query_params.delete(:assignees)
- issues_query_params[:assigned] = false
- else
- issues_query_params[:assigned] = nil
- end
- issues_query_params
- end
-
def issues_query_params_from_filter(filter)
Internal.issues.deserializeFilterQuery(filter).to_hash
end
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb
index b6a5ba9f4e2..6956a1287eb 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb
@@ -71,10 +71,9 @@ class ProfilesController < ApplicationController
end
end
profile_name = Java::OrgSonarServerQualityprofile::QProfileName.new(params[:language], params[:name])
- Internal.qprofile_service.create(profile_name)
- # TODO use files_by_key
- #flash[:notice] = message('quality_profiles.profile_x_created', :params => result.profile.name)
- #flash_result(result)
+ result = Internal.qprofile_service.create(profile_name, files_by_key)
+ flash[:notice] = message('quality_profiles.profile_x_created', :params => result.profile().getName())
+ flash_result(result)
end
redirect_to :action => 'index'
end
@@ -530,7 +529,7 @@ class ProfilesController < ApplicationController
def flash_result(result)
# only 4 messages are kept each time to avoid cookie overflow.
unless result.infos.empty?
- flash[:notice] += result.infos.to_a[0...4].join('<br/>')
+ flash[:notice] += '<br/>' + result.infos.to_a[0...4].join('<br/>')
end
unless result.warnings.empty?
flash[:warning] = result.warnings.to_a[0...4].join('<br/>')
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/profiles/_create_form.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/profiles/_create_form.html.erb
index 328e2af6add..a003c054478 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/profiles/_create_form.html.erb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/profiles/_create_form.html.erb
@@ -1,6 +1,6 @@
<%
language = controller.java_facade.getLanguages().find { |l| l.getKey()==language_key }
- importers = Internal.component(Java::OrgSonarServerQualityprofile::QProfileRepositoryExporter.java_class).getProfileImportersForLanguage(language_key)
+ importers = Internal.component(Java::OrgSonarServerQualityprofile::QProfileExporters.java_class).findProfileImportersForLanguage(language_key)
%>
<form id="create-profile-form" action="profiles/create" enctype="multipart/form-data" method="POST">
<fieldset>
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb b/server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb
index 81f897e66a3..62d3e809416 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb
@@ -261,3 +261,9 @@ DatabaseVersion.automatic_setup
# All these changes are prefixed by the comment #sonar
#
#
+
+# Increase size of form parameters
+# See http://jira.codehaus.org/browse/SONAR-5577
+Rack::Utils.key_space_limit = 262144 # 4 times the default size
+
+
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/602_remove_duplication_in_group_roles.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/602_remove_duplication_in_group_roles.rb
new file mode 100644
index 00000000000..168fa378ebb
--- /dev/null
+++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/602_remove_duplication_in_group_roles.rb
@@ -0,0 +1,44 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube 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.
+#
+# SonarQube 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.
+#
+
+#
+# SonarQube 4.5
+# SONAR-4950 Unique constraint cannot be created because it would be on resource_id that is nullable
+#
+class RemoveDuplicationInGroupRoles < ActiveRecord::Migration
+
+ class GroupRole < ActiveRecord::Base
+ end
+
+ def self.up
+ GroupRole.reset_column_information
+
+ duplicated_ids = ActiveRecord::Base.connection.select_rows('select group_id,resource_id,role from group_roles group by group_id,resource_id,role having count(*) > 1')
+ say_with_time "Remove #{duplicated_ids.size} duplicated group roles" do
+ duplicated_ids.each do |fields|
+ rows = GroupRole.find(:all, :conditions => {:group_id => fields[0], :resource_id => fields[1], :role => fields[2]})
+ # delete all rows except the last one
+ rows[0...-1].each do |row|
+ GroupRole.delete(row.id)
+ end
+ end
+ end
+ end
+end
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/lib/need_authentication.rb b/server/sonar-web/src/main/webapp/WEB-INF/lib/need_authentication.rb
index 400ccbad2f1..61b266fc66d 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/lib/need_authentication.rb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/lib/need_authentication.rb
@@ -64,6 +64,10 @@ class PluginRealm
result = nil
if !username.blank? && !password.blank?
user = User.find_active_by_login(username)
+ # SONAR-4950 Use a transaction to prevent multiple insertion of same groups
+ User.transaction do
+ user.save(false)
+ end
result = user if user && user.authenticated?(password)
end
result
@@ -117,40 +121,46 @@ class PluginRealm
def synchronize(username, password, details)
username=details.getName() if username.blank? && details
user = User.find_by_login(username)
- if !user
- # No such user in Sonar database
- return nil if !Api::Utils.java_facade.getSettings().getBoolean('sonar.authenticator.createUsers')
- # Automatically create a user in the sonar db if authentication has been successfully done
- user = User.new(:login => username, :name => username, :email => '')
- if details
- user.name = details.getName()
- user.email = details.getEmail()
- end
- default_group_name = Api::Utils.java_facade.getSettings().getString('sonar.defaultGroup')
- default_group = Group.find_by_name(default_group_name)
- if default_group
- user.groups << default_group
+
+ # SONAR-4950 Use a transaction to prevent multiple insertion of same groups
+ User.transaction do
+ if !user
+ # No such user in Sonar database
+ return nil if !Api::Utils.java_facade.getSettings().getBoolean('sonar.authenticator.createUsers')
+ # Automatically create a user in the sonar db if authentication has been successfully done
+ user = User.new(:login => username, :name => username, :email => '')
+ if details
+ user.name = details.getName()
+ user.email = details.getEmail()
+ end
+ default_group_name = Api::Utils.java_facade.getSettings().getString('sonar.defaultGroup')
+ default_group = Group.find_by_name(default_group_name)
+ if default_group
+ user.groups << default_group
+ else
+ Rails.logger.error("The default user group does not exist: #{default_group_name}. Please check the parameter 'Default user group' in general settings.")
+ end
else
- Rails.logger.error("The default user group does not exist: #{default_group_name}. Please check the parameter 'Default user group' in general settings.")
+ # Existing user
+ if details && Api::Utils.java_facade.getSettings().getBoolean('sonar.security.updateUserAttributes')
+ user.name = details.getName()
+ user.email = details.getEmail()
+ end
end
- else
- # Existing user
- if details && Api::Utils.java_facade.getSettings().getBoolean('sonar.security.updateUserAttributes')
- user.name = details.getName()
- user.email = details.getEmail()
+ if @save_password
+ user.password = password
+ user.password_confirmation = password
end
+
+ # A user that is synchronized with an external system is always set to 'active' (see SONAR-3258 for the deactivation concept)
+ user.active=true
+ # Note that validation disabled
+ user.save(false)
+
+ synchronize_groups(user)
+ user.notify_creation_handlers
+ user
end
- if @save_password
- user.password = password
- user.password_confirmation = password
- end
- synchronize_groups(user)
- # A user that is synchronized with an external system is always set to 'active' (see SONAR-3258 for the deactivation concept)
- user.active=true
- # Note that validation disabled
- user.save(false)
- user.notify_creation_handlers
- user
end
def synchronize_groups(user)
diff --git a/sonar-application/src/main/assembly/conf/sonar.properties b/sonar-application/src/main/assembly/conf/sonar.properties
index b9bee4266e5..0c70358e1c1 100644
--- a/sonar-application/src/main/assembly/conf/sonar.properties
+++ b/sonar-application/src/main/assembly/conf/sonar.properties
@@ -28,7 +28,7 @@
#----- MySQL 5.x
-#sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useCursorFetch=true&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance
+#sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance&useCursorFetch=true
#----- Oracle 10g/11g
diff --git a/sonar-application/src/main/java/org/sonar/application/JdbcSettings.java b/sonar-application/src/main/java/org/sonar/application/JdbcSettings.java
index 4a34e55a642..b2f36dbb6c0 100644
--- a/sonar-application/src/main/java/org/sonar/application/JdbcSettings.java
+++ b/sonar-application/src/main/java/org/sonar/application/JdbcSettings.java
@@ -95,6 +95,7 @@ public class JdbcSettings {
if (Provider.MYSQL.equals(provider)) {
checkRequiredParameter(url, "useUnicode=true");
checkRequiredParameter(url, "characterEncoding=utf8");
+ checkRequiredParameter(url, "useCursorFetch=true");
checkRecommendedParameter(url, "rewriteBatchedStatements=true");
checkRecommendedParameter(url, "useConfigs=maxPerformance");
}
diff --git a/sonar-application/src/test/java/org/sonar/application/JdbcSettingsTest.java b/sonar-application/src/test/java/org/sonar/application/JdbcSettingsTest.java
index 5a2708ab5c8..d6fd2af70e2 100644
--- a/sonar-application/src/test/java/org/sonar/application/JdbcSettingsTest.java
+++ b/sonar-application/src/test/java/org/sonar/application/JdbcSettingsTest.java
@@ -65,11 +65,11 @@ public class JdbcSettingsTest {
// minimal -> ok
settings.checkUrlParameters(JdbcSettings.Provider.MYSQL,
- "jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8");
+ "jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&useCursorFetch=true");
// full -> ok
settings.checkUrlParameters(JdbcSettings.Provider.MYSQL,
- "jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance");
+ "jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance&useCursorFetch=true");
// missing required -> ko
try {
diff --git a/sonar-core/src/main/resources/org/sonar/core/permission/PermissionTemplateMapper.xml b/sonar-core/src/main/resources/org/sonar/core/permission/PermissionTemplateMapper.xml
index 64fb208e8e9..c153b3564fd 100644
--- a/sonar-core/src/main/resources/org/sonar/core/permission/PermissionTemplateMapper.xml
+++ b/sonar-core/src/main/resources/org/sonar/core/permission/PermissionTemplateMapper.xml
@@ -73,6 +73,7 @@
AND ptu.permission_reference=#{query.permission}
AND ptu.template_id=#{templateId}
<where>
+ u.active = ${_true}
<choose>
<when test="query.membership() == 'IN'">
AND ptu.permission_reference IS NOT NULL
diff --git a/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql b/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql
index e7aa6e29d9a..2a6adb2b0b5 100644
--- a/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql
+++ b/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql
@@ -256,6 +256,7 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('583');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('584');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('600');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('601');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('602');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('700');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('701');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('702');
diff --git a/sonar-core/src/test/java/org/sonar/core/permission/UserWithPermissionTemplateDaoTest.java b/sonar-core/src/test/java/org/sonar/core/permission/UserWithPermissionTemplateDaoTest.java
index ed0dc5358fb..e0f0aea1167 100644
--- a/sonar-core/src/test/java/org/sonar/core/permission/UserWithPermissionTemplateDaoTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/permission/UserWithPermissionTemplateDaoTest.java
@@ -20,11 +20,15 @@
package org.sonar.core.permission;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
import org.junit.Before;
import org.junit.Test;
import org.sonar.api.utils.System2;
import org.sonar.core.persistence.AbstractDaoTestCase;
+import javax.annotation.Nullable;
+
import java.util.List;
import static org.fest.assertions.Assertions.assertThat;
@@ -99,6 +103,23 @@ public class UserWithPermissionTemplateDaoTest extends AbstractDaoTestCase {
}
@Test
+ public void select_only_enable_users() throws Exception {
+ setupData("select_only_enable_users");
+
+ PermissionQuery query = PermissionQuery.builder().permission("user").build();
+ List<UserWithPermissionDto> result = dao.selectUsers(query, 999L);
+ assertThat(result).hasSize(3);
+
+ // Disabled user should not be returned
+ assertThat(Iterables.find(result, new Predicate<UserWithPermissionDto>() {
+ @Override
+ public boolean apply(@Nullable UserWithPermissionDto input) {
+ return input.getLogin().equals("disabledUser");
+ }
+ }, null)).isNull();
+ }
+
+ @Test
public void search_by_user_name() throws Exception {
setupData("users_with_permissions");
diff --git a/sonar-core/src/test/resources/org/sonar/core/permission/UserWithPermissionTemplateDaoTest/select_only_enable_users.xml b/sonar-core/src/test/resources/org/sonar/core/permission/UserWithPermissionTemplateDaoTest/select_only_enable_users.xml
new file mode 100644
index 00000000000..14833919475
--- /dev/null
+++ b/sonar-core/src/test/resources/org/sonar/core/permission/UserWithPermissionTemplateDaoTest/select_only_enable_users.xml
@@ -0,0 +1,14 @@
+<dataset>
+
+ <users id="200" login="user1" name="User1" active="[true]"/>
+ <users id="201" login="user2" name="User2" active="[true]"/>
+ <users id="202" login="user3" name="User3" active="[true]"/>
+ <users id="999" login="disabledUser" name="disabledUser" active="[false]"/>
+
+ <perm_templates_users id="1" user_id="200" permission_reference="user" template_id="50"/>
+ <perm_templates_users id="2" user_id="200" permission_reference="admin" template_id="50"/>
+ <perm_templates_users id="3" user_id="200" permission_reference="codeviewer" template_id="50"/>
+
+ <perm_templates_users id="4" user_id="201" permission_reference="user" template_id="50"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/permission/UserWithPermissionTemplateDaoTest/users_with_permissions.xml b/sonar-core/src/test/resources/org/sonar/core/permission/UserWithPermissionTemplateDaoTest/users_with_permissions.xml
index 9c9f018aa2b..e886636bd9b 100644
--- a/sonar-core/src/test/resources/org/sonar/core/permission/UserWithPermissionTemplateDaoTest/users_with_permissions.xml
+++ b/sonar-core/src/test/resources/org/sonar/core/permission/UserWithPermissionTemplateDaoTest/users_with_permissions.xml
@@ -1,8 +1,8 @@
<dataset>
- <users id="200" login="user1" name="User1"/>
- <users id="201" login="user2" name="User2"/>
- <users id="202" login="user3" name="User3"/>
+ <users id="200" login="user1" name="User1" active="[true]"/>
+ <users id="201" login="user2" name="User2" active="[true]"/>
+ <users id="202" login="user3" name="User3" active="[true]"/>
<perm_templates_users id="1" user_id="200" permission_reference="user" template_id="50"/>
<perm_templates_users id="2" user_id="200" permission_reference="admin" template_id="50"/>
diff --git a/sonar-core/src/test/resources/org/sonar/core/permission/UserWithPermissionTemplateDaoTest/users_with_permissions_should_be_sorted_by_user_name.xml b/sonar-core/src/test/resources/org/sonar/core/permission/UserWithPermissionTemplateDaoTest/users_with_permissions_should_be_sorted_by_user_name.xml
index 54acdf839b2..fd8b981c203 100644
--- a/sonar-core/src/test/resources/org/sonar/core/permission/UserWithPermissionTemplateDaoTest/users_with_permissions_should_be_sorted_by_user_name.xml
+++ b/sonar-core/src/test/resources/org/sonar/core/permission/UserWithPermissionTemplateDaoTest/users_with_permissions_should_be_sorted_by_user_name.xml
@@ -1,8 +1,8 @@
<dataset>
- <users id="200" login="user3" name="User3"/>
- <users id="201" login="user1" name="User1"/>
- <users id="202" login="user2" name="User2"/>
+ <users id="200" login="user3" name="User3" active="[true]"/>
+ <users id="201" login="user1" name="User1" active="[true]"/>
+ <users id="202" login="user2" name="User2" active="[true]"/>
<perm_templates_users id="1" user_id="200" permission_reference="user" template_id="50"/>
<perm_templates_users id="2" user_id="200" permission_reference="admin" template_id="50"/>