]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6075 Add ability to search issues on developer technical project copy 114/head
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Mon, 23 Feb 2015 16:27:50 +0000 (17:27 +0100)
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Tue, 24 Feb 2015 09:19:54 +0000 (10:19 +0100)
server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java
server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java
server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java
server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/delete-result.xml
server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/shared.xml
sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml

index ea8b19c55bb5be0ff3edd1b0a5c6313ffead4e2d..9eb2a6277d663adbd590a9f1ac2a191cac890d37 100644 (file)
@@ -25,6 +25,7 @@ import com.google.common.base.Function;
 import com.google.common.base.Joiner;
 import com.google.common.base.Splitter;
 import com.google.common.base.Strings;
+import com.google.common.collect.Collections2;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
@@ -269,23 +270,16 @@ public class IssueQueryService implements ServerComponent {
     switch(uniqueQualifier) {
       case Qualifiers.VIEW:
       case Qualifiers.SUBVIEW:
-        List<String> filteredViewUuids = newArrayList();
-        for (String viewUuid : componentUuids) {
-          if ((Qualifiers.VIEW.equals(uniqueQualifier) && UserSession.get().hasProjectPermissionByUuid(UserRole.USER, viewUuid))
-            || (Qualifiers.SUBVIEW.equals(uniqueQualifier) && UserSession.get().hasComponentUuidPermission(UserRole.USER, viewUuid))) {
-            filteredViewUuids.add(viewUuid);
-          }
-        }
-        if (filteredViewUuids.isEmpty()) {
-          filteredViewUuids.add(UNKNOWN);
-        }
-        builder.viewUuids(filteredViewUuids);
+        addViewsOrSubViews(builder, componentUuids, uniqueQualifier);
         break;
       case "DEV":
         // XXX No constant for developer !!!
-        Collection<String> actualAuthors = authors == null ? dbClient.authorDao().selectScmAccountsByDeveloperUuids(session, componentUuids) : authors;
+        Collection<String> actualAuthors = authorsFromParamsOrFromDeveloper(session, componentUuids, authors);
         builder.authors(actualAuthors);
         break;
+      case "DEV_PRJ":
+        addDeveloperTechnicalProjects(builder, session, componentUuids, authors);
+        break;
       case Qualifiers.PROJECT:
         builder.projectUuids(componentUuids);
         break;
@@ -293,14 +287,7 @@ public class IssueQueryService implements ServerComponent {
         builder.moduleRootUuids(componentUuids);
         break;
       case Qualifiers.DIRECTORY:
-        Collection<String> directoryModuleUuids = Sets.newHashSet();
-        Collection<String> directoryPaths = Sets.newHashSet();
-        for (ComponentDto directory : componentService.getByUuids(session, componentUuids)) {
-          directoryModuleUuids.add(directory.moduleUuid());
-          directoryPaths.add(directory.path());
-        }
-        builder.moduleUuids(directoryModuleUuids);
-        builder.directories(directoryPaths);
+        addDirectories(builder, session, componentUuids);
         break;
       case Qualifiers.FILE:
       case Qualifiers.UNIT_TEST_FILE:
@@ -311,6 +298,61 @@ public class IssueQueryService implements ServerComponent {
     }
   }
 
+  private void addViewsOrSubViews(IssueQuery.Builder builder, Collection<String> componentUuids, String uniqueQualifier) {
+    List<String> filteredViewUuids = newArrayList();
+    for (String viewUuid : componentUuids) {
+      if ((Qualifiers.VIEW.equals(uniqueQualifier) && UserSession.get().hasProjectPermissionByUuid(UserRole.USER, viewUuid))
+        || (Qualifiers.SUBVIEW.equals(uniqueQualifier) && UserSession.get().hasComponentUuidPermission(UserRole.USER, viewUuid))) {
+        filteredViewUuids.add(viewUuid);
+      }
+    }
+    if (filteredViewUuids.isEmpty()) {
+      filteredViewUuids.add(UNKNOWN);
+    }
+    builder.viewUuids(filteredViewUuids);
+  }
+
+  private void addDeveloperTechnicalProjects(IssueQuery.Builder builder, DbSession session, Collection<String> componentUuids, Collection<String> authors) {
+    Collection<ComponentDto> technicalProjects = dbClient.componentDao().getByUuids(session, componentUuids);
+    Collection<String> developerUuids = Collections2.transform(technicalProjects, new Function<ComponentDto, String>() {
+      @Override
+      public String apply(ComponentDto input) {
+        return input.projectUuid();
+      }
+    });
+    Collection<String> authorsFromProjects = authorsFromParamsOrFromDeveloper(session, developerUuids, authors);
+    builder.authors(authorsFromProjects);
+    Collection<Long> projectIds = Collections2.transform(technicalProjects, new Function<ComponentDto, Long>() {
+      @Override
+      public Long apply(ComponentDto input) {
+        return input.getCopyResourceId();
+      }
+    });
+    List<ComponentDto> originalProjects = dbClient.componentDao().getByIds(session, projectIds);
+    Collection<String> projectUuids = Collections2.transform(originalProjects, new Function<ComponentDto, String>() {
+      @Override
+      public String apply(ComponentDto input) {
+        return input.uuid();
+      }
+    });
+    builder.projectUuids(projectUuids);
+  }
+
+  private Collection<String> authorsFromParamsOrFromDeveloper(DbSession session, Collection<String> componentUuids, Collection<String> authors) {
+    return authors == null ? dbClient.authorDao().selectScmAccountsByDeveloperUuids(session, componentUuids) : authors;
+  }
+
+  private void addDirectories(IssueQuery.Builder builder, DbSession session, Collection<String> componentUuids) {
+    Collection<String> directoryModuleUuids = Sets.newHashSet();
+    Collection<String> directoryPaths = Sets.newHashSet();
+    for (ComponentDto directory : componentService.getByUuids(session, componentUuids)) {
+      directoryModuleUuids.add(directory.moduleUuid());
+      directoryPaths.add(directory.path());
+    }
+    builder.moduleUuids(directoryModuleUuids);
+    builder.directories(directoryPaths);
+  }
+
   private Collection<String> componentUuids(DbSession session, @Nullable Collection<String> componentKeys) {
     Collection<String> componentUuids = Lists.newArrayList();
     componentUuids.addAll(componentService.componentUuids(session, componentKeys, true));
index bcb34731db50332767cd07b951c51ecd8aa480b6..64ff8638acf3af5389e86000eaccb888aa42b934 100644 (file)
@@ -130,6 +130,20 @@ public class ComponentTesting {
       .setLanguage(null);
   }
 
+  public static ComponentDto newDevProjectCopy(String uuid, ComponentDto project, ComponentDto developer) {
+    Preconditions.checkNotNull(project.getId(), "The project need to be persisted before creating this technical project.");
+    return newChildComponent(uuid, developer)
+      .setUuid(uuid)
+      .setKey(developer.key() + ":" + project.key())
+      .setName(project.name())
+      .setLongName(project.longName())
+      .setCopyResourceId(project.getId())
+      .setScope(Scopes.PROJECT)
+      .setQualifier("DEV_PRJ")
+      .setPath(null)
+      .setLanguage(null);
+  }
+
   private static ComponentDto newChildComponent(String uuid, ComponentDto module) {
     return newChildComponent(uuid, module, false);
   }
index fde5e2162b94c2b6d28b84235829444bb1dbfcb2..1c62b09058eb3782a6b00541d4fcc99984f9374c 100644 (file)
@@ -79,6 +79,28 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
     assertThat(result.qualifier()).isEqualTo("FIL");
     assertThat(result.scope()).isEqualTo("FIL");
     assertThat(result.language()).isEqualTo("java");
+    assertThat(result.getCopyResourceId()).isNull();
+  }
+
+  @Test
+  public void get_by_uuid_on_technical_project_copy() {
+    setupData("shared");
+
+    ComponentDto result = dao.getNullableByUuid(session, "STUV");
+    assertThat(result).isNotNull();
+    assertThat(result.uuid()).isEqualTo("STUV");
+    assertThat(result.moduleUuid()).isEqualTo("OPQR");
+    assertThat(result.moduleUuidPath()).isEqualTo(".OPQR.");
+    assertThat(result.parentProjectId()).isEqualTo(11);
+    assertThat(result.projectUuid()).isEqualTo("OPQR");
+    assertThat(result.key()).isEqualTo("DEV:anakin@skywalker.name:org.struts:struts");
+    assertThat(result.path()).isNull();
+    assertThat(result.name()).isEqualTo("Apache Struts");
+    assertThat(result.longName()).isEqualTo("Apache Struts");
+    assertThat(result.qualifier()).isEqualTo("DEV_PRJ");
+    assertThat(result.scope()).isEqualTo("PRJ");
+    assertThat(result.language()).isNull();
+    assertThat(result.getCopyResourceId()).isEqualTo(1L);
   }
 
   @Test
index 8ad7564189508f2dc77902b7bb133222b2e10da0..1a301b8cc66ca3890654c9d2eaea94a843a01d01 100644 (file)
@@ -356,6 +356,31 @@ public class IssueQueryServiceTest {
     assertThat(query.authors()).containsExactly(login);
   }
 
+  @Test
+  public void should_search_on_developer_technical_project() throws Exception {
+    String projectUuid = "sample1";
+    String devUuid = "DEV:anakin.skywalker";
+    String login1 = "anakin@skywalker.name";
+    String login2 = "darth.vader";
+    String copyProjectUuid = devUuid + ":" + projectUuid;
+
+    long copyResourceId = 42L;
+    ComponentDto technicalProject = new ComponentDto().setProjectUuid(devUuid).setCopyResourceId(copyResourceId);
+    when(componentDao.getByUuids(isA(DbSession.class), anyCollection())).thenReturn(Arrays.asList(technicalProject));
+
+    when(componentService.getDistinctQualifiers(isA(DbSession.class), anyCollection())).thenReturn(Sets.newHashSet("DEV_PRJ"));
+    when(authorDao.selectScmAccountsByDeveloperUuids(isA(DbSession.class), anyCollection())).thenReturn(Lists.newArrayList(login1, login2));
+
+    ComponentDto actualProject = new ComponentDto().setUuid(projectUuid);
+    when(componentDao.getByIds(isA(DbSession.class), anyCollection())).thenReturn(Arrays.asList(actualProject));
+
+    Map<String, Object> map = newHashMap();
+    map.put("componentUuids", newArrayList(copyProjectUuid));
+    IssueQuery query = issueQueryService.createFromMap(map);
+    assertThat(query.authors()).containsExactly(login1, login2);
+    assertThat(query.projectUuids()).containsExactly(projectUuid);
+  }
+
   @Test
   public void should_search_in_tree_with_module_uuid() throws Exception {
     String moduleUuid = "ABCD";
index 5b3ed06779439bb03da756f41dfddb45675575cb..b8d6c393b92729fd36151ca790779ee048d56b78 100644 (file)
@@ -49,6 +49,7 @@ import org.sonar.server.user.MockUserSession;
 import org.sonar.server.view.index.ViewDoc;
 import org.sonar.server.view.index.ViewIndexer;
 import org.sonar.server.ws.WsTester;
+import org.sonar.server.ws.WsTester.Result;
 
 import java.util.List;
 
@@ -498,6 +499,40 @@ public class SearchActionComponentsMediumTest {
       .assertJson(this.getClass(), "search_by_developer.json", false);
   }
 
+  @Test
+  public void search_by_developer_technical_project() throws Exception {
+    ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject"));
+    setDefaultProjectPermission(project);
+    ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent"));
+
+    ComponentDto otherProject = insertComponent(ComponentTesting.newProjectDto("XXXX").setKey("OtherProject"));
+    setDefaultProjectPermission(otherProject);
+    ComponentDto otherFile = insertComponent(ComponentTesting.newFileDto(otherProject, "YYYY").setKey("OtherComponent"));
+
+    ComponentDto developer = insertComponent(ComponentTesting.newDeveloper("Anakin Skywalker"));
+    ComponentDto technicalProject = insertComponent(ComponentTesting.newDevProjectCopy("CDEF", project, developer));
+    insertComponent(ComponentTesting.newDevProjectCopy("DEFG", otherProject, developer));
+
+    db.authorDao().insertAuthor("vader", developer.getId());
+    db.authorDao().insertAuthor("anakin@skywalker.name", developer.getId());
+    RuleDto newRule = newRule();
+
+    IssueDto issue1 = IssueTesting.newDto(newRule, file, project).setAuthorLogin("vader").setKee("2bd4eac2-b650-4037-80bc-7b112bd4eac2");
+    IssueDto issue2 = IssueTesting.newDto(newRule, file, project).setAuthorLogin("anakin@skywalker.name").setKee("82fd47d4-b650-4037-80bc-7b1182fd47d4");
+    IssueDto issueX = IssueTesting.newDto(newRule, otherFile, otherProject).setAuthorLogin("anakin@skywalker.name").setKee("82fd47d4-b650-4037-7b11-80bc82fd47d4");
+
+    db.issueDao().insert(session, issue1, issue2, issueX);
+    session.commit();
+    tester.get(IssueIndexer.class).indexAll();
+
+    Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.COMPONENT_UUIDS, technicalProject.uuid())
+      .execute();
+    System.out.println(result.outputAsString());
+    result
+      .assertJson(this.getClass(), "search_by_developer.json", false);
+  }
+
   private RuleDto newRule() {
     RuleDto rule = RuleTesting.newXooX1()
       .setName("Rule name")
index d8b3fcdfe0a5ee96250590203be2e451af73d7f3..2547c1eb70781320a5154d4f92cddc607314331a 100644 (file)
             description="the description" long_name="Disabled project"
             enabled="[false]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="123456789" />
 
+  <!-- Developer and technical project copy -->
+  <projects id="11" root_id="[null]" scope="PRJ" qualifier="DEV" kee="DEV:anakin@skywalker.name" name="Anakin Skywalker"
+            uuid="OPQR" project_uuid="OPQR" module_uuid="[null]" module_uuid_path=".OPQR."
+            description="the description" long_name="Anakin Skywalker"
+            enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="123456789" />
+  <projects id="12" project_id="11" root_id="11" scope="PRJ" qualifier="DEV_PRJ" kee="DEV:anakin@skywalker.name:org.struts:struts" name="Apache Struts"
+            uuid="STUV" project_uuid="OPQR" module_uuid="OPQR" module_uuid_path=".OPQR."
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="[null]" copy_resource_id="1" person_id="11" path="[null]" authorization_updated_at="123456789" />
+
 </dataset>
index 45d8372c00bb2515d8ec7e952e8df1757a5775c8..70b0af093df84620a4b9e075d19cf353c12deda8 100644 (file)
             description="the description" long_name="Disabled project"
             enabled="[false]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="123456789" />
 
+  <!-- Developer and technical project copy -->
+  <projects id="11" root_id="[null]" scope="PRJ" qualifier="DEV" kee="DEV:anakin@skywalker.name" name="Anakin Skywalker"
+            uuid="OPQR" project_uuid="OPQR" module_uuid="[null]" module_uuid_path=".OPQR."
+            description="the description" long_name="Anakin Skywalker"
+            enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="123456789" />
+  <projects id="12" project_id="11" root_id="11" scope="PRJ" qualifier="DEV_PRJ" kee="DEV:anakin@skywalker.name:org.struts:struts" name="Apache Struts"
+            uuid="STUV" project_uuid="OPQR" module_uuid="OPQR" module_uuid_path=".OPQR."
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="[null]" copy_resource_id="1" person_id="11" path="[null]" authorization_updated_at="123456789" />
+
 </dataset>
index e48052debb589253538ff1392d6efede9163cc93..547092e5076dd44611b27a856fdeb29acb37777a 100644 (file)
@@ -18,6 +18,7 @@
     p.root_id as parentProjectId,
     p.path as path,
     p.enabled as enabled,
+    p.copy_resource_id as copyResourceId,
     p.authorization_updated_at as authorizationUpdatedAt,
     p.created_at as createdAt
   </sql>