Browse Source

SONAR-5531 Return sub projects in components list of issues search ws

tags/5.0-RC1
Julien Lancelot 9 years ago
parent
commit
e38085cd20

+ 26
- 0
server/sonar-server/src/main/java/org/sonar/server/component/db/ComponentDao.java View File

@@ -19,6 +19,7 @@
*/
package org.sonar.server.component.db;

import com.google.common.collect.Lists;
import org.sonar.api.ServerComponent;
import org.sonar.api.utils.System2;
import org.sonar.core.component.AuthorizedComponentDto;
@@ -31,8 +32,12 @@ import org.sonar.server.exceptions.NotFoundException;

import javax.annotation.CheckForNull;

import java.util.Collection;
import java.util.Collections;
import java.util.List;

import static com.google.common.collect.Lists.newArrayList;

/**
* @since 4.3
*/
@@ -85,6 +90,27 @@ public class ComponentDao extends BaseDao<ComponentMapper, ComponentDto, String>
return mapper(session).findModulesByProject(projectKey);
}

public List<ComponentDto> findSubProjectsByComponentKeys(DbSession session, Collection<String> keys) {
return mapper(session).findSubProjectsByComponentKeys(keys);
}

public List<ComponentDto> getByIds(DbSession session, Collection<Long> ids) {
if (ids.isEmpty()) {
return Collections.emptyList();
}
List<ComponentDto> components = newArrayList();
List<List<Long>> partitionList = Lists.partition(newArrayList(ids), 1000);
for (List<Long> partition : partitionList) {
List<ComponentDto> dtos = mapper(session).findByIds(partition);
components.addAll(dtos);
}
return components;
}

protected List<ComponentDto> doGetByKeys(DbSession session, Collection<String> keys) {
return mapper(session).findByKeys(keys);
}

@CheckForNull
public AuthorizedComponentDto getNullableAuthorizedComponentById(Long id, DbSession session) {
return mapper(session).selectAuthorizedComponentById(id);

+ 19
- 20
server/sonar-server/src/main/java/org/sonar/server/db/BaseDao.java View File

@@ -22,6 +22,7 @@ package org.sonar.server.db;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.apache.ibatis.session.ResultContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -32,24 +33,16 @@ import org.sonar.core.persistence.Dto;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.search.DbSynchronizationHandler;
import org.sonar.server.search.IndexDefinition;
import org.sonar.server.search.action.DeleteKey;
import org.sonar.server.search.action.DeleteNestedItem;
import org.sonar.server.search.action.InsertDto;
import org.sonar.server.search.action.RefreshIndex;
import org.sonar.server.search.action.UpsertDto;
import org.sonar.server.search.action.UpsertNestedItem;
import org.sonar.server.search.action.*;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.*;

import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;

/**
@@ -168,14 +161,20 @@ public abstract class BaseDao<MAPPER, DTO extends Dto<KEY>, KEY extends Serializ
}

public List<DTO> getByKeys(DbSession session, Collection<KEY> keys) {
List<DTO> results = new ArrayList<DTO>();
for (KEY key : keys) {
DTO result = this.getNullableByKey(session, key);
if (result != null) {
results.add(result);
}
if (keys.isEmpty()) {
return Collections.emptyList();
}
List<DTO> components = newArrayList();
List<List<KEY>> partitionList = Lists.partition(newArrayList(keys), 1000);
for (List<KEY> partition : partitionList) {
List<DTO> dtos = doGetByKeys(session, partition);
components.addAll(dtos);
}
return results;
return components;
}

protected List<DTO> doGetByKeys(DbSession session, Collection<KEY> keys) {
throw notImplemented(this);
}

@Override
@@ -348,7 +347,7 @@ public abstract class BaseDao<MAPPER, DTO extends Dto<KEY>, KEY extends Serializ
return getSynchronizationParams(date, Collections.<String, String>emptyMap());
}

protected Map getSynchronizationParams(Date date, Map<String, String> params) {
protected Map<String, Object> getSynchronizationParams(Date date, Map<String, String> params) {
Map<String, Object> finalParams = newHashMap();
finalParams.put("date", new Timestamp(date.getTime()));
return finalParams;

+ 1
- 0
server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java View File

@@ -143,6 +143,7 @@ public class DbClient implements ServerComponent {
public ComponentDao componentDao() {
return componentDao;
}

public SnapshotDao snapshotDao() {
return snapshotDao;
}

+ 7
- 1
server/sonar-server/src/main/java/org/sonar/server/issue/db/IssueDao.java View File

@@ -29,7 +29,9 @@ import org.sonar.core.persistence.DbSession;
import org.sonar.server.db.BaseDao;
import org.sonar.server.search.IndexDefinition;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class IssueDao extends BaseDao<IssueMapper, IssueDto, String> implements DaoComponent {
@@ -50,6 +52,10 @@ public class IssueDao extends BaseDao<IssueMapper, IssueDto, String> implements
return mapper(session).selectByKey(key);
}

protected List<IssueDto> doGetByKeys(DbSession session, Collection<String> keys) {
return mapper(session).selectByKeys(keys);
}

@Override
protected IssueDto doUpdate(DbSession session, IssueDto issue) {
mapper(session).update(issue);
@@ -70,7 +76,7 @@ public class IssueDao extends BaseDao<IssueMapper, IssueDto, String> implements
}

@Override
protected Map getSynchronizationParams(Date date, Map<String, String> params) {
protected Map<String, Object> getSynchronizationParams(Date date, Map<String, String> params) {
Map<String, Object> finalParams = super.getSynchronizationParams(date, params);
finalParams.put(PROJECT_KEY, params.get(PROJECT_KEY));
return finalParams;

+ 4
- 0
server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java View File

@@ -234,6 +234,7 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
Set<RuleKey> ruleKeys = newHashSet();
Set<String> projectKeys = newHashSet();
Set<String> componentKeys = newHashSet();
Set<Long> componentIds = newHashSet();
Set<String> actionPlanKeys = newHashSet();
List<String> userLogins = newArrayList();
Map<String, User> usersByLogin = newHashMap();
@@ -244,6 +245,7 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
ruleKeys.add(issue.ruleKey());
projectKeys.add(issue.projectKey());
componentKeys.add(issue.componentKey());
// componentIds.add(issue.com());
actionPlanKeys.add(issue.actionPlanKey());
if (issue.reporter() != null) {
userLogins.add(issue.reporter());
@@ -263,8 +265,10 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
usersByLogin = getUsersByLogin(session, userLogins);

List<ComponentDto> componentDtos = dbClient.componentDao().getByKeys(session, componentKeys);
List<ComponentDto> subProjectDtos = dbClient.componentDao().findSubProjectsByComponentKeys(session, componentKeys);
List<ComponentDto> projectDtos = dbClient.componentDao().getByKeys(session, projectKeys);

componentDtos.addAll(subProjectDtos);
componentDtos.addAll(projectDtos);
writeProjects(json, projectDtos);
writeComponents(json, componentDtos);

+ 78
- 0
server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java View File

@@ -33,6 +33,7 @@ import org.sonar.server.exceptions.NotFoundException;
import java.util.Date;
import java.util.List;

import static com.google.common.collect.Lists.newArrayList;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -94,6 +95,50 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
assertThat(result.getAuthorizationUpdatedAt()).isEqualTo(DateUtils.parseDate("2014-06-18"));
}

@Test
public void find_by_keys() {
setupData("shared");

List<ComponentDto> results = dao.getByKeys(session, "org.struts:struts-core:src/org/struts/RequestContext.java");
assertThat(results).hasSize(1);

ComponentDto result = results.get(0);
assertThat(result).isNotNull();
assertThat(result.key()).isEqualTo("org.struts:struts-core:src/org/struts/RequestContext.java");
assertThat(result.path()).isEqualTo("src/org/struts/RequestContext.java");
assertThat(result.name()).isEqualTo("RequestContext.java");
assertThat(result.longName()).isEqualTo("org.struts.RequestContext");
assertThat(result.qualifier()).isEqualTo("FIL");
assertThat(result.scope()).isEqualTo("FIL");
assertThat(result.language()).isEqualTo("java");
assertThat(result.subProjectId()).isEqualTo(2);
assertThat(result.projectId()).isEqualTo(1);

assertThat(dao.getByKeys(session, "unknown")).isEmpty();
}

@Test
public void find_by_ids() {
setupData("shared");

List<ComponentDto> results = dao.getByIds(session, newArrayList(4L));
assertThat(results).hasSize(1);

ComponentDto result = results.get(0);
assertThat(result).isNotNull();
assertThat(result.key()).isEqualTo("org.struts:struts-core:src/org/struts/RequestContext.java");
assertThat(result.path()).isEqualTo("src/org/struts/RequestContext.java");
assertThat(result.name()).isEqualTo("RequestContext.java");
assertThat(result.longName()).isEqualTo("org.struts.RequestContext");
assertThat(result.qualifier()).isEqualTo("FIL");
assertThat(result.scope()).isEqualTo("FIL");
assertThat(result.language()).isEqualTo("java");
assertThat(result.subProjectId()).isEqualTo(2);
assertThat(result.projectId()).isEqualTo(1);

assertThat(dao.getByIds(session, newArrayList(123L))).isEmpty();
}

@Test
public void get_by_id() {
setupData("shared");
@@ -181,6 +226,39 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
assertThat(dao.getParentModuleByKey("unknown", session)).isNull();
}

@Test
public void find_sub_projects_by_component_keys() throws Exception {
setupData("multi-modules");

// Sub project of a file
List<ComponentDto> results = dao.findSubProjectsByComponentKeys(session, newArrayList("org.struts:struts-core:src/org/struts/RequestContext.java"));
assertThat(results).hasSize(1);
assertThat(results.get(0).getKey()).isEqualTo("org.struts:struts-data");

// Sub project of a directory
results = dao.findSubProjectsByComponentKeys(session, newArrayList("org.struts:struts-core:src/org/struts"));
assertThat(results).hasSize(1);
assertThat(results.get(0).getKey()).isEqualTo("org.struts:struts-data");

// Sub project of a sub module
results = dao.findSubProjectsByComponentKeys(session, newArrayList("org.struts:struts-data"));
assertThat(results).hasSize(1);
assertThat(results.get(0).getKey()).isEqualTo("org.struts:struts");

// Sub project of a module
results = dao.findSubProjectsByComponentKeys(session, newArrayList("org.struts:struts-core"));
assertThat(results).hasSize(1);
assertThat(results.get(0).getKey()).isEqualTo("org.struts:struts");

// Sub project of a project
assertThat(dao.findSubProjectsByComponentKeys(session, newArrayList("org.struts:struts"))).isEmpty();

// SUb projects of a component and a sub module
assertThat(dao.findSubProjectsByComponentKeys(session, newArrayList("org.struts:struts-core:src/org/struts/RequestContext.java", "org.struts:struts-data"))).hasSize(2);

assertThat(dao.findSubProjectsByComponentKeys(session, newArrayList("unknown"))).isEmpty();
}

@Test
public void get_nullable_authorized_component_by_id() {
setupData("shared");

+ 38
- 0
server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueDaoTest.java View File

@@ -33,6 +33,7 @@ import org.sonar.core.persistence.DbSession;
import org.sonar.server.rule.RuleTesting;

import java.util.Date;
import java.util.List;

import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@@ -90,6 +91,43 @@ public class IssueDaoTest extends AbstractDaoTestCase {
assertThat(issue.getRootComponentKey()).isEqualTo("struts");
}

@Test
public void get_by_keys() {
setupData("shared", "get_by_key");

List<IssueDto> issues = dao.getByKeys(session, "ABCDE");
assertThat(issues).hasSize(1);

IssueDto issue = issues.get(0);
assertThat(issue.getKee()).isEqualTo("ABCDE");
assertThat(issue.getId()).isEqualTo(100L);
assertThat(issue.getComponentId()).isEqualTo(401);
assertThat(issue.getRootComponentId()).isEqualTo(399);
assertThat(issue.getRuleId()).isEqualTo(500);
assertThat(issue.getLanguage()).isEqualTo("java");
assertThat(issue.getSeverity()).isEqualTo("BLOCKER");
assertThat(issue.isManualSeverity()).isFalse();
assertThat(issue.getMessage()).isNull();
assertThat(issue.getLine()).isEqualTo(200);
assertThat(issue.getEffortToFix()).isEqualTo(4.2);
assertThat(issue.getStatus()).isEqualTo("OPEN");
assertThat(issue.getResolution()).isEqualTo("FIXED");
assertThat(issue.getChecksum()).isEqualTo("XXX");
assertThat(issue.getAuthorLogin()).isEqualTo("karadoc");
assertThat(issue.getReporter()).isEqualTo("arthur");
assertThat(issue.getAssignee()).isEqualTo("perceval");
assertThat(issue.getIssueAttributes()).isEqualTo("JIRA=FOO-1234");
assertThat(issue.getIssueCreationDate()).isNotNull();
assertThat(issue.getIssueUpdateDate()).isNotNull();
assertThat(issue.getIssueCloseDate()).isNotNull();
assertThat(issue.getCreatedAt()).isNotNull();
assertThat(issue.getUpdatedAt()).isNotNull();
assertThat(issue.getRuleRepo()).isEqualTo("squid");
assertThat(issue.getRule()).isEqualTo("AvoidCycle");
assertThat(issue.getComponentKey()).isEqualTo("Action.java");
assertThat(issue.getRootComponentKey()).isEqualTo("struts");
}

@Test
public void find_after_dates() throws Exception {
setupData("shared", "some_issues");

+ 35
- 1
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java View File

@@ -91,7 +91,7 @@ public class SearchActionMediumTest {

file = new ComponentDto()
.setKey("MyComponent")
.setProjectId(project.getId());
.setSubProjectId(project.getId());
db.componentDao().insert(session, file);
db.snapshotDao().insert(session, SnapshotTesting.createForComponent(file));

@@ -233,6 +233,40 @@ public class SearchActionMediumTest {
result.assertJson(this.getClass(), "issue_with_extra_fields.json", false);
}

@Test
public void components_contains_sub_projects() throws Exception {
ComponentDto project = new ComponentDto()
.setKey("ProjectHavingModule")
.setScope("PRJ");
db.componentDao().insert(session, project);
db.snapshotDao().insert(session, SnapshotTesting.createForComponent(project));

// project can be seen by anyone
tester.get(PermissionFacade.class).insertGroupPermission(project.getId(), DefaultGroups.ANYONE, UserRole.USER, session);
db.issueAuthorizationDao().synchronizeAfter(session, new Date(0));

ComponentDto module = new ComponentDto()
.setKey("ModuleHavingFile")
.setScope("PRJ")
.setSubProjectId(project.getId());
db.componentDao().insert(session, module);
db.snapshotDao().insert(session, SnapshotTesting.createForComponent(module));

ComponentDto file = new ComponentDto()
.setKey("FileLinkedToModule")
.setScope("FIL")
.setSubProjectId(module.getId());
db.componentDao().insert(session, file);
db.snapshotDao().insert(session, SnapshotTesting.createForComponent(file));

IssueDto issue = IssueTesting.newDto(rule, file, project);
db.issueDao().insert(session, issue);
session.commit();

WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).execute();
result.assertJson(this.getClass(), "components_contains_sub_projects.json", false);
}

@Test
public void display_facets() throws Exception {
IssueDto issue = IssueTesting.newDto(rule, file, project)

+ 18
- 0
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/components_contains_sub_projects.json View File

@@ -0,0 +1,18 @@
{
"components": [
{
"key": "FileLinkedToModule"
},
{
"key": "ModuleHavingFile"
},
{
"key": "ProjectHavingModule"
}
],
"projects": [
{
"key": "ProjectHavingModule"
}
]
}

+ 3
- 1
sonar-core/src/main/java/org/sonar/core/component/ComponentDto.java View File

@@ -32,11 +32,13 @@ public class ComponentDto extends AuthorizedComponentDto implements Component {
private String name;
private String longName;
private String language;
private Long projectId;
private Long subProjectId;
private boolean enabled = true;
private Date authorizationUpdatedAt;

// Return by join for the moment
private Long projectId;

public ComponentDto setId(Long id) {
super.setId(id);
return this;

+ 10
- 0
sonar-core/src/main/java/org/sonar/core/component/db/ComponentMapper.java View File

@@ -25,6 +25,7 @@ import org.sonar.core.component.ComponentDto;

import javax.annotation.CheckForNull;

import java.util.Collection;
import java.util.List;

/**
@@ -49,6 +50,15 @@ public interface ComponentMapper {
*/
List<ComponentDto> findModulesByProject(@Param("projectKey") String projectKey);

/**
* Return sub project of component keys
*/
List<ComponentDto> findSubProjectsByComponentKeys(@Param("keys") Collection<String> keys);

List<ComponentDto> findByIds(@Param("ids") Collection<Long> ids);

List<ComponentDto> findByKeys(@Param("keys") Collection<String> keys);

long countById(long id);

@CheckForNull

+ 2
- 0
sonar-core/src/main/java/org/sonar/core/issue/db/IssueMapper.java View File

@@ -34,6 +34,8 @@ public interface IssueMapper {

IssueDto selectByKey(String key);

List<IssueDto> selectByKeys(Collection<String> keys);

/**
* Return a paginated list of authorized issue ids for a user.
* If the role is null, then the authorisation check is disabled.

+ 41
- 0
sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml View File

@@ -86,6 +86,47 @@
</where>
</select>

<select id="findByIds" 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 in
<foreach collection="ids" open="(" close=")" item="id" separator=",">
#{id}
</foreach>
</where>
</select>

<select id="findByKeys" 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 in
<foreach collection="keys" open="(" close=")" item="key" separator=",">
#{key}
</foreach>
</where>
</select>

<select id="findSubProjectsByComponentKeys" 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}
INNER JOIN projects child ON child.root_id=p.id AND child.enabled=${_true}
<where>
AND p.enabled=${_true}
AND p.scope='PRJ'
AND child.kee in
<foreach collection="keys" open="(" close=")" item="key" separator=",">
#{key}
</foreach>
</where>
</select>

<select id="selectAuthorizedComponentById" parameterType="long" resultType="AuthorizedComponent">
SELECT <include refid="authorizedComponentColumns"/>
FROM projects p

+ 13
- 0
sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml View File

@@ -204,6 +204,19 @@
</foreach>
</select>

<select id="selectByKeys" parameterType="map" resultType="Issue">
select
<include refid="issueColumns"/>
from issues i
inner join rules r on r.id=i.rule_id
inner join projects p on p.id=i.component_id
inner join projects root on root.id=i.root_component_id
where i.kee in
<foreach collection="list" open="(" close=")" item="key" separator=",">
#{key}
</foreach>
</select>

<select id="selectIssues" parameterType="map" resultType="Issue">
select
<include refid="issueColumns"/>

Loading…
Cancel
Save