From 2877ce0c94684aa5aeb37df18e584111a12f254b Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Lievremont Date: Mon, 23 Feb 2015 17:27:50 +0100 Subject: [PATCH] SONAR-6075 Add ability to search issues on developer technical project copy --- .../sonar/server/issue/IssueQueryService.java | 82 ++++++++++++++----- .../server/component/ComponentTesting.java | 14 ++++ .../server/component/db/ComponentDaoTest.java | 22 +++++ .../server/issue/IssueQueryServiceTest.java | 25 ++++++ .../ws/SearchActionComponentsMediumTest.java | 35 ++++++++ .../db/ComponentDaoTest/delete-result.xml | 10 +++ .../component/db/ComponentDaoTest/shared.xml | 10 +++ .../core/component/db/ComponentMapper.xml | 1 + 8 files changed, 179 insertions(+), 20 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java index ea8b19c55bb..9eb2a6277d6 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java @@ -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 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 actualAuthors = authors == null ? dbClient.authorDao().selectScmAccountsByDeveloperUuids(session, componentUuids) : authors; + Collection 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 directoryModuleUuids = Sets.newHashSet(); - Collection 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 componentUuids, String uniqueQualifier) { + List 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 componentUuids, Collection authors) { + Collection technicalProjects = dbClient.componentDao().getByUuids(session, componentUuids); + Collection developerUuids = Collections2.transform(technicalProjects, new Function() { + @Override + public String apply(ComponentDto input) { + return input.projectUuid(); + } + }); + Collection authorsFromProjects = authorsFromParamsOrFromDeveloper(session, developerUuids, authors); + builder.authors(authorsFromProjects); + Collection projectIds = Collections2.transform(technicalProjects, new Function() { + @Override + public Long apply(ComponentDto input) { + return input.getCopyResourceId(); + } + }); + List originalProjects = dbClient.componentDao().getByIds(session, projectIds); + Collection projectUuids = Collections2.transform(originalProjects, new Function() { + @Override + public String apply(ComponentDto input) { + return input.uuid(); + } + }); + builder.projectUuids(projectUuids); + } + + private Collection authorsFromParamsOrFromDeveloper(DbSession session, Collection componentUuids, Collection authors) { + return authors == null ? dbClient.authorDao().selectScmAccountsByDeveloperUuids(session, componentUuids) : authors; + } + + private void addDirectories(IssueQuery.Builder builder, DbSession session, Collection componentUuids) { + Collection directoryModuleUuids = Sets.newHashSet(); + Collection 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 componentUuids(DbSession session, @Nullable Collection componentKeys) { Collection componentUuids = Lists.newArrayList(); componentUuids.addAll(componentService.componentUuids(session, componentKeys, true)); diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java index bcb34731db5..64ff8638acf 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java @@ -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); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java index fde5e2162b9..1c62b09058e 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java @@ -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 diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryServiceTest.java index 8ad75641895..1a301b8cc66 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryServiceTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryServiceTest.java @@ -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 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"; diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java index 5b3ed067794..b8d6c393b92 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java @@ -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") diff --git a/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/delete-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/delete-result.xml index d8b3fcdfe0a..2547c1eb707 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/delete-result.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/delete-result.xml @@ -81,4 +81,14 @@ description="the description" long_name="Disabled project" enabled="[false]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="123456789" /> + + + + diff --git a/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/shared.xml index 45d8372c00b..70b0af093df 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/shared.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/shared.xml @@ -82,4 +82,14 @@ description="the description" long_name="Disabled project" enabled="[false]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="123456789" /> + + + + diff --git a/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml b/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml index e48052debb5..547092e5076 100644 --- a/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml @@ -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 -- 2.39.5