]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5417 Return quality profiles and settings by module
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 24 Jul 2014 07:21:51 +0000 (09:21 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 24 Jul 2014 07:21:51 +0000 (09:21 +0200)
24 files changed:
server/sonar-server/src/main/java/org/sonar/server/batch/BatchWs.java
server/sonar-server/src/main/java/org/sonar/server/batch/GlobalReferentialsAction.java
server/sonar-server/src/main/java/org/sonar/server/batch/ProjectReferentialsAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/component/persistence/ComponentDao.java
server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileProjectOperations.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java
server/sonar-server/src/test/java/org/sonar/server/batch/BatchWsTest.java
server/sonar-server/src/test/java/org/sonar/server/batch/GlobalReferentialsActionTest.java
server/sonar-server/src/test/java/org/sonar/server/batch/ProjectReferentialsActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/component/persistence/ComponentDaoTest.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileFactoryMediumTest.java
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profile_from_default_profile.json [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profiles.json [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_settings_by_modules.json [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_settings_by_modules_without_empty_module_settings.json [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/component/db/ComponentMapper.java
sonar-core/src/main/java/org/sonar/core/properties/PropertiesDao.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/component/db/ComponentMapper.xml
sonar-core/src/main/resources/org/sonar/core/qualityprofile/db/QualityProfileMapper.xml
sonar-core/src/test/java/org/sonar/core/qualityprofile/db/QualityProfileDaoTest.java

index 948ae2417147da2f519f24df7005198e3b1a0aa9..39f5fc8c6956cbb2bac8879f99af8e3913575e04 100644 (file)
@@ -32,10 +32,12 @@ public class BatchWs implements WebService {
 
   private final BatchIndex batchIndex;
   private final GlobalReferentialsAction globalReferentialsAction;
+  private final ProjectReferentialsAction projectReferentialsAction;
 
-  public BatchWs(BatchIndex batchIndex, GlobalReferentialsAction globalReferentialsAction) {
+  public BatchWs(BatchIndex batchIndex, GlobalReferentialsAction globalReferentialsAction, ProjectReferentialsAction projectReferentialsAction) {
     this.batchIndex = batchIndex;
     this.globalReferentialsAction = globalReferentialsAction;
+    this.projectReferentialsAction = projectReferentialsAction;
   }
 
   @Override
@@ -47,6 +49,7 @@ public class BatchWs implements WebService {
     defineIndexAction(controller);
     defineFileAction(controller);
     globalReferentialsAction.define(controller);
+    projectReferentialsAction.define(controller);
 
     controller.done();
   }
index 286f37021becfee0fc6cbc3ed4f6cf423e5d1e95..03251c896950568a0a54f22248c847f77dd6b267 100644 (file)
@@ -101,7 +101,7 @@ public class GlobalReferentialsAction implements RequestHandler {
     }
   }
 
-  private boolean isPropertyAllowed(String key, boolean hasScanPerm, boolean hasDryRunPerm){
+  private static boolean isPropertyAllowed(String key, boolean hasScanPerm, boolean hasDryRunPerm) {
     return !key.contains(".secured") || hasScanPerm || (key.contains(".license") && hasDryRunPerm);
   }
 
diff --git a/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectReferentialsAction.java b/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectReferentialsAction.java
new file mode 100644 (file)
index 0000000..8b4a9f2
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * 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.batch;
+
+import org.apache.commons.io.IOUtils;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.RequestHandler;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.batch.protocol.input.ProjectReferentials;
+import org.sonar.batch.protocol.input.QProfile;
+import org.sonar.core.UtcDateUtils;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.properties.PropertiesDao;
+import org.sonar.core.properties.PropertyDto;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.plugins.MimeTypes;
+import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonar.server.user.UserSession;
+
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.collect.Maps.newHashMap;
+
+public class ProjectReferentialsAction implements RequestHandler {
+
+  private static final String PARAM_KEY = "key";
+
+  private final DbClient dbClient;
+  private final PropertiesDao propertiesDao;
+  private final QProfileFactory qProfileFactory;
+  private final Languages languages;
+
+  public ProjectReferentialsAction(DbClient dbClient, PropertiesDao propertiesDao, QProfileFactory qProfileFactory, Languages languages) {
+    this.dbClient = dbClient;
+    this.propertiesDao = propertiesDao;
+    this.qProfileFactory = qProfileFactory;
+    this.languages = languages;
+  }
+
+  void define(WebService.NewController controller) {
+    WebService.NewAction action = controller.createAction("project")
+      .setDescription("Return project referentials")
+      .setSince("4.5")
+      .setInternal(true)
+      .setHandler(this);
+
+    action
+      .createParam(PARAM_KEY)
+      .setRequired(true)
+      .setDescription("Project key")
+      .setExampleValue("org.codehaus.sonar:sonar");
+  }
+
+  @Override
+  public void handle(Request request, Response response) throws Exception {
+    UserSession userSession = UserSession.get();
+    boolean hasScanPerm = userSession.hasGlobalPermission(GlobalPermissions.SCAN_EXECUTION);
+
+    DbSession session = dbClient.openSession(false);
+    try {
+      ProjectReferentials ref = new ProjectReferentials();
+      String projectKey = request.mandatoryParam(PARAM_KEY);
+      addSettings(ref, projectKey, hasScanPerm, session);
+      addProfiles(ref, projectKey, session);
+
+      response.stream().setMediaType(MimeTypes.JSON);
+      IOUtils.write(ref.toJson(), response.stream().output());
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  private void addSettings(ProjectReferentials ref, String projectKey, boolean hasScanPerm, DbSession session) {
+    addSettings(ref, projectKey, propertiesDao.selectProjectProperties(projectKey, session), hasScanPerm);
+    for (ComponentDto module : dbClient.componentDao().findModulesByProject(projectKey, session)) {
+      addSettings(ref, module.getKey(), propertiesDao.selectProjectProperties(module.getKey(), session), hasScanPerm);
+    }
+  }
+
+  private void addSettings(ProjectReferentials ref, String projectOrModuleKey, List<PropertyDto> propertyDtos, boolean hasScanPerm) {
+    Map<String, String> properties = newHashMap();
+    for (PropertyDto propertyDto : propertyDtos) {
+      String key = propertyDto.getKey();
+      String value = propertyDto.getValue();
+      if (isPropertyAllowed(key, hasScanPerm)) {
+        properties.put(key, value);
+      }
+    }
+    if (!properties.isEmpty()) {
+      ref.addSettings(projectOrModuleKey, properties);
+    }
+  }
+
+  private static boolean isPropertyAllowed(String key, boolean hasScanPerm) {
+    return !key.contains(".secured") || hasScanPerm;
+  }
+
+  private void addProfiles(ProjectReferentials ref, String projectKey, DbSession session) {
+    for (Language language : languages.all()) {
+      String languageKey = language.getKey();
+      QualityProfileDto qualityProfileDto = qProfileFactory.getByProjectAndLanguage(session, projectKey, languageKey);
+      qualityProfileDto = qualityProfileDto != null ? qualityProfileDto : qProfileFactory.getDefault(session, languageKey);
+      if (qualityProfileDto != null) {
+        QProfile profile = new QProfile(qualityProfileDto.getKey(), qualityProfileDto.getName(), qualityProfileDto.getLanguage(),
+          UtcDateUtils.parseDateTime(qualityProfileDto.getRulesUpdatedAt()));
+        ref.addQProfile(profile);
+      }
+    }
+  }
+
+}
index 940bd4d344e74931629fd6239a39a360bf380d8e..39a23370fdfa6bceb86a31a0152bab341cd9236b 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.server.component.persistence;
 
-import org.apache.ibatis.session.SqlSession;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.utils.System2;
 import org.sonar.core.component.ComponentDto;
@@ -29,6 +28,7 @@ import org.sonar.core.persistence.DbSession;
 import org.sonar.server.db.BaseDao;
 
 import java.util.Date;
+import java.util.List;
 
 /**
  * @since 4.3
@@ -39,26 +39,26 @@ public class ComponentDao extends BaseDao<ComponentMapper, ComponentDto, String>
     super(ComponentMapper.class, system);
   }
 
-  public ComponentDto getById(Long id, SqlSession session) {
-    return getMapper(session).selectById(id);
+  public ComponentDto getById(Long id, DbSession session) {
+    return mapper(session).selectById(id);
   }
 
-  public boolean existsById(Long id, SqlSession session) {
-    return getMapper(session).countById(id) > 0;
+  public boolean existsById(Long id, DbSession session) {
+    return mapper(session).countById(id) > 0;
   }
 
-  private ComponentMapper getMapper(SqlSession session) {
-    return session.getMapper(ComponentMapper.class);
+  public List<ComponentDto> findModulesByProject(String projectKey, DbSession session) {
+    return mapper(session).findModulesByProject(projectKey);
   }
 
   @Override
   protected ComponentDto doGetNullableByKey(DbSession session, String key) {
-    return getMapper(session).selectByKey(key);
+    return mapper(session).selectByKey(key);
   }
 
   @Override
   protected ComponentDto doInsert(DbSession session, ComponentDto item) {
-    getMapper(session).insert(item);
+    mapper(session).insert(item);
     return item;
   }
 
index db2109db7f9d5888cece43320f5e19ed22beafc1..91023ef5a0ec3bb81de2ffa8243f1fc80cd66393 100644 (file)
@@ -81,6 +81,7 @@ import org.sonar.server.authentication.ws.AuthenticationWs;
 import org.sonar.server.batch.BatchIndex;
 import org.sonar.server.batch.BatchWs;
 import org.sonar.server.batch.GlobalReferentialsAction;
+import org.sonar.server.batch.ProjectReferentialsAction;
 import org.sonar.server.charts.ChartFactory;
 import org.sonar.server.component.DefaultComponentFinder;
 import org.sonar.server.component.DefaultRubyComponentService;
@@ -296,6 +297,7 @@ class ServerComponents {
     // batch
     pico.addSingleton(BatchIndex.class);
     pico.addSingleton(GlobalReferentialsAction.class);
+    pico.addSingleton(ProjectReferentialsAction.class);
     pico.addSingleton(BatchWs.class);
 
     // update center
index a6fa81675e67a0b94493e6fc5d5b449b56525422..0e7b1042e12bfef2063ae882008e7bd892bd28d5 100644 (file)
@@ -141,7 +141,7 @@ public class QProfileFactory implements ServerComponent {
   }
 
   @CheckForNull
-  QualityProfileDto getDefault(DbSession session, String language) {
+  public QualityProfileDto getDefault(DbSession session, String language) {
     return db.qualityProfileDao().getDefaultProfile(language, session);
   }
 
@@ -168,6 +168,19 @@ public class QProfileFactory implements ServerComponent {
     db.propertiesDao().setProperty(property, session);
   }
 
+  QualityProfileDto getByProjectAndLanguage(String projectKey, String language) {
+    DbSession dbSession = db.openSession(false);
+    try {
+      return getByProjectAndLanguage(dbSession, projectKey, language);
+    } finally {
+      dbSession.close();
+    }
+  }
+
+  public QualityProfileDto getByProjectAndLanguage(DbSession session, String projectKey, String language) {
+    return db.qualityProfileDao().getByProjectAndLanguage(projectKey, language, PROFILE_PROPERTY_PREFIX + language, session);
+  }
+
   private void checkNotDefault(@Nullable QualityProfileDto defaultProfile, QualityProfileDto p) {
     if (defaultProfile != null && defaultProfile.getKey().equals(p.getKey())) {
       throw new BadRequestException("The profile marked as default can not be deleted: " + p.getKey());
index f1e694297ca0e96bf436dd66043876d2a4a96640..da24181f9fbf2a00f9e64f1ea42085b0aa7e3bb9 100644 (file)
@@ -44,15 +44,21 @@ public class QProfileProjectOperations implements ServerComponent {
     checkPermission(userSession);
     DbSession session = db.openSession(false);
     try {
+      addProject(profileId, projectId, userSession, session);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  void addProject(int profileId, long projectId, UserSession userSession, DbSession session) {
+    checkPermission(userSession);
       ComponentDto project = (ComponentDto) findProjectNotNull(projectId, session);
       QualityProfileDto qualityProfile = findNotNull(profileId, session);
 
       db.propertiesDao().setProperty(new PropertyDto().setKey(
         QProfileProjectLookup.PROFILE_PROPERTY_PREFIX + qualityProfile.getLanguage()).setValue(qualityProfile.getName()).setResourceId(project.getId()), session);
       session.commit();
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
   }
 
   public void removeProject(int profileId, long projectId, UserSession userSession) {
index e36b55dae05f1ec54504302d3cad5dc099c8d4a7..b3559277ad1388db3e8d2c4873463bbb3bac5bb2 100644 (file)
@@ -31,6 +31,10 @@ import javax.annotation.CheckForNull;
 
 import java.util.List;
 
+/**
+ * Use {@link org.sonar.server.qualityprofile.QProfileService} instead
+ */
+@Deprecated
 public class QProfiles implements ServerComponent {
 
   private static final String LANGUAGE_PARAM = "language";
@@ -90,7 +94,7 @@ public class QProfiles implements ServerComponent {
   }
 
   /**
-   * Used in /project/profile
+   * Used in /project/profile and in /api/profiles
    */
   @CheckForNull
   public QProfile findProfileByProjectAndLanguage(long projectId, String language) {
index bef1af04f54251dce680e543095cb2478bccd123..50a7c34070529820a8ce8aacc5333ebcb744ab6a 100644 (file)
@@ -28,8 +28,10 @@ import org.junit.rules.TemporaryFolder;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.resources.Languages;
 import org.sonar.core.properties.PropertiesDao;
 import org.sonar.server.db.DbClient;
+import org.sonar.server.qualityprofile.QProfileFactory;
 import org.sonar.server.ws.WsTester;
 
 import java.io.File;
@@ -55,7 +57,9 @@ public class BatchWsTest {
 
   @Before
   public void before() throws IOException {
-    tester = new WsTester(new BatchWs(batchIndex, new GlobalReferentialsAction(mock(DbClient.class), mock(PropertiesDao.class))));
+    tester = new WsTester(new BatchWs(batchIndex,
+      new GlobalReferentialsAction(mock(DbClient.class), mock(PropertiesDao.class)),
+      new ProjectReferentialsAction(mock(DbClient.class), mock(PropertiesDao.class), mock(QProfileFactory.class), mock(Languages.class))));
   }
 
   @Test
index d3f9fb9906af53be58ecc5924b5647398f62db3c..4468e1b7f66ed125518b1c728a9fddf828077619 100644 (file)
@@ -59,7 +59,7 @@ public class GlobalReferentialsActionTest {
     when(dbClient.openSession(false)).thenReturn(session);
     when(dbClient.metricDao()).thenReturn(metricDao);
 
-    tester = new WsTester(new BatchWs(mock(BatchIndex.class), new GlobalReferentialsAction(dbClient, propertiesDao)));
+    tester = new WsTester(new BatchWs(mock(BatchIndex.class), new GlobalReferentialsAction(dbClient, propertiesDao), mock(ProjectReferentialsAction.class)));
   }
 
   @Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/batch/ProjectReferentialsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/batch/ProjectReferentialsActionTest.java
new file mode 100644 (file)
index 0000000..a04fcc5
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * 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.batch;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.properties.PropertiesDao;
+import org.sonar.core.properties.PropertyDto;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
+import org.sonar.server.component.persistence.ComponentDao;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonar.server.user.MockUserSession;
+import org.sonar.server.ws.WsTester;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ProjectReferentialsActionTest {
+
+  @Mock
+  DbSession session;
+
+  @Mock
+  ComponentDao componentDao;
+
+  @Mock
+  PropertiesDao propertiesDao;
+
+  @Mock
+  QProfileFactory qProfileFactory;
+
+  @Mock
+  Languages languages;
+
+  @Mock
+  Language language;
+
+  WsTester tester;
+
+  @Before
+  public void setUp() throws Exception {
+    DbClient dbClient = mock(DbClient.class);
+    when(dbClient.openSession(false)).thenReturn(session);
+    when(dbClient.componentDao()).thenReturn(componentDao);
+
+    when(language.getKey()).thenReturn("java");
+    when(languages.all()).thenReturn(new Language[]{language});
+
+    tester = new WsTester(new BatchWs(mock(BatchIndex.class), mock(GlobalReferentialsAction.class), new ProjectReferentialsAction(dbClient, propertiesDao, qProfileFactory, languages)));
+  }
+
+  @Test
+  public void return_settings_by_modules() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION, GlobalPermissions.DRY_RUN_EXECUTION);
+    String projectKey = "org.codehaus.sonar:sonar";
+    String moduleKey = "org.codehaus.sonar:sonar-server";
+
+    when(componentDao.findModulesByProject(projectKey, session)).thenReturn(newArrayList(
+      new ComponentDto().setKey(projectKey),
+      new ComponentDto().setKey(moduleKey)
+      ));
+
+    when(propertiesDao.selectProjectProperties(projectKey, session)).thenReturn(newArrayList(
+      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR"),
+      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john")
+      ));
+
+    when(propertiesDao.selectProjectProperties(moduleKey, session)).thenReturn(newArrayList(
+      new PropertyDto().setKey("sonar.coverage.exclusions").setValue("**/*.java")
+    ));
+
+    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", projectKey);
+    request.execute().assertJson(getClass(), "return_settings_by_modules.json");
+  }
+
+  @Test
+  public void return_settings_by_modules_without_empty_module_settings() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION, GlobalPermissions.DRY_RUN_EXECUTION);
+    String projectKey = "org.codehaus.sonar:sonar";
+    String moduleKey = "org.codehaus.sonar:sonar-server";
+
+    when(componentDao.findModulesByProject(projectKey, session)).thenReturn(newArrayList(
+      new ComponentDto().setKey(projectKey),
+      new ComponentDto().setKey(moduleKey)
+    ));
+
+    when(propertiesDao.selectProjectProperties(projectKey, session)).thenReturn(newArrayList(
+      new PropertyDto().setKey("sonar.jira.project.key").setValue("SONAR"),
+      new PropertyDto().setKey("sonar.jira.login.secured").setValue("john")
+    ));
+    // No property on module
+
+    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", projectKey);
+    request.execute().assertJson(getClass(), "return_settings_by_modules_without_empty_module_settings.json");
+  }
+
+  @Test
+  public void return_quality_profiles() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION, GlobalPermissions.DRY_RUN_EXECUTION);
+
+    String projectKey = "org.codehaus.sonar:sonar";
+
+    when(qProfileFactory.getByProjectAndLanguage(session, projectKey, "java")).thenReturn(
+      QualityProfileDto.createFor("abcd").setName("Default").setLanguage("java").setRulesUpdatedAt("2014-01-14T14:00:00+0200")
+    );
+
+    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", projectKey);
+    request.execute().assertJson(getClass(), "return_quality_profiles.json");
+  }
+
+  @Test
+  public void return_quality_profile_from_default_profile() throws Exception {
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION, GlobalPermissions.DRY_RUN_EXECUTION);
+
+    String projectKey = "org.codehaus.sonar:sonar";
+
+    when(qProfileFactory.getDefault(session, "java")).thenReturn(
+      QualityProfileDto.createFor("abcd").setName("Default").setLanguage("java").setRulesUpdatedAt("2014-01-14T14:00:00+0200")
+    );
+
+    WsTester.TestRequest request = tester.newGetRequest("batch", "project").setParam("key", projectKey);
+    request.execute().assertJson(getClass(), "return_quality_profile_from_default_profile.json");
+  }
+
+}
index 4d794a8c9ad1e75fedcbc955da4cff1c2dfb989f..c5cb63a11b5b10a174427cc2904719f2cb9a4c4d 100644 (file)
@@ -29,6 +29,7 @@ import org.sonar.core.persistence.AbstractDaoTestCase;
 import org.sonar.core.persistence.DbSession;
 
 import java.util.Date;
+import java.util.List;
 
 import static org.fest.assertions.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -106,6 +107,17 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
     assertThat(dao.existsById(111L, session)).isFalse();
   }
 
+  @Test
+  public void find_modules_by_project() throws Exception {
+    setupData("shared");
+
+    List<ComponentDto> results = dao.findModulesByProject("org.struts:struts", session);
+    assertThat(results).hasSize(1);
+    assertThat(results.get(0).getKey()).isEqualTo("org.struts:struts-core");
+
+    assertThat(dao.findModulesByProject("unknown", session)).isEmpty();
+  }
+
   @Test
   public void insert() {
     when(system2.now()).thenReturn(DateUtils.parseDate("2014-06-18").getTime());
index caaab96473ba210da383553690f5afac64cb7135..cfcb07c5eaeceedc1e01ce10e25e3c873b3ee459 100644 (file)
@@ -24,6 +24,8 @@ import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Test;
 import org.sonar.api.server.rule.RuleParamType;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.properties.PropertyDto;
 import org.sonar.core.qualityprofile.db.QualityProfileDto;
@@ -35,6 +37,7 @@ import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
 import org.sonar.server.rule.RuleTesting;
 import org.sonar.server.search.IndexClient;
 import org.sonar.server.tester.ServerTester;
+import org.sonar.server.user.MockUserSession;
 
 import static org.fest.assertions.Assertions.assertThat;
 import static org.fest.assertions.Fail.fail;
@@ -300,6 +303,31 @@ public class QProfileFactoryMediumTest {
     }
   }
 
+  @Test
+  public void get_profile_by_project_and_language() {
+    ComponentDto project = new ComponentDto()
+      .setId(1L)
+      .setKey("org.codehaus.sonar:sonar")
+      .setName("SonarQube")
+      .setLongName("SonarQube")
+      .setQualifier("TRK")
+      .setScope("TRK")
+      .setEnabled(true);
+    db.componentDao().insert(dbSession, project);
+
+    QualityProfileDto profileDto = QProfileTesting.newXooP1();
+    db.qualityProfileDao().insert(dbSession, profileDto);
+    dbSession.commit();
+    dbSession.clearCache();
+    assertThat(factory.getByProjectAndLanguage("org.codehaus.sonar:sonar", "xoo")).isNull();
+
+    tester.get(QProfileProjectOperations.class).addProject(profileDto.getId(), project.getId(),
+      MockUserSession.set().setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN), dbSession);
+    dbSession.commit();
+    dbSession.clearCache();
+    assertThat(factory.getByProjectAndLanguage("org.codehaus.sonar:sonar", "xoo").getKey()).isEqualTo(XOO_P1_KEY);
+  }
+
   private void initRules() {
     // create pre-defined rules
     RuleDto xooRule1 = RuleTesting.newXooX1();
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profile_from_default_profile.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profile_from_default_profile.json
new file mode 100644 (file)
index 0000000..a1bb33b
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "timestamp": 0,
+  "qprofilesByLanguage": {
+    "java": {
+      "key": "abcd",
+      "name": "Default",
+      "language": "java",
+      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
+    }
+  },
+  "activeRules": [],
+  "settingsByModule": {}
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profiles.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_quality_profiles.json
new file mode 100644 (file)
index 0000000..a1bb33b
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "timestamp": 0,
+  "qprofilesByLanguage": {
+    "java": {
+      "key": "abcd",
+      "name": "Default",
+      "language": "java",
+      "rulesUpdatedAt": "Jan 14, 2014 1:00:00 PM"
+    }
+  },
+  "activeRules": [],
+  "settingsByModule": {}
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_settings_by_modules.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_settings_by_modules.json
new file mode 100644 (file)
index 0000000..8891c45
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "timestamp": 0,
+  "qprofilesByLanguage": {},
+  "activeRules": [],
+  "settingsByModule": {
+    "org.codehaus.sonar:sonar": {
+      "sonar.jira.project.key": "SONAR",
+      "sonar.jira.login.secured": "john"
+    },
+    "org.codehaus.sonar:sonar-server": {
+      "sonar.coverage.exclusions": "**/*.java"
+    }
+  }
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_settings_by_modules_without_empty_module_settings.json b/server/sonar-server/src/test/resources/org/sonar/server/batch/ProjectReferentialsActionTest/return_settings_by_modules_without_empty_module_settings.json
new file mode 100644 (file)
index 0000000..5ca420c
--- /dev/null
@@ -0,0 +1,11 @@
+{
+  "timestamp": 0,
+  "qprofilesByLanguage": {},
+  "activeRules": [],
+  "settingsByModule": {
+    "org.codehaus.sonar:sonar": {
+      "sonar.jira.project.key": "SONAR",
+      "sonar.jira.login.secured": "john"
+    }
+  }
+}
index cb8c8dac1a04c65beeaa0a2368fec29c8228ddd3..9d74af46428e1b83aeb6b54d5d475c8282b2b951 100644 (file)
  */
 package org.sonar.core.component.db;
 
+import org.apache.ibatis.annotations.Param;
 import org.sonar.core.component.ComponentDto;
 
+import java.util.List;
+
 /**
  * @since 4.3
  */
@@ -30,6 +33,8 @@ public interface ComponentMapper {
 
   ComponentDto selectById(long id);
 
+  List<ComponentDto> findModulesByProject(@Param("projectKey") String projectKey);
+
   long countById(long id);
 
   void insert(ComponentDto rule);
index 756ed70d824df9def83e7aa6e4192f025e89e689..4357258a1b43e3261e75f78c2d5d0067bce05d17 100644 (file)
@@ -95,11 +95,14 @@ public class PropertiesDao implements BatchComponent, ServerComponent, DaoCompon
     }
   }
 
+  public List<PropertyDto> selectProjectProperties(String resourceKey, SqlSession session) {
+      return session.getMapper(PropertiesMapper.class).selectProjectProperties(resourceKey);
+  }
+
   public List<PropertyDto> selectProjectProperties(String resourceKey) {
     SqlSession session = mybatis.openSession(false);
-    PropertiesMapper mapper = session.getMapper(PropertiesMapper.class);
     try {
-      return mapper.selectProjectProperties(resourceKey);
+      return selectProjectProperties(resourceKey, session);
     } finally {
       MyBatis.closeQuietly(session);
     }
index 45189d64df9fa5bb53242f95c8f602d4830830c3..01244ef1ae24a57d7f3af03c0e3f0879d47a4a18 100644 (file)
@@ -187,12 +187,17 @@ public class QualityProfileDao implements ServerComponent, DaoComponent {
   public QualityProfileDto getByProjectAndLanguage(long projectId, String language, String key) {
     DbSession session = mybatis.openSession(false);
     try {
-      return session.getMapper(QualityProfileMapper.class).selectByProjectAndLanguage(projectId, language, key);
+      return session.getMapper(QualityProfileMapper.class).selectByProjectIdAndLanguage(projectId, language, key);
     } finally {
       MyBatis.closeQuietly(session);
     }
   }
 
+  @CheckForNull
+  public QualityProfileDto getByProjectAndLanguage(String projectKey, String language, String propertyKeyPrefix, DbSession session) {
+    return session.getMapper(QualityProfileMapper.class).selectByProjectAndLanguage(projectKey, language, propertyKeyPrefix);
+  }
+
   public List<QualityProfileDto> findByLanguage(String language) {
     DbSession session = mybatis.openSession(false);
     try {
index cef07f9a24ad9617f2b60775bb3a74747d08f4e4..3ba368804515c4ee00de4a1a36b6f729bf1c0489 100644 (file)
@@ -67,5 +67,7 @@ public interface QualityProfileMapper {
 
   int countProjects(@Param("value") String propertyValue, @Param("key") String propertyKey);
 
-  QualityProfileDto selectByProjectAndLanguage(@Param("projectId") Long projectId, @Param("language") String language, @Param("key") String propertyKeyPrefix);
+  QualityProfileDto selectByProjectIdAndLanguage(@Param("projectId") Long projectId, @Param("language") String language, @Param("key") String propertyKeyPrefix);
+
+  QualityProfileDto selectByProjectAndLanguage(@Param("projectKey") String projectKey, @Param("language") String language, @Param("propertyKey") String propertyKeyPrefix);
 }
index de9ad8a46b58cee23c6eb678fda9f2770083aa12..f0dc353a03a337489f26c7660eaad98b0f3a035d 100644 (file)
   <select id="selectByKey" parameterType="String" resultType="Component">
     SELECT <include refid="componentColumns"/>
     FROM projects p
-    INNER JOIN snapshots s on s.project_id=p.id and s.islast=${_true}
-    WHERE p.enabled=${_true} AND p.kee=#{key}
+    INNER JOIN snapshots s ON s.project_id=p.id AND s.islast=${_true}
+    <where>
+      AND p.enabled=${_true}
+      AND p.kee=#{key}
+    </where>
   </select>
 
   <select id="selectById" parameterType="long" resultType="Component">
     SELECT <include refid="componentColumns"/>
     FROM projects p
-    INNER JOIN snapshots s on s.project_id=p.id and s.islast=${_true}
-    WHERE p.enabled=${_true} AND p.id=#{id}
+    INNER JOIN snapshots s ON s.project_id=p.id AND s.islast=${_true}
+    <where>
+      AND p.enabled=${_true}
+      AND p.id=#{id}
+    </where>
   </select>
 
   <select id="countById" parameterType="long" resultType="long">
     SELECT count(p.id)
     FROM projects p
-    WHERE p.enabled=${_true} AND p.id=#{id}
+    <where>
+      AND p.enabled=${_true}
+      AND p.id=#{id}
+    </where>
+  </select>
+
+  <select id="findModulesByProject" parameterType="String" resultType="Component">
+    SELECT <include refid="componentColumns"/>
+    FROM projects p
+    INNER JOIN projects root ON root.id=p.root_id AND root.enabled=${_true} AND root.kee=#{projectKey}
+    INNER JOIN snapshots s ON s.project_id=p.id AND s.islast=${_true}
+    <where>
+      AND p.enabled=${_true}
+      AND p.scope='PRJ'
+    </where>
   </select>
 
   <sql id="insertColumns">
index 84c2ae5e10117f9f76d4d4ef02c645819747409e..b8a6ea50889725d5396e7fbb2be25b660082b2a3 100644 (file)
     </where>
   </select>
 
-  <select id="selectByProjectAndLanguage" parameterType="map" resultType="QualityProfile">
+  <select id="selectByProjectIdAndLanguage" parameterType="map" resultType="QualityProfile">
     SELECT <include refid="profilesColumns"/>
     FROM rules_profiles p
     INNER JOIN properties prop ON prop.resource_id=#{projectId}
     WHERE p.language=#{language}
   </select>
 
+  <select id="selectByProjectAndLanguage" parameterType="map" resultType="QualityProfile">
+    SELECT <include refid="profilesColumns"/>
+    FROM rules_profiles p, projects project
+    INNER JOIN properties prop ON prop.resource_id=project.id
+    <where>
+      AND p.language=#{language}
+      AND prop.prop_key LIKE #{propertyKey}
+      AND prop.text_value LIKE p.name
+      AND project.kee=#{projectKey}
+    </where>
+  </select>
+
 </mapper>
 
index 1f1c8554acf082ccc7ef6ba7105d63c17735e0bb..21386e7be708fc05eb4ffb5aa0f6781da8e3041d 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.sonar.core.qualityprofile.db;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.utils.System2;
@@ -36,14 +37,21 @@ import static org.mockito.Mockito.when;
 public class QualityProfileDaoTest extends AbstractDaoTestCase {
 
   QualityProfileDao dao;
+  DbSession session;
   System2 system = mock(System2.class);
 
   @Before
   public void createDao() {
+    this.session = getMyBatis().openSession(false);
     dao = new QualityProfileDao(getMyBatis(), system);
     when(system.now()).thenReturn(UtcDateUtils.parseDateTime("2014-01-20T12:00:00+0000").getTime());
   }
 
+  @After
+  public void after() {
+    this.session.close();
+  }
+
   @Test
   public void insert() {
     setupData("shared");
@@ -217,10 +225,21 @@ public class QualityProfileDaoTest extends AbstractDaoTestCase {
   }
 
   @Test
-  public void select_by_project_and_language() {
+  public void select_by_project_id_and_language() {
     setupData("projects");
 
     QualityProfileDto dto = dao.getByProjectAndLanguage(1L, "java", "sonar.profile.java");
     assertThat(dto.getId()).isEqualTo(1);
   }
+
+  @Test
+  public void select_by_project_key_and_language() {
+    setupData("projects");
+
+    QualityProfileDto dto = dao.getByProjectAndLanguage("org.codehaus.sonar:sonar", "java", "sonar.profile.java", session);
+    assertThat(dto.getId()).isEqualTo(1);
+
+    assertThat(dao.getByProjectAndLanguage("org.codehaus.sonar:sonar", "unkown", "sonar.profile.java", session)).isNull();
+    assertThat(dao.getByProjectAndLanguage("unknown", "java", "sonar.profile.java", session)).isNull();
+  }
 }