]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-926 feed ModuleRules
authorSimon Brandhof <simon.brandhof@gmail.com>
Sun, 26 Jan 2014 23:35:35 +0000 (00:35 +0100)
committerSimon Brandhof <simon.brandhof@gmail.com>
Mon, 27 Jan 2014 06:57:21 +0000 (07:57 +0100)
32 files changed:
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ProfileSensor.java [deleted file]
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/ProfileSensorTest.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/DefaultProfileLoader.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/ProfileLoader.java
sonar-batch/src/main/java/org/sonar/batch/ProfileProvider.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/rule/ModuleQProfiles.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/rule/ModuleRulesProvider.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/rule/QProfileSensor.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/rule/RulesProfileProvider.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/rule/RulesProfileWrapper.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
sonar-batch/src/test/java/org/sonar/batch/DefaultProfileLoaderTest.java
sonar-batch/src/test/java/org/sonar/batch/ProfileProviderTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/rule/ModuleQProfilesTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/rule/ModuleRulesProviderTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/rule/QProfileSensorTest.java [new file with mode: 0644]
sonar-batch/src/test/resources/org/sonar/batch/rule/ModuleQProfilesTest/shared.xml [new file with mode: 0644]
sonar-batch/src/test/resources/org/sonar/batch/rule/ModuleRulesProviderTest/shared.xml [new file with mode: 0644]
sonar-batch/src/test/resources/org/sonar/batch/rule/QProfileSensorTest/mark_profiles_as_used-result.xml [new file with mode: 0644]
sonar-batch/src/test/resources/org/sonar/batch/rule/QProfileSensorTest/shared.xml [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/qualityprofile/db/ActiveRuleDao.java
sonar-core/src/main/java/org/sonar/core/qualityprofile/db/ActiveRuleMapper.java
sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileDao.java
sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileMapper.java
sonar-core/src/main/resources/org/sonar/core/qualityprofile/db/ActiveRuleMapper.xml
sonar-core/src/main/resources/org/sonar/core/qualityprofile/db/QualityProfileMapper.xml
sonar-core/src/test/java/org/sonar/core/qualityprofile/db/ActiveRuleDaoTest.java
sonar-core/src/test/java/org/sonar/core/qualityprofile/db/QualityProfileDaoTest.java
sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/QualityProfileDaoTest/update_used_column-result.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/QualityProfileDaoTest/update_used_column.xml [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/NewModuleRule.java

index 00009b74c6dc4f1b9bffcd29e6c93f41c2b16eaf..02f7faece032d39df21bfb450f5a912494984310 100644 (file)
@@ -79,7 +79,6 @@ import org.sonar.plugins.core.sensors.OverallBranchCoverageDecorator;
 import org.sonar.plugins.core.sensors.OverallCoverageDecorator;
 import org.sonar.plugins.core.sensors.OverallLineCoverageDecorator;
 import org.sonar.plugins.core.sensors.ProfileEventsSensor;
-import org.sonar.plugins.core.sensors.ProfileSensor;
 import org.sonar.plugins.core.sensors.ProjectLinksSensor;
 import org.sonar.plugins.core.sensors.UnitTestDecorator;
 import org.sonar.plugins.core.sensors.VersionEventsSensor;
@@ -378,7 +377,6 @@ public final class CorePlugin extends SonarPlugin {
       NewTechnicalDebtDecorator.class,
 
       // batch
-      ProfileSensor.class,
       ProfileEventsSensor.class,
       ProjectLinksSensor.class,
       UnitTestDecorator.class,
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ProfileSensor.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ProfileSensor.java
deleted file mode 100644 (file)
index ffff3ae..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.plugins.core.sensors;
-
-import org.sonar.api.batch.ModuleLanguages;
-import org.sonar.api.batch.Sensor;
-import org.sonar.api.batch.SensorContext;
-import org.sonar.api.database.DatabaseSession;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Measure;
-import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.resources.Project;
-import org.sonar.batch.RulesProfileWrapper;
-
-public class ProfileSensor implements Sensor {
-
-  private final RulesProfile profile;
-  private final DatabaseSession session;
-  private final ModuleLanguages languages;
-
-  public ProfileSensor(RulesProfile profile, DatabaseSession session, ModuleLanguages languages) {
-    this.profile = profile;
-    this.session = session;
-    this.languages = languages;
-  }
-
-  public boolean shouldExecuteOnProject(Project project) {
-    // Views will define a fake profile
-    return profile instanceof RulesProfileWrapper;
-  }
-
-  public void analyse(Project project, SensorContext context) {
-    RulesProfileWrapper wrapper = (RulesProfileWrapper) profile;
-    for (String languageKey : languages.keys()) {
-      RulesProfile realProfile = wrapper.getProfileByLanguage(languageKey);
-      Measure measure = new Measure(CoreMetrics.PROFILE, profile.getName());
-      Measure measureVersion = new Measure(CoreMetrics.PROFILE_VERSION, Integer.valueOf(profile.getVersion()).doubleValue());
-      if (realProfile.getId() != null) {
-        measure.setValue(realProfile.getId().doubleValue());
-
-        realProfile.setUsed(true);
-        session.merge(realProfile);
-      }
-      context.saveMeasure(measure);
-      context.saveMeasure(measureVersion);
-    }
-  }
-
-  @Override
-  public String toString() {
-    return getClass().getSimpleName();
-  }
-}
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/ProfileSensorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/ProfileSensorTest.java
deleted file mode 100644 (file)
index c1b720f..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.plugins.core.sensors;
-
-import org.junit.Test;
-import org.sonar.api.batch.SensorContext;
-import org.sonar.api.config.Settings;
-import org.sonar.api.database.DatabaseSession;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.resources.Java;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.test.IsMeasure;
-import org.sonar.batch.RulesProfileWrapper;
-import org.sonar.batch.scan.language.DefaultModuleLanguages;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class ProfileSensorTest {
-
-  @Test
-  public void saveProfile() {
-    RulesProfile profile = mock(RulesProfile.class);
-    when(profile.getId()).thenReturn(22);
-    when(profile.getName()).thenReturn("fake");
-    when(profile.getVersion()).thenReturn(2);
-
-    DefaultModuleLanguages moduleLanguages = new DefaultModuleLanguages(new Settings(), new Languages(Java.INSTANCE));
-    moduleLanguages.addLanguage("java");
-    Map<String, RulesProfile> ruleProfilesPerLanguages = new HashMap<String, RulesProfile>();
-    ruleProfilesPerLanguages.put("java", profile);
-    RulesProfileWrapper wrapper = new RulesProfileWrapper(moduleLanguages, ruleProfilesPerLanguages);
-
-    SensorContext context = mock(SensorContext.class);
-    DatabaseSession session = mock(DatabaseSession.class);
-
-    ProfileSensor sensor = new ProfileSensor(wrapper, session, moduleLanguages);
-    sensor.analyse(null, context);
-
-    verify(context).saveMeasure(argThat(new IsMeasure(CoreMetrics.PROFILE, 22d)));
-    verify(context).saveMeasure(argThat(new IsMeasure(CoreMetrics.PROFILE_VERSION, 2d)));
-  }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/DefaultProfileLoader.java b/sonar-batch/src/main/java/org/sonar/batch/DefaultProfileLoader.java
deleted file mode 100644 (file)
index 78d6259..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.batch;
-
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.ModuleLanguages;
-import org.sonar.api.config.Settings;
-import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.resources.Project;
-import org.sonar.api.rules.ActiveRule;
-import org.sonar.api.utils.SonarException;
-import org.sonar.jpa.dao.ProfilesDao;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class DefaultProfileLoader implements ProfileLoader {
-
-  private static final Logger LOG = LoggerFactory.getLogger(DefaultProfileLoader.class);
-
-  private ProfilesDao dao;
-  private Languages languages;
-  private ModuleLanguages moduleLanguages;
-
-  public DefaultProfileLoader(ProfilesDao dao, ModuleLanguages moduleLanguages, Languages languages) {
-    this.dao = dao;
-    this.moduleLanguages = moduleLanguages;
-    this.languages = languages;
-  }
-
-  public RulesProfile load(Project module, Settings settings) {
-
-    if (!moduleLanguages.keys().isEmpty()) {
-      return loadSingleProfile(settings);
-    }
-
-    return loadProfileWrapper(settings);
-  }
-
-  private RulesProfile loadProfileWrapper(Settings settings) {
-    Map<String, RulesProfile> profilesPerLanguageKey = new HashMap<String, RulesProfile>();
-
-    // We have to load profile of all languages even if module will only use part of them because language detection was not done
-    for (Language language : languages.all()) {
-      String languageKey = language.getKey();
-
-      if (StringUtils.isNotBlank(settings.getString("sonar.profile"))) {
-        throw new SonarException("Property sonar.profile should not be used in a multi-language project");
-      }
-      String profileName = settings.getString("sonar.profile." + languageKey);
-
-      RulesProfile profile = dao.getProfile(languageKey, profileName);
-      if (profile == null) {
-        throw new SonarException("Quality profile not found : " + profileName + ", language " + languageKey);
-      }
-
-      profilesPerLanguageKey.put(languageKey, hibernateHack(profile));
-    }
-
-    RulesProfile profile = new RulesProfileWrapper(moduleLanguages, profilesPerLanguageKey);
-    for (Map.Entry<String, RulesProfile> profiles : profilesPerLanguageKey.entrySet()) {
-      LOG.info("Quality profile for {}: {}", profiles.getKey(), profiles.getValue());
-    }
-    return profile;
-  }
-
-  private RulesProfile loadSingleProfile(Settings settings) {
-    Map<String, RulesProfile> profilesPerLanguageKey = new HashMap<String, RulesProfile>();
-
-    // Single language is forced, load a single quality profile
-    String languageKey = moduleLanguages.keys().iterator().next();
-
-    String profileName = StringUtils.defaultIfBlank(
-      settings.getString("sonar.profile"),
-      settings.getString("sonar.profile." + languageKey));
-
-    RulesProfile profile = dao.getProfile(languageKey, profileName);
-    if (profile == null) {
-      throw new SonarException("Quality profile not found : " + profileName + ", language " + languageKey);
-    }
-    profilesPerLanguageKey.put(languageKey, hibernateHack(profile));
-    LOG.info("Quality profile for {}: {}", languageKey, profile);
-
-    return new RulesProfileWrapper(moduleLanguages, profilesPerLanguageKey);
-  }
-
-  private RulesProfile hibernateHack(RulesProfile profile) {
-    // hack to lazy initialize the profile collections
-    profile.getActiveRules().size();
-    for (ActiveRule activeRule : profile.getActiveRules()) {
-      activeRule.getActiveRuleParams().size();
-      activeRule.getRule().getParams().size();
-    }
-    profile.getAlerts().size();
-    return profile;
-  }
-
-}
index 51ce91c7b376332a573dd5d52473cf086ec75d10..9617bc634c5d41df72e814f4cc282d26e81631ed 100644 (file)
@@ -21,17 +21,17 @@ package org.sonar.batch;
 
 import org.sonar.api.config.Settings;
 import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.resources.Project;
 
 /**
   * This interface is implemented by the views plugin!!
   *
   */
+@Deprecated
 public interface ProfileLoader {
 
   /**
    * Loads quality profile for specified project.
    */
-  RulesProfile load(Project project, Settings settings);
+  RulesProfile load(Settings settings);
 
 }
diff --git a/sonar-batch/src/main/java/org/sonar/batch/ProfileProvider.java b/sonar-batch/src/main/java/org/sonar/batch/ProfileProvider.java
deleted file mode 100644 (file)
index e73f13a..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.batch;
-
-import org.picocontainer.injectors.ProviderAdapter;
-import org.sonar.api.config.Settings;
-import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.resources.Project;
-
-public class ProfileProvider extends ProviderAdapter {
-
-  private RulesProfile profile;
-
-  /**
-   * @param languages This parameter is here to ensure Languages is started before this provider in order to display available languages.
-   */
-  public RulesProfile provide(Project project, ProfileLoader profileLoader, Settings settings, Languages languages) {
-    if (profile == null) {
-      profile = profileLoader.load(project, settings);
-    }
-    return profile;
-  }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/rule/ModuleQProfiles.java b/sonar-batch/src/main/java/org/sonar/batch/rule/ModuleQProfiles.java
new file mode 100644 (file)
index 0000000..47da55b
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.batch.rule;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.config.Settings;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
+import org.sonar.api.utils.MessageException;
+import org.sonar.batch.ProfileLoader;
+import org.sonar.core.qualityprofile.db.QualityProfileDao;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
+
+import javax.annotation.CheckForNull;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Lists the Quality profiles enabled on the current module.
+ */
+public class ModuleQProfiles implements BatchComponent {
+
+  private static final Logger LOG = LoggerFactory.getLogger(ModuleQProfiles.class);
+
+  public static class QProfile {
+    private final String name, language;
+    private final Integer version;
+    private final int id;
+
+    public QProfile(QualityProfileDto dto) {
+      this.id = dto.getId();
+      this.name = dto.getName();
+      this.language = dto.getLanguage();
+      this.version = dto.getVersion();
+    }
+
+    public int id() {
+      return id;
+    }
+
+    public String name() {
+      return name;
+    }
+
+    public String language() {
+      return language;
+    }
+
+    public Integer version() {
+      return version;
+    }
+  }
+
+  private final Map<String, QProfile> byLanguage;
+
+
+  public ModuleQProfiles(Settings settings, Languages languages, QualityProfileDao dao, ProfileLoader[] loaders) {
+    ImmutableMap.Builder<String, QProfile> builder = ImmutableMap.builder();
+    if (loaders.length == 0) {
+      // not views plugin
+
+      String defaultName = settings.getString("sonar.profile");
+
+      for (Language language : languages.all()) {
+        QProfile profile;
+        if (StringUtils.isNotBlank(defaultName)) {
+          profile = loadDefaultQProfile(dao, defaultName, language.getKey());
+        } else {
+          profile = loadQProfile(dao, settings, language.getKey());
+        }
+        if (profile != null) {
+          LOG.info("Quality profile for {}: {}", profile.language(), profile.name());
+          builder.put(profile.language(), profile);
+        }
+      }
+    }
+    byLanguage = builder.build();
+  }
+
+  @CheckForNull
+  private QProfile loadQProfile(QualityProfileDao dao, Settings settings, String language) {
+    String profileName = settings.getString("sonar.profile." + language);
+    if (profileName != null) {
+      QualityProfileDto dto = dao.selectByNameAndLanguage(profileName, language);
+      if (dto == null) {
+        throw MessageException.of(String.format("Quality profile not found : '%s' on language '%s'", profileName, language));
+      }
+      return new QProfile(dto);
+    }
+    return null;
+  }
+
+  @CheckForNull
+  private QProfile loadDefaultQProfile(QualityProfileDao dao, String profileName, String language) {
+    QualityProfileDto dto = dao.selectByNameAndLanguage(profileName, language);
+    if (dto != null) {
+      return new QProfile(dto);
+    }
+    return null;
+  }
+
+  public Collection<QProfile> findAll() {
+    return byLanguage.values();
+  }
+
+  @CheckForNull
+  public QProfile findByLanguage(String language) {
+    return byLanguage.get(language);
+  }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/rule/ModuleRulesProvider.java b/sonar-batch/src/main/java/org/sonar/batch/rule/ModuleRulesProvider.java
new file mode 100644 (file)
index 0000000..a4bcdc3
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.batch.rule;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap;
+import org.picocontainer.injectors.ProviderAdapter;
+import org.sonar.api.batch.rule.ModuleRules;
+import org.sonar.api.batch.rule.internal.ModuleRulesBuilder;
+import org.sonar.api.batch.rule.internal.NewModuleRule;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.core.qualityprofile.db.ActiveRuleDao;
+import org.sonar.core.qualityprofile.db.ActiveRuleDto;
+import org.sonar.core.qualityprofile.db.ActiveRuleParamDto;
+
+/**
+ * Loads the rules that are activated on the Quality profiles
+ * used by the current module.
+ */
+public class ModuleRulesProvider extends ProviderAdapter {
+
+  private ModuleRules singleton = null;
+
+  public ModuleRules provide(ModuleQProfiles qProfiles, ActiveRuleDao dao, RuleFinder ruleFinder) {
+    if (singleton == null) {
+      singleton = load(qProfiles, dao, ruleFinder);
+    }
+    return singleton;
+  }
+
+  private ModuleRules load(ModuleQProfiles qProfiles, ActiveRuleDao dao, RuleFinder ruleFinder) {
+    ModuleRulesBuilder builder = new ModuleRulesBuilder();
+    for (ModuleQProfiles.QProfile qProfile : qProfiles.findAll()) {
+      ListMultimap<Integer, ActiveRuleParamDto> paramDtosByActiveRuleId = ArrayListMultimap.create();
+      for (ActiveRuleParamDto dto : dao.selectParamsByProfileId(qProfile.id())) {
+        paramDtosByActiveRuleId.put(dto.getActiveRuleId(), dto);
+      }
+
+      for (ActiveRuleDto activeDto : dao.selectByProfileId(qProfile.id())) {
+        Rule rule = ruleFinder.findById(activeDto.getRulId());
+        if (rule != null) {
+          NewModuleRule newModuleRule = builder.activate(rule.ruleKey());
+          newModuleRule.setSeverity(activeDto.getSeverityString());
+          for (ActiveRuleParamDto paramDto : paramDtosByActiveRuleId.get(activeDto.getId())) {
+            newModuleRule.setParam(paramDto.getKey(), paramDto.getValue());
+          }
+          // TODO add default values declared on rule parameters
+        }
+      }
+    }
+    return builder.build();
+  }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/rule/QProfileSensor.java b/sonar-batch/src/main/java/org/sonar/batch/rule/QProfileSensor.java
new file mode 100644 (file)
index 0000000..3012bbd
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.batch.rule;
+
+import org.sonar.api.batch.ModuleLanguages;
+import org.sonar.api.batch.Sensor;
+import org.sonar.api.batch.SensorContext;
+import org.sonar.api.resources.Project;
+import org.sonar.core.qualityprofile.db.QualityProfileDao;
+
+/**
+ * Stores which Quality profiles have been used on the current module.
+ */
+public class QProfileSensor implements Sensor {
+
+  private final ModuleQProfiles moduleQProfiles;
+  private final ModuleLanguages moduleLanguages;
+  private final QualityProfileDao dao;
+
+  public QProfileSensor(ModuleQProfiles moduleQProfiles, ModuleLanguages moduleLanguages, QualityProfileDao dao) {
+    this.moduleQProfiles = moduleQProfiles;
+    this.moduleLanguages = moduleLanguages;
+    this.dao = dao;
+  }
+
+  public boolean shouldExecuteOnProject(Project project) {
+    return true;
+  }
+
+  public void analyse(Project project, SensorContext context) {
+    for (String language : moduleLanguages.keys()) {
+      ModuleQProfiles.QProfile qProfile = moduleQProfiles.findByLanguage(language);
+      // TODO does not support multi-language modules
+//        Measure measure = new Measure(CoreMetrics.PROFILE, qProfile.name());
+//        Measure measureVersion = new Measure(CoreMetrics.PROFILE_VERSION, qProfile.version().doubleValue());
+//        context.saveMeasure(measure);
+//        context.saveMeasure(measureVersion);
+      if (qProfile != null) {
+        dao.updateUsedColumn(qProfile.id(), true);
+      }
+    }
+  }
+
+  @Override
+  public String toString() {
+    return getClass().getSimpleName();
+  }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/rule/RulesProfileProvider.java b/sonar-batch/src/main/java/org/sonar/batch/rule/RulesProfileProvider.java
new file mode 100644 (file)
index 0000000..d8c0c00
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.batch.rule;
+
+import com.google.common.collect.Lists;
+import org.picocontainer.injectors.ProviderAdapter;
+import org.sonar.api.batch.ModuleLanguages;
+import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.rules.ActiveRule;
+import org.sonar.jpa.dao.ProfilesDao;
+
+import java.util.Collection;
+
+/**
+ * Ensures backward-compatibility with extensions that use {@link org.sonar.api.profiles.RulesProfile}.
+ */
+public class RulesProfileProvider extends ProviderAdapter {
+
+  private RulesProfile singleton = null;
+
+  public RulesProfile provide(ModuleQProfiles qProfiles, ModuleLanguages moduleLanguages, ProfilesDao dao) {
+    if (singleton == null) {
+      if (moduleLanguages.keys().size() == 1) {
+        // Backward-compatibility with single-language modules
+        singleton = loadSingleLanguageProfile(qProfiles, moduleLanguages.keys().iterator().next(), dao);
+      } else {
+        singleton = loadProfiles(qProfiles, dao);
+      }
+    }
+    return singleton;
+  }
+
+  private RulesProfile loadSingleLanguageProfile(ModuleQProfiles qProfiles, String language, ProfilesDao dao) {
+    ModuleQProfiles.QProfile qProfile = qProfiles.findByLanguage(language);
+    return new RulesProfileWrapper(select(qProfile, dao));
+  }
+
+  private RulesProfile loadProfiles(ModuleQProfiles qProfiles, ProfilesDao dao) {
+    Collection<RulesProfile> dtos = Lists.newArrayList();
+    for (ModuleQProfiles.QProfile qProfile : qProfiles.findAll()) {
+      dtos.add(select(qProfile, dao));
+    }
+    return new RulesProfileWrapper(dtos);
+  }
+
+  private RulesProfile select(ModuleQProfiles.QProfile qProfile, ProfilesDao dao) {
+    RulesProfile dto = dao.getProfile(qProfile.language(), qProfile.name());
+    return hibernateHack(dto);
+  }
+
+  private RulesProfile hibernateHack(RulesProfile profile) {
+    // hack to lazy initialize the profile collections
+    profile.getActiveRules().size();
+    for (ActiveRule activeRule : profile.getActiveRules()) {
+      activeRule.getActiveRuleParams().size();
+      activeRule.getRule().getParams().size();
+    }
+    profile.getAlerts().size();
+    return profile;
+  }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/rule/RulesProfileWrapper.java b/sonar-batch/src/main/java/org/sonar/batch/rule/RulesProfileWrapper.java
new file mode 100644 (file)
index 0000000..8bd0c36
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.batch.rule;
+
+import com.google.common.collect.Lists;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.profiles.Alert;
+import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.rules.ActiveRule;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.utils.SonarException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * This wrapper is used to try to preserve backward compatibility for plugins that used to
+ * depends on {@link org.sonar.api.profiles.RulesProfile}
+ *
+ * @since 4.2
+ */
+public class RulesProfileWrapper extends RulesProfile {
+
+  private static final Logger LOG = LoggerFactory.getLogger(RulesProfileWrapper.class);
+
+  private final Collection<RulesProfile> profiles;
+  private final RulesProfile singleLanguageProfile;
+
+  RulesProfileWrapper(Collection<RulesProfile> profiles) {
+    this.profiles = profiles;
+    this.singleLanguageProfile = null;
+  }
+
+  RulesProfileWrapper(RulesProfile profile) {
+    this.profiles = Lists.newArrayList(profile);
+    this.singleLanguageProfile = profile;
+  }
+
+  @Override
+  public Integer getId() {
+    return getSingleProfileOrFail().getId();
+  }
+
+  private RulesProfile getSingleProfileOrFail() {
+    if (singleLanguageProfile != null) {
+      throw new SonarException("Please update your plugin to support multi-language analysis");
+    }
+    return singleLanguageProfile;
+  }
+
+  @Override
+  public String getName() {
+    return getSingleProfileOrFail().getName();
+  }
+
+  @Override
+  public String getLanguage() {
+    if (singleLanguageProfile == null) {
+      // Multi-languages module
+      // FIXME This is a hack for CommonChecksDecorator that call this method in its constructor
+      LOG.debug("Please update your plugin to support multi-language analysis", new SonarException("Please update your plugin to support multi-language analysis"));
+      return "";
+    }
+    return singleLanguageProfile.getName();
+  }
+
+  @Override
+  public List<Alert> getAlerts() {
+    List<Alert> result = new ArrayList<Alert>();
+    for (RulesProfile profile : profiles) {
+      result.addAll(profile.getAlerts());
+    }
+    return result;
+  }
+
+  @Override
+  public List<ActiveRule> getActiveRules() {
+    List<ActiveRule> activeRules = new ArrayList<ActiveRule>();
+    for (RulesProfile profile : profiles) {
+      activeRules.addAll(profile.getActiveRules());
+    }
+    return activeRules;
+  }
+
+  @Override
+  public int getVersion() {
+    return getSingleProfileOrFail().getVersion();
+  }
+
+  @Override
+  public ActiveRule getActiveRule(String repositoryKey, String ruleKey) {
+    for (RulesProfile profile : profiles) {
+      ActiveRule activeRule = profile.getActiveRule(repositoryKey, ruleKey);
+      if (activeRule != null) {
+        return activeRule;
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public List<ActiveRule> getActiveRulesByRepository(String repositoryKey) {
+    List<ActiveRule> activeRules = new ArrayList<ActiveRule>();
+    for (RulesProfile profile : profiles) {
+      activeRules.addAll(profile.getActiveRulesByRepository(repositoryKey));
+    }
+    return activeRules;
+  }
+
+  @Override
+  public List<ActiveRule> getActiveRules(boolean acceptDisabledRules) {
+    List<ActiveRule> activeRules = new ArrayList<ActiveRule>();
+    for (RulesProfile profile : profiles) {
+      activeRules.addAll(profile.getActiveRules(acceptDisabledRules));
+    }
+    return activeRules;
+  }
+
+  @Override
+  public ActiveRule getActiveRule(Rule rule) {
+    for (RulesProfile profile : profiles) {
+      ActiveRule activeRule = profile.getActiveRule(rule);
+      if (activeRule != null) {
+        return activeRule;
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public Boolean getDefaultProfile() {
+    return getSingleProfileOrFail().getDefaultProfile();
+  }
+
+}
index f0d28e30ccd0a9d8401a4ec1d728006a6eff3a14..b34065bff145b05bafa882615e02af5e2cc70511 100644 (file)
@@ -19,8 +19,6 @@
  */
 package org.sonar.batch.scan;
 
-import org.sonar.batch.scan.filesystem.ComponentIndexer;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.BatchExtension;
@@ -30,15 +28,7 @@ import org.sonar.api.platform.ComponentContainer;
 import org.sonar.api.resources.Languages;
 import org.sonar.api.resources.Project;
 import org.sonar.api.scan.filesystem.FileExclusions;
-import org.sonar.batch.DefaultProfileLoader;
-import org.sonar.batch.DefaultProjectClasspath;
-import org.sonar.batch.DefaultSensorContext;
-import org.sonar.batch.DefaultTimeMachine;
-import org.sonar.batch.ProfileLoader;
-import org.sonar.batch.ProfileProvider;
-import org.sonar.batch.ProjectTree;
-import org.sonar.batch.ResourceFilters;
-import org.sonar.batch.ViolationFilters;
+import org.sonar.batch.*;
 import org.sonar.batch.bootstrap.BatchExtensionDictionnary;
 import org.sonar.batch.bootstrap.ExtensionInstaller;
 import org.sonar.batch.bootstrap.ExtensionMatcher;
@@ -52,16 +42,10 @@ import org.sonar.batch.issue.IssueFilters;
 import org.sonar.batch.issue.ModuleIssues;
 import org.sonar.batch.phases.PhaseExecutor;
 import org.sonar.batch.phases.PhasesTimeProfiler;
-import org.sonar.batch.scan.filesystem.DefaultModuleFileSystem;
-import org.sonar.batch.scan.filesystem.DeprecatedFileFilters;
-import org.sonar.batch.scan.filesystem.ExclusionFilters;
-import org.sonar.batch.scan.filesystem.FileHashes;
-import org.sonar.batch.scan.filesystem.FileIndex;
-import org.sonar.batch.scan.filesystem.FileSystemLogger;
-import org.sonar.batch.scan.filesystem.LanguageRecognizer;
-import org.sonar.batch.scan.filesystem.ModuleFileSystemInitializer;
-import org.sonar.batch.scan.filesystem.ProjectFileSystemAdapter;
-import org.sonar.batch.scan.filesystem.RemoteFileHashes;
+import org.sonar.batch.rule.ModuleRulesProvider;
+import org.sonar.batch.rule.QProfileSensor;
+import org.sonar.batch.rule.RulesProfileProvider;
+import org.sonar.batch.scan.filesystem.*;
 import org.sonar.batch.scan.language.DefaultModuleLanguages;
 import org.sonar.batch.scan.report.ComponentSelectorFactory;
 import org.sonar.batch.scan.report.JsonReport;
@@ -95,11 +79,6 @@ public class ModuleScanContainer extends ComponentContainer {
     // hack to initialize commons-configuration before ExtensionProviders
     getComponentByType(ModuleSettings.class);
 
-    // Don't override ProfileLoader provided by views plugin in parent container
-    if (getComponentByType(ProfileLoader.class) == null) {
-      add(DefaultProfileLoader.class);
-    }
-
     add(
       EventBus.class,
       PhaseExecutor.class,
@@ -138,7 +117,11 @@ public class ModuleScanContainer extends ComponentContainer {
       IssueFilters.class,
       MeasurementFilters.class,
       ResourceFilters.class,
-      new ProfileProvider(),
+
+      // rules
+      new ModuleRulesProvider(),
+      new RulesProfileProvider(),
+      QProfileSensor.class,
 
       // report
       JsonReport.class,
index 081d7fe6f69511cbc2dba97528fbb1dfb05e0e52..cbded87c5c120df53c7833a9798ddc21620e019a 100644 (file)
  */
 package org.sonar.batch;
 
-import org.apache.commons.configuration.PropertiesConfiguration;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.config.Settings;
-import org.sonar.api.profiles.Alert;
-import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.resources.AbstractLanguage;
-import org.sonar.api.resources.Java;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.resources.Project;
-import org.sonar.api.rules.ActiveRule;
-import org.sonar.api.rules.RulePriority;
-import org.sonar.api.utils.SonarException;
-import org.sonar.batch.scan.language.DefaultModuleLanguages;
-import org.sonar.jpa.dao.ProfilesDao;
-
-import java.util.Arrays;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class DefaultProfileLoaderTest {
-
-  @Rule
-  public ExpectedException thrown = ExpectedException.none();
-
-  private ProfilesDao dao;
-  private Languages languages;
-  private Project javaProject = newProject(Java.KEY);
-
-  @Before
-  public void setUp() {
-    dao = mock(ProfilesDao.class);
-    Language cobol = new AbstractLanguage("cobol", "Cobol") {
-      public String[] getFileSuffixes() {
-        return null;
-      };
-    };
-    languages = new Languages(Java.INSTANCE, cobol);
-  }
-
-  @Test
-  public void should_get_configured_profile() {
-    Settings settings = new Settings();
-    settings.setProperty("sonar.profile.java", "legacy profile");
-    settings.setProperty("sonar.profile.cobol", "cobol profile");
-    when(dao.getProfile(Java.KEY, "legacy profile")).thenReturn(RulesProfile.create("legacy profile", "java"));
-    when(dao.getProfile("cobol", "cobol profile")).thenReturn(RulesProfile.create("cobol profile", "cobol"));
-
-    DefaultModuleLanguages moduleLanguages = new DefaultModuleLanguages(settings, languages);
-    moduleLanguages.addLanguage("java");
-    RulesProfile profile = new DefaultProfileLoader(dao, moduleLanguages, languages).load(javaProject, settings);
-
-    assertThat(profile.getName()).isEqualTo("legacy profile");
-  }
-
-  @Test
-  public void some_methods_should_support_multilanguage() {
-    Settings settings = new Settings();
-    settings.setProperty("sonar.profile.java", "java profile");
-    settings.setProperty("sonar.profile.cobol", "cobol profile");
-
-    RulesProfile javaProfile = RulesProfile.create("java profile", "java");
-    org.sonar.api.rules.Rule javaRule = new org.sonar.api.rules.Rule("javaplugin", "javarule");
-    ActiveRule javaActiveRule = new ActiveRule(javaProfile, javaRule, RulePriority.BLOCKER);
-    javaProfile.addActiveRule(javaActiveRule);
-    Alert javaAlert = mock(Alert.class);
-    javaProfile.setAlerts(Arrays.asList(javaAlert));
-    when(dao.getProfile(Java.KEY, "java profile")).thenReturn(javaProfile);
-
-    RulesProfile cobolProfile = RulesProfile.create("cobol profile", "cobol");
-    org.sonar.api.rules.Rule cobolRule = new org.sonar.api.rules.Rule("cobolplugin", "cobolrule");
-    ActiveRule cobolActiveRule = new ActiveRule(cobolProfile, cobolRule, RulePriority.BLOCKER);
-    cobolProfile.addActiveRule(cobolActiveRule);
-    Alert cobolAlert = mock(Alert.class);
-    cobolProfile.setAlerts(Arrays.asList(cobolAlert));
-    when(dao.getProfile("cobol", "cobol profile")).thenReturn(cobolProfile);
-
-    DefaultModuleLanguages moduleLanguages = new DefaultModuleLanguages(settings, languages);
-    RulesProfile profile = new DefaultProfileLoader(dao, moduleLanguages, languages).load(javaProject, settings);
-
-    // Languages are detected later
-    moduleLanguages.addLanguage("java");
-    moduleLanguages.addLanguage("cobol");
-
-    assertThat(profile.getActiveRules()).containsOnly(javaActiveRule, cobolActiveRule);
-    assertThat(profile.getActiveRules(true)).containsOnly(javaActiveRule, cobolActiveRule);
-    assertThat(profile.getActiveRulesByRepository("javaplugin")).containsOnly(javaActiveRule);
-    assertThat(profile.getActiveRulesByRepository("cobolplugin")).containsOnly(cobolActiveRule);
-    assertThat(profile.getActiveRule("javaplugin", "javarule")).isEqualTo(javaActiveRule);
-    assertThat(profile.getActiveRule(javaRule)).isEqualTo(javaActiveRule);
-    assertThat(profile.getActiveRule("cobolplugin", "cobolrule")).isEqualTo(cobolActiveRule);
-    assertThat(profile.getActiveRule(cobolRule)).isEqualTo(cobolActiveRule);
-    assertThat(profile.getAlerts()).containsOnly(javaAlert, cobolAlert);
-    // Hack for CommonChecksDecorator
-    assertThat(profile.getLanguage()).isEqualTo("");
-  }
-
-  @Test
-  public void some_methods_should_not_support_multilanguage() {
-    Settings settings = new Settings();
-    settings.setProperty("sonar.profile.java", "java profile");
-    settings.setProperty("sonar.profile.cobol", "cobol profile");
-
-    RulesProfile javaProfile = RulesProfile.create("java profile", "java");
-    org.sonar.api.rules.Rule javaRule = new org.sonar.api.rules.Rule("javaplugin", "javarule");
-    ActiveRule javaActiveRule = new ActiveRule(javaProfile, javaRule, RulePriority.BLOCKER);
-    javaProfile.addActiveRule(javaActiveRule);
-    when(dao.getProfile(Java.KEY, "java profile")).thenReturn(javaProfile);
-
-    RulesProfile cobolProfile = RulesProfile.create("cobol profile", "cobol");
-    org.sonar.api.rules.Rule cobolRule = new org.sonar.api.rules.Rule("cobolplugin", "cobolrule");
-    ActiveRule cobolActiveRule = new ActiveRule(cobolProfile, cobolRule, RulePriority.BLOCKER);
-    cobolProfile.addActiveRule(cobolActiveRule);
-    when(dao.getProfile("cobol", "cobol profile")).thenReturn(cobolProfile);
-
-    DefaultModuleLanguages moduleLanguages = new DefaultModuleLanguages(settings, languages);
-    moduleLanguages.addLanguage("java");
-    moduleLanguages.addLanguage("cobol");
-    RulesProfile profile = new DefaultProfileLoader(dao, moduleLanguages, languages).load(javaProject, settings);
-
-    thrown.expect(SonarException.class);
-    thrown.expectMessage("Please update your plugin to support multi-language analysis");
-    profile.getId();
-  }
-
-  @Test
-  public void should_fail_if_not_found() {
-    Settings settings = new Settings();
-    settings.setProperty("sonar.profile.java", "unknown");
-
-    thrown.expect(SonarException.class);
-    thrown.expectMessage("Quality profile not found : unknown, language java");
-    new DefaultProfileLoader(dao, new DefaultModuleLanguages(settings, languages), languages).load(javaProject, settings);
-  }
-
-  private Project newProject(String language) {
-    PropertiesConfiguration configuration = new PropertiesConfiguration();
-    configuration.setProperty("sonar.language", language);
-    return new Project("project").setConfiguration(configuration);
-  }
-}
+//import org.apache.commons.configuration.PropertiesConfiguration;
+//import org.junit.Before;
+//import org.junit.Rule;
+//import org.junit.Test;
+//import org.junit.rules.ExpectedException;
+//import org.sonar.api.config.Settings;
+//import org.sonar.api.profiles.Alert;
+//import org.sonar.api.profiles.RulesProfile;
+//import org.sonar.api.resources.AbstractLanguage;
+//import org.sonar.api.resources.Java;
+//import org.sonar.api.resources.Language;
+//import org.sonar.api.resources.Languages;
+//import org.sonar.api.resources.Project;
+//import org.sonar.api.rules.ActiveRule;
+//import org.sonar.api.rules.RulePriority;
+//import org.sonar.api.utils.SonarException;
+//import org.sonar.batch.scan.language.DefaultModuleLanguages;
+//import org.sonar.jpa.dao.ProfilesDao;
+//
+//import java.util.Arrays;
+//
+//import static org.fest.assertions.Assertions.assertThat;
+//import static org.mockito.Mockito.mock;
+//import static org.mockito.Mockito.when;
+//
+//public class DefaultProfileLoaderTest {
+//
+//  @Rule
+//  public ExpectedException thrown = ExpectedException.none();
+//
+//  ProfilesDao dao;
+//  Languages languages;
+//
+//  @Before
+//  public void setUp() {
+//    dao = mock(ProfilesDao.class);
+//    Language cobol = new AbstractLanguage("cobol", "Cobol") {
+//      public String[] getFileSuffixes() {
+//        return null;
+//      }
+//    };
+//    languages = new Languages(Java.INSTANCE, cobol);
+//  }
+//
+//  @Test
+//  public void should_get_configured_profile() {
+//    Settings settings = new Settings();
+//    settings.setProperty("sonar.profile.java", "legacy profile");
+//    settings.setProperty("sonar.profile.cobol", "cobol profile");
+//    when(dao.getProfile(Java.KEY, "legacy profile")).thenReturn(RulesProfile.create("legacy profile", "java"));
+//    when(dao.getProfile("cobol", "cobol profile")).thenReturn(RulesProfile.create("cobol profile", "cobol"));
+//
+//    DefaultModuleLanguages moduleLanguages = new DefaultModuleLanguages(settings, languages);
+//    moduleLanguages.addLanguage("java");
+//    RulesProfile profile = new DefaultProfileLoader(dao, moduleLanguages, languages).load(settings);
+//
+//    assertThat(profile.getName()).isEqualTo("legacy profile");
+//  }
+//
+//  @Test
+//  public void some_methods_should_support_multilanguage() {
+//    Settings settings = new Settings();
+//    settings.setProperty("sonar.profile.java", "java profile");
+//    settings.setProperty("sonar.profile.cobol", "cobol profile");
+//
+//    RulesProfile javaProfile = RulesProfile.create("java profile", "java");
+//    org.sonar.api.rules.Rule javaRule = new org.sonar.api.rules.Rule("javaplugin", "javarule");
+//    ActiveRule javaActiveRule = new ActiveRule(javaProfile, javaRule, RulePriority.BLOCKER);
+//    javaProfile.addActiveRule(javaActiveRule);
+//    Alert javaAlert = mock(Alert.class);
+//    javaProfile.setAlerts(Arrays.asList(javaAlert));
+//    when(dao.getProfile(Java.KEY, "java profile")).thenReturn(javaProfile);
+//
+//    RulesProfile cobolProfile = RulesProfile.create("cobol profile", "cobol");
+//    org.sonar.api.rules.Rule cobolRule = new org.sonar.api.rules.Rule("cobolplugin", "cobolrule");
+//    ActiveRule cobolActiveRule = new ActiveRule(cobolProfile, cobolRule, RulePriority.BLOCKER);
+//    cobolProfile.addActiveRule(cobolActiveRule);
+//    Alert cobolAlert = mock(Alert.class);
+//    cobolProfile.setAlerts(Arrays.asList(cobolAlert));
+//    when(dao.getProfile("cobol", "cobol profile")).thenReturn(cobolProfile);
+//
+//    DefaultModuleLanguages moduleLanguages = new DefaultModuleLanguages(settings, languages);
+//    RulesProfile profile = new DefaultProfileLoader(dao, moduleLanguages, languages).load(settings);
+//
+//    // Languages are detected later
+//    moduleLanguages.addLanguage("java");
+//    moduleLanguages.addLanguage("cobol");
+//
+//    assertThat(profile.getActiveRules()).containsOnly(javaActiveRule, cobolActiveRule);
+//    assertThat(profile.getActiveRules(true)).containsOnly(javaActiveRule, cobolActiveRule);
+//    assertThat(profile.getActiveRulesByRepository("javaplugin")).containsOnly(javaActiveRule);
+//    assertThat(profile.getActiveRulesByRepository("cobolplugin")).containsOnly(cobolActiveRule);
+//    assertThat(profile.getActiveRule("javaplugin", "javarule")).isEqualTo(javaActiveRule);
+//    assertThat(profile.getActiveRule(javaRule)).isEqualTo(javaActiveRule);
+//    assertThat(profile.getActiveRule("cobolplugin", "cobolrule")).isEqualTo(cobolActiveRule);
+//    assertThat(profile.getActiveRule(cobolRule)).isEqualTo(cobolActiveRule);
+//    assertThat(profile.getAlerts()).containsOnly(javaAlert, cobolAlert);
+//    // Hack for CommonChecksDecorator
+//    assertThat(profile.getLanguage()).isEqualTo("");
+//  }
+//
+//  @Test
+//  public void some_methods_should_not_support_multilanguage() {
+//    Settings settings = new Settings();
+//    settings.setProperty("sonar.profile.java", "java profile");
+//    settings.setProperty("sonar.profile.cobol", "cobol profile");
+//
+//    RulesProfile javaProfile = RulesProfile.create("java profile", "java");
+//    org.sonar.api.rules.Rule javaRule = new org.sonar.api.rules.Rule("javaplugin", "javarule");
+//    ActiveRule javaActiveRule = new ActiveRule(javaProfile, javaRule, RulePriority.BLOCKER);
+//    javaProfile.addActiveRule(javaActiveRule);
+//    when(dao.getProfile(Java.KEY, "java profile")).thenReturn(javaProfile);
+//
+//    RulesProfile cobolProfile = RulesProfile.create("cobol profile", "cobol");
+//    org.sonar.api.rules.Rule cobolRule = new org.sonar.api.rules.Rule("cobolplugin", "cobolrule");
+//    ActiveRule cobolActiveRule = new ActiveRule(cobolProfile, cobolRule, RulePriority.BLOCKER);
+//    cobolProfile.addActiveRule(cobolActiveRule);
+//    when(dao.getProfile("cobol", "cobol profile")).thenReturn(cobolProfile);
+//
+//    DefaultModuleLanguages moduleLanguages = new DefaultModuleLanguages(settings, languages);
+//    moduleLanguages.addLanguage("java");
+//    moduleLanguages.addLanguage("cobol");
+//    RulesProfile profile = new DefaultProfileLoader(dao, moduleLanguages, languages).load(settings);
+//
+//    thrown.expect(SonarException.class);
+//    thrown.expectMessage("Please update your plugin to support multi-language analysis");
+//    profile.getId();
+//  }
+//
+//  @Test
+//  public void should_fail_if_not_found() {
+//    Settings settings = new Settings();
+//    settings.setProperty("sonar.profile.java", "unknown");
+//
+//    thrown.expect(SonarException.class);
+//    thrown.expectMessage("Quality profile not found : unknown, language java");
+//    new DefaultProfileLoader(dao, new DefaultModuleLanguages(settings, languages), languages).load(settings);
+//  }
+//
+//  private Project newProject(String language) {
+//    PropertiesConfiguration configuration = new PropertiesConfiguration();
+//    configuration.setProperty("sonar.language", language);
+//    return new Project("project").setConfiguration(configuration);
+//  }
+//}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/ProfileProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/ProfileProviderTest.java
deleted file mode 100644 (file)
index 12c7cb2..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.batch;
-
-import org.apache.commons.configuration.PropertiesConfiguration;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.config.Settings;
-import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.resources.Project;
-
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-public class ProfileProviderTest {
-
-  @Rule
-  public ExpectedException thrown = ExpectedException.none();
-
-  private Project javaProject;
-
-  @Before
-  public void setUp() {
-    javaProject = newProject("java");
-  }
-
-  @Test
-  public void shouldProvideProfile() {
-    ProfileProvider provider = new ProfileProvider();
-    ProfileLoader loader = mock(ProfileLoader.class);
-    RulesProfile profile = RulesProfile.create();
-    when(loader.load(eq(javaProject), any(Settings.class))).thenReturn(profile);
-
-    assertThat(provider.provide(javaProject, loader, new Settings(), mock(Languages.class)), is(profile));
-    assertThat(provider.provide(javaProject, loader, new Settings(), mock(Languages.class)), is(profile));
-    verify(loader).load(eq(javaProject), any(Settings.class));
-    verifyNoMoreInteractions(loader);
-  }
-
-  private Project newProject(String language) {
-    PropertiesConfiguration configuration = new PropertiesConfiguration();
-    configuration.setProperty("sonar.language", language);
-    return new Project("project").setConfiguration(configuration);
-  }
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/rule/ModuleQProfilesTest.java b/sonar-batch/src/test/java/org/sonar/batch/rule/ModuleQProfilesTest.java
new file mode 100644 (file)
index 0000000..478b4fa
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.batch.rule;
+
+import com.google.common.collect.Lists;
+import org.junit.Test;
+import org.sonar.api.config.Settings;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
+import org.sonar.api.utils.MessageException;
+import org.sonar.batch.ProfileLoader;
+import org.sonar.core.persistence.AbstractDaoTestCase;
+import org.sonar.core.qualityprofile.db.QualityProfileDao;
+
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+
+public class ModuleQProfilesTest extends AbstractDaoTestCase {
+
+  Languages languages = new Languages(new SimpleLanguage("java"), new SimpleLanguage("php"));
+  Settings settings = new Settings();
+
+  @Test
+  public void find_profiles() throws Exception {
+    setupData("shared");
+    QualityProfileDao dao = new QualityProfileDao(getMyBatis());
+
+    settings.setProperty("sonar.profile.java", "Java Two");
+    settings.setProperty("sonar.profile.abap", "Abap One");
+    settings.setProperty("sonar.profile.php", "Php One");
+
+    ModuleQProfiles moduleQProfiles = new ModuleQProfiles(settings, languages, dao, new ProfileLoader[0]);
+    List<ModuleQProfiles.QProfile> qProfiles = Lists.newArrayList(moduleQProfiles.findAll());
+
+    assertThat(qProfiles).hasSize(2);
+    assertThat(moduleQProfiles.findByLanguage("java")).isNotNull();
+    assertThat(moduleQProfiles.findByLanguage("php")).isNotNull();
+    assertThat(moduleQProfiles.findByLanguage("abap")).isNull();
+    ModuleQProfiles.QProfile javaProfile = qProfiles.get(0);
+    assertThat(javaProfile.id()).isEqualTo(2);
+    assertThat(javaProfile.name()).isEqualTo("Java Two");
+    assertThat(javaProfile.language()).isEqualTo("java");
+    assertThat(javaProfile.version()).isEqualTo(20);
+    ModuleQProfiles.QProfile phpProfile = qProfiles.get(1);
+    assertThat(phpProfile.id()).isEqualTo(3);
+    assertThat(phpProfile.name()).isEqualTo("Php One");
+    assertThat(phpProfile.language()).isEqualTo("php");
+    assertThat(phpProfile.version()).isEqualTo(30);
+
+  }
+
+  @Test
+  public void use_deprecated_property() throws Exception {
+    setupData("shared");
+    QualityProfileDao dao = new QualityProfileDao(getMyBatis());
+
+    settings.setProperty("sonar.profile", "Java Two");
+    settings.setProperty("sonar.profile.php", "Php One");
+
+    ModuleQProfiles moduleQProfiles = new ModuleQProfiles(settings, languages, dao, new ProfileLoader[0]);
+    List<ModuleQProfiles.QProfile> qProfiles = Lists.newArrayList(moduleQProfiles.findAll());
+
+    assertThat(qProfiles).hasSize(1);
+    ModuleQProfiles.QProfile javaProfile = qProfiles.get(0);
+    assertThat(javaProfile.id()).isEqualTo(2);
+    assertThat(javaProfile.name()).isEqualTo("Java Two");
+    assertThat(javaProfile.language()).isEqualTo("java");
+    assertThat(javaProfile.version()).isEqualTo(20);
+
+    // the php profile is not found as sonar.profile overrides all other properties.
+  }
+
+  @Test
+  public void fail_if_unknown_profile() throws Exception {
+    setupData("shared");
+    QualityProfileDao dao = new QualityProfileDao(getMyBatis());
+
+    settings.setProperty("sonar.profile.java", "Unknown");
+    settings.setProperty("sonar.profile.php", "Php One");
+
+    try {
+      new ModuleQProfiles(settings, languages, dao, new ProfileLoader[0]);
+      fail();
+    } catch (MessageException e) {
+      assertThat(e).hasMessage("Quality profile not found : 'Unknown' on language 'java'");
+    }
+  }
+
+  private static class SimpleLanguage implements Language {
+
+    private final String key;
+
+    private SimpleLanguage(String key) {
+      this.key = key;
+    }
+
+    @Override
+    public String getKey() {
+      return key;
+    }
+
+    @Override
+    public String getName() {
+      return key;
+    }
+
+    @Override
+    public String[] getFileSuffixes() {
+      return new String[0];
+    }
+  }
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/rule/ModuleRulesProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/rule/ModuleRulesProviderTest.java
new file mode 100644 (file)
index 0000000..5d1fdcf
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.batch.rule;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.batch.rule.ModuleRule;
+import org.sonar.api.batch.rule.ModuleRules;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.core.persistence.AbstractDaoTestCase;
+import org.sonar.core.qualityprofile.db.ActiveRuleDao;
+import org.sonar.core.qualityprofile.db.QualityProfileDao;
+
+import java.util.Arrays;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ModuleRulesProviderTest extends AbstractDaoTestCase {
+
+  ModuleQProfiles qProfiles = mock(ModuleQProfiles.class);
+  RuleFinder ruleFinder = mock(RuleFinder.class);
+
+  @Before
+  public void init_rules() {
+    when(ruleFinder.findById(10)).thenReturn(new Rule().setRepositoryKey("squid").setKey("S0001"));
+    when(ruleFinder.findById(100)).thenReturn(new Rule().setRepositoryKey("phpunit").setKey("P1"));
+  }
+  @Test
+  public void build_module_rules() throws Exception {
+    setupData("shared");
+    QualityProfileDao profileDao = new QualityProfileDao(getMyBatis());
+    when(qProfiles.findAll()).thenReturn(Arrays.asList(
+      // 1 rule is enabled on java with severity INFO
+      new ModuleQProfiles.QProfile(profileDao.selectById(2)),
+      // 1 rule is enabled on php with severity BLOCKER
+      new ModuleQProfiles.QProfile(profileDao.selectById(3))
+    ));
+
+    ModuleRulesProvider provider = new ModuleRulesProvider();
+    ActiveRuleDao activeRuleDao = new ActiveRuleDao(getMyBatis());
+    ModuleRules moduleRules = provider.provide(qProfiles, activeRuleDao, ruleFinder);
+
+    assertThat(moduleRules.findAll()).hasSize(2);
+    assertThat(moduleRules.findByRepository("squid")).hasSize(1);
+    assertThat(moduleRules.findByRepository("phpunit")).hasSize(1);
+    assertThat(moduleRules.findByRepository("unknown")).isEmpty();
+    ModuleRule squidRule = moduleRules.find(RuleKey.of("squid", "S0001"));
+    assertThat(squidRule.severity()).isEqualTo(Severity.INFO);
+    assertThat(squidRule.params()).hasSize(2);
+    assertThat(squidRule.param("max")).isEqualTo("20");
+    assertThat(squidRule.param("format")).isEqualTo("html");
+    ModuleRule phpRule = moduleRules.find(RuleKey.of("phpunit", "P1"));
+    assertThat(phpRule.severity()).isEqualTo(Severity.BLOCKER);
+    assertThat(phpRule.params()).isEmpty();
+  }
+
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/rule/QProfileSensorTest.java b/sonar-batch/src/test/java/org/sonar/batch/rule/QProfileSensorTest.java
new file mode 100644 (file)
index 0000000..c8fab70
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.batch.rule;
+
+import edu.emory.mathcs.backport.java.util.Collections;
+import org.junit.Test;
+import org.sonar.api.batch.ModuleLanguages;
+import org.sonar.api.batch.SensorContext;
+import org.sonar.api.resources.Project;
+import org.sonar.core.persistence.AbstractDaoTestCase;
+import org.sonar.core.qualityprofile.db.QualityProfileDao;
+
+import java.util.Arrays;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
+public class QProfileSensorTest extends AbstractDaoTestCase {
+
+  ModuleQProfiles moduleQProfiles = mock(ModuleQProfiles.class);
+  ModuleLanguages moduleLanguages = mock(ModuleLanguages.class);
+  Project project = mock(Project.class);
+  SensorContext sensorContext = mock(SensorContext.class);
+
+  @Test
+  public void no_qprofiles() throws Exception {
+    setupData("shared");
+    QualityProfileDao dao = new QualityProfileDao(getMyBatis());
+    when(moduleQProfiles.findAll()).thenReturn(Collections.emptyList());
+
+    QProfileSensor sensor = new QProfileSensor(moduleQProfiles, moduleLanguages, dao);
+    assertThat(sensor.shouldExecuteOnProject(project)).isTrue();
+    sensor.analyse(project, sensorContext);
+
+    // measures are not saved
+    verifyZeroInteractions(sensorContext);
+  }
+
+  @Test
+  public void mark_profiles_as_used() throws Exception {
+    setupData("shared");
+
+    QualityProfileDao dao = new QualityProfileDao(getMyBatis());
+    when(moduleQProfiles.findByLanguage("java")).thenReturn(new ModuleQProfiles.QProfile(dao.selectById(2)));
+    when(moduleQProfiles.findByLanguage("php")).thenReturn(new ModuleQProfiles.QProfile(dao.selectById(3)));
+    when(moduleQProfiles.findByLanguage("abap")).thenReturn(null);
+    when(moduleLanguages.keys()).thenReturn(Arrays.asList("java", "php", "abap"));
+
+    QProfileSensor sensor = new QProfileSensor(moduleQProfiles, moduleLanguages, dao);
+    assertThat(sensor.shouldExecuteOnProject(project)).isTrue();
+    sensor.analyse(project, sensorContext);
+
+    checkTable("mark_profiles_as_used", "rules_profiles");
+  }
+}
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/rule/ModuleQProfilesTest/shared.xml b/sonar-batch/src/test/resources/org/sonar/batch/rule/ModuleQProfilesTest/shared.xml
new file mode 100644 (file)
index 0000000..425b89d
--- /dev/null
@@ -0,0 +1,15 @@
+<dataset>
+
+  <rules_profiles id="1" name="Java One" language="java" parent_name="[null]" version="10"
+                  used_profile="[false]"/>
+
+  <rules_profiles id="2" name="Java Two" language="java" parent_name="[null]" version="20"
+                  used_profile="[false]"/>
+
+  <rules_profiles id="3" name="Php One" language="php" parent_name="[null]" version="30"
+                  used_profile="[false]"/>
+
+  <rules_profiles id="4" name="Cobol One" language="cbl" parent_name="[null]" version="40"
+                  used_profile="[false]"/>
+
+</dataset>
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/rule/ModuleRulesProviderTest/shared.xml b/sonar-batch/src/test/resources/org/sonar/batch/rule/ModuleRulesProviderTest/shared.xml
new file mode 100644 (file)
index 0000000..2c4953c
--- /dev/null
@@ -0,0 +1,25 @@
+<dataset>
+
+  <rules_profiles id="1" name="Java One" language="java" parent_name="[null]" version="10"
+                  used_profile="[false]"/>
+
+  <rules_profiles id="2" name="Java Two" language="java" parent_name="[null]" version="20"
+                  used_profile="[false]"/>
+
+  <rules_profiles id="3" name="Php One" language="php" parent_name="[null]" version="30"
+                  used_profile="[false]"/>
+
+  <rules_profiles id="4" name="Cobol One" language="cbl" parent_name="[null]" version="40"
+                  used_profile="[false]"/>
+
+  <!-- java -->
+  <active_rules id="1" profile_id="2" rule_id="10" failure_level="0" inheritance="[null]"
+                note_created_at="2013-12-18" note_updated_at="2013-12-18" note_user_login="john" note_data="other note"/>
+
+  <active_rule_parameters id="1" active_rule_id="1" rules_parameter_id="1" rules_parameter_key="max" value="20"/>
+  <active_rule_parameters id="2" active_rule_id="1" rules_parameter_id="2" rules_parameter_key="format" value="html"/>
+
+  <!-- php -->
+  <active_rules id="2" profile_id="3" rule_id="100" failure_level="4" inheritance="[null]"
+                note_created_at="2013-12-18" note_updated_at="2013-12-18" note_user_login="john" note_data="other note"/>
+</dataset>
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/rule/QProfileSensorTest/mark_profiles_as_used-result.xml b/sonar-batch/src/test/resources/org/sonar/batch/rule/QProfileSensorTest/mark_profiles_as_used-result.xml
new file mode 100644 (file)
index 0000000..7794819
--- /dev/null
@@ -0,0 +1,15 @@
+<dataset>
+
+  <rules_profiles id="1" name="Java One" language="java" parent_name="[null]" version="1"
+                  used_profile="[false]"/>
+
+  <rules_profiles id="2" name="Java Two" language="java" parent_name="[null]" version="1"
+                  used_profile="[true]"/>
+
+  <rules_profiles id="3" name="Php One" language="php" parent_name="[null]" version="1"
+                  used_profile="[true]"/>
+
+  <rules_profiles id="4" name="Cobol One" language="cbl" parent_name="[null]" version="1"
+                  used_profile="[false]"/>
+
+</dataset>
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/rule/QProfileSensorTest/shared.xml b/sonar-batch/src/test/resources/org/sonar/batch/rule/QProfileSensorTest/shared.xml
new file mode 100644 (file)
index 0000000..c3ec8e0
--- /dev/null
@@ -0,0 +1,15 @@
+<dataset>
+
+  <rules_profiles id="1" name="Java One" language="java" parent_name="[null]" version="1"
+                  used_profile="[false]"/>
+
+  <rules_profiles id="2" name="Java Two" language="java" parent_name="[null]" version="1"
+                  used_profile="[false]"/>
+
+  <rules_profiles id="3" name="Php One" language="php" parent_name="[null]" version="1"
+                  used_profile="[false]"/>
+
+  <rules_profiles id="4" name="Cobol One" language="cbl" parent_name="[null]" version="1"
+                  used_profile="[false]"/>
+
+</dataset>
index bdc607fef259c8acd1152dcd7240248f01b51c0e..e41c91c708c8fcdc6227d252007cddbc451488a8 100644 (file)
@@ -347,4 +347,13 @@ public class ActiveRuleDao implements ServerComponent {
   public List<ActiveRuleParamDto> selectAllParams(SqlSession session) {
     return session.getMapper(ActiveRuleMapper.class).selectAllParams();
   }
+
+  public List<ActiveRuleParamDto> selectParamsByProfileId(int profileId) {
+    SqlSession session = mybatis.openSession();
+    try {
+      return session.getMapper(ActiveRuleMapper.class).selectParamsByProfileId(profileId);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
 }
index aae23290ee5fca53015e6d60c0221dae0d2e4da2..4c974f09e33f817858e2d7a11e83ab119b8905b8 100644 (file)
@@ -70,6 +70,8 @@ public interface ActiveRuleMapper {
 
   List<ActiveRuleParamDto> selectParamsByActiveRuleId(int activeRuleId);
 
+  List<ActiveRuleParamDto> selectParamsByProfileId(int profileId);
+
   List<ActiveRuleParamDto> selectAllParams();
 
 
index e736686264fd75a05af91322478924b79f3eda83..2f8ab8a38b522c39e7c0d6132cc5f7349e85da5f 100644 (file)
@@ -211,4 +211,13 @@ public class QualityProfileDao implements ServerComponent {
     }
   }
 
+  public void updateUsedColumn(int profileId, boolean used) {
+    SqlSession session = mybatis.openSession();
+    try {
+      session.getMapper(QualityProfileMapper.class).updatedUsedColumn(profileId, used);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
 }
index 8338ab6c885fd7dc3e25e6ec42c5596bea236152..5ddf7e3b98fcadfe94363afcadca49ee09f91261 100644 (file)
@@ -65,4 +65,5 @@ public interface QualityProfileMapper {
 
   List<QualityProfileDto> selectByProject(@Param("projectId") Long projectId, @Param("key") String propertyKeyPrefix);
 
+  void updatedUsedColumn(@Param("id") int profileId, @Param("used") boolean used);
 }
index cf389856b4587bba805b24429c1b1ce0c8dd62eb..a41353bf019691211bcb998745eb34ff94c8faaf 100644 (file)
     </where>
   </select>
 
+  <select id="selectParamsByProfileId" parameterType="int" resultType="ActiveRuleParam">
+    select
+    <include refid="activeRuleParamColumns"/>
+    from active_rule_parameters p
+    inner join active_rules ar on ar.id=p.active_rule_id
+    where ar.profile_id=#{profileId}
+  </select>
+
   <select id="selectAllParams" parameterType="map" resultType="ActiveRuleParam">
     SELECT <include refid="activeRuleParamColumns"/>
     FROM active_rule_parameters p
index 9bf019e41d6349f7e87794b47e701ab5df0a2323..876fc40df5cb7f984cc28b95fef1ec78e4ba88c7 100644 (file)
       AND prop.text_value LIKE p.name
   </select>
 
+  <update id="updatedUsedColumn" parameterType="map">
+    UPDATE rules_profiles SET
+    used_profile=#{used}
+    WHERE id=#{id}
+  </update>
+
 </mapper>
 
index 9b3ba405b717d5e65a7fd02c3871e489f6a7bfbb..165dd319deec082f61a171151a647979e8fd74f6 100644 (file)
@@ -270,6 +270,13 @@ public class ActiveRuleDaoTest extends AbstractDaoTestCase {
     assertThat(dao.selectParamsByActiveRuleIds(ImmutableList.of(1, 2))).hasSize(3);
   }
 
+  @Test
+  public void select_params_by_profile_id() {
+    setupData("shared");
+
+    assertThat(dao.selectParamsByProfileId(1)).hasSize(2);
+  }
+
   @Test
   public void select_all_params() {
     setupData("shared");
index 863471257c9d6fbfe2da2ec0d066bc6db899f3ce..f01091d99630e093ec084416df5d737cd210ca58 100644 (file)
@@ -223,5 +223,12 @@ public class QualityProfileDaoTest extends AbstractDaoTestCase {
     assertThat(dao.selectByProject(1L, "sonar.profile.%")).hasSize(2);
   }
 
+  @Test
+  public void update_used_column() {
+    setupData("update_used_column");
+
+    dao.updateUsedColumn(123, true);
 
+    checkTables("update_used_column", "rules_profiles");
+  }
 }
diff --git a/sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/QualityProfileDaoTest/update_used_column-result.xml b/sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/QualityProfileDaoTest/update_used_column-result.xml
new file mode 100644 (file)
index 0000000..8d050e7
--- /dev/null
@@ -0,0 +1,6 @@
+<dataset>
+
+  <rules_profiles id="123" name="Sonar Way" language="java" parent_name="[null]" version="1"
+                  used_profile="[true]"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/QualityProfileDaoTest/update_used_column.xml b/sonar-core/src/test/resources/org/sonar/core/qualityprofile/db/QualityProfileDaoTest/update_used_column.xml
new file mode 100644 (file)
index 0000000..8b13511
--- /dev/null
@@ -0,0 +1,6 @@
+<dataset>
+
+  <rules_profiles id="123" name="Sonar Way" language="java" parent_name="[null]" version="1"
+                  used_profile="[false]"/>
+
+</dataset>
index cc95045ec3e845ba8004db9bd1343be94fb7233e..2cfecd7c9af6a08ea8845580dfb290c8be7752de 100644 (file)
@@ -26,12 +26,12 @@ import javax.annotation.Nullable;
 import java.util.HashMap;
 import java.util.Map;
 
-class NewModuleRule {
+public class NewModuleRule {
   final RuleKey ruleKey;
   String severity = Severity.defaultSeverity();
   Map<String, String> params = new HashMap<String, String>();
 
-  public NewModuleRule(RuleKey ruleKey) {
+  NewModuleRule(RuleKey ruleKey) {
     this.ruleKey = ruleKey;
   }