Browse Source

SONAR-5673 Creating a new profile from a configuration file is not working

tags/4.5.1-RC1
Julien Lancelot 9 years ago
parent
commit
3ac8de5955
19 changed files with 512 additions and 401 deletions
  1. 6
    10
      plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java
  2. 55
    0
      plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeExporter.java
  3. 50
    0
      plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeImporter.java
  4. 47
    0
      plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeImporterWithMessages.java
  5. 1
    1
      plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java
  6. 0
    1
      server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
  7. 70
    3
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java
  8. 4
    0
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileName.java
  9. 0
    139
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRepositoryExporter.java
  10. 5
    3
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResult.java
  11. 13
    3
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileService.java
  12. 5
    1
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java
  13. 9
    5
      server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivatorContextFactory.java
  14. 128
    2
      server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileExportersTest.java
  15. 0
    224
      server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRepositoryExporterTest.java
  16. 88
    1
      server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileServiceMediumTest.java
  17. 26
    2
      server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java
  18. 4
    5
      server/sonar-web/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb
  19. 1
    1
      server/sonar-web/src/main/webapp/WEB-INF/app/views/profiles/_create_form.html.erb

+ 6
- 10
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java View File

@@ -20,16 +20,8 @@
package org.sonar.xoo;

import org.sonar.api.SonarPlugin;
import org.sonar.xoo.lang.MeasureSensor;
import org.sonar.xoo.lang.ScmActivitySensor;
import org.sonar.xoo.lang.SymbolReferencesSensor;
import org.sonar.xoo.lang.SyntaxHighlightingSensor;
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 java.util.Arrays;
import java.util.List;
@@ -49,6 +41,10 @@ public class XooPlugin extends SonarPlugin {
XooRulesDefinition.class,
XooQualityProfile.class,

XooFakeExporter.class,
XooFakeImporter.class,
XooFakeImporterWithMessages.class,

// sensors
MeasureSensor.class,
ScmActivitySensor.class,

+ 55
- 0
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeExporter.java View File

@@ -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);
}
}
}

+ 50
- 0
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeImporter.java View File

@@ -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;
}
}

+ 47
- 0
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/XooFakeImporterWithMessages.java View File

@@ -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();
}
}

+ 1
- 1
plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java View File

@@ -27,6 +27,6 @@ public class XooPluginTest {

@Test
public void provide_extensions() {
assertThat(new XooPlugin().getExtensions()).hasSize(11);
assertThat(new XooPlugin().getExtensions()).hasSize(14);
}
}

+ 0
- 1
server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java View File

@@ -320,7 +320,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);

+ 70
- 3
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java View File

@@ -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;
}

}

+ 4
- 0
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileName.java View File

@@ -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) {

+ 0
- 139
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRepositoryExporter.java View File

@@ -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;
}

}

+ 5
- 3
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResult.java View File

@@ -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;
}

+ 13
- 3
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileService.java View File

@@ -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();
}

+ 5
- 1
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java View File

@@ -21,7 +21,6 @@ package org.sonar.server.qualityprofile;

import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.ServerComponent;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.core.activity.Activity;
@@ -89,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();

+ 9
- 5
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivatorContextFactory.java View File

@@ -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);
}

+ 128
- 2
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileExportersTest.java View File

@@ -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();
}
}

}

+ 0
- 224
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRepositoryExporterTest.java View File

@@ -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);
}

}

+ 88
- 1
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileServiceMediumTest.java View File

@@ -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;
@@ -87,6 +98,35 @@ public class QProfileServiceMediumTest {
dbSession.close();
}

@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;
}
}

}

+ 26
- 2
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java View File

@@ -20,7 +20,10 @@
package org.sonar.server.qualityprofile;

import com.google.common.collect.ImmutableMap;
import org.junit.*;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
@@ -29,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;
@@ -66,6 +70,8 @@ public class RuleActivatorMediumTest {
RuleActivator ruleActivator;
ActiveRuleIndex index;

QualityProfileDto profileDto;

@Before
public void before() {
tester.clearDbAndIndexes();
@@ -97,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();
}
@@ -124,6 +131,23 @@ public class RuleActivatorMediumTest {
assertThat(changes.get(0).getType()).isEqualTo(ActiveRuleChange.Type.ACTIVATED);
}

@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);

+ 4
- 5
server/sonar-web/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb View File

@@ -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/>')

+ 1
- 1
server/sonar-web/src/main/webapp/WEB-INF/app/views/profiles/_create_form.html.erb View File

@@ -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>

Loading…
Cancel
Save