@@ -35,6 +35,7 @@ import org.apache.ibatis.session.ResultHandler; | |||
import org.apache.ibatis.session.RowBounds; | |||
import org.sonar.api.resources.Qualifiers; | |||
import org.sonar.api.resources.Scopes; | |||
import org.sonar.core.util.stream.MoreCollectors; | |||
import org.sonar.db.Dao; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.RowNotFoundException; | |||
@@ -47,6 +48,7 @@ import static org.sonar.db.DaoDatabaseUtils.buildLikeValue; | |||
import static org.sonar.db.DatabaseUtils.executeLargeInputs; | |||
import static org.sonar.db.DatabaseUtils.executeLargeUpdates; | |||
import static org.sonar.db.WildcardPosition.BEFORE_AND_AFTER; | |||
import static org.sonar.db.component.ComponentDto.generateBranchKey; | |||
public class ComponentDao implements Dao { | |||
@@ -169,6 +171,11 @@ public class ComponentDao implements Dao { | |||
return executeLargeInputs(keys, mapper(session)::selectByKeys); | |||
} | |||
public List<ComponentDto> selectByKeysAndBranch(DbSession session, Collection<String> keys, String branch) { | |||
List<String> dbKeys = keys.stream().map(k -> generateBranchKey(k, branch)).collect(MoreCollectors.toList()); | |||
return executeLargeInputs(dbKeys, mapper(session)::selectByDbKeys); | |||
} | |||
public List<ComponentDto> selectComponentsHavingSameKeyOrderedById(DbSession session, String key) { | |||
return mapper(session).selectComponentsHavingSameKeyOrderedById(key); | |||
} | |||
@@ -215,7 +222,7 @@ public class ComponentDao implements Dao { | |||
} | |||
public java.util.Optional<ComponentDto> selectByKeyAndBranch(DbSession session, String key, String branch) { | |||
return java.util.Optional.ofNullable(mapper(session).selectByDbKey(ComponentDto.generateBranchKey(key, branch))); | |||
return java.util.Optional.ofNullable(mapper(session).selectByDbKey(generateBranchKey(key, branch))); | |||
} | |||
public List<UuidWithProjectUuidDto> selectAllViewsAndSubViews(DbSession session) { |
@@ -52,6 +52,8 @@ public interface ComponentMapper { | |||
List<ComponentDto> selectByKeys(@Param("keys") Collection<String> keys); | |||
List<ComponentDto> selectByDbKeys(@Param("keys") Collection<String> keys); | |||
List<ComponentDto> selectByIds(@Param("ids") Collection<Long> ids); | |||
List<ComponentDto> selectByUuids(@Param("uuids") Collection<String> uuids); |
@@ -89,6 +89,18 @@ | |||
</foreach> | |||
</select> | |||
<select id="selectByDbKeys" parameterType="String" resultType="Component"> | |||
select | |||
<include refid="componentColumns"/> | |||
from projects p | |||
where | |||
p.enabled=${_true} | |||
and p.kee in | |||
<foreach collection="keys" open="(" close=")" item="key" separator=","> | |||
#{key,jdbcType=VARCHAR} | |||
</foreach> | |||
</select> | |||
<select id="selectByIds" parameterType="long" resultType="Component"> | |||
select | |||
<include refid="componentColumns"/> |
@@ -249,6 +249,24 @@ public class ComponentDaoTest { | |||
assertThat(underTest.selectByKeys(dbSession, singletonList("unknown"))).isEmpty(); | |||
} | |||
@Test | |||
public void selectByKeysAndBranch() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch")); | |||
ComponentDto file1 = db.components().insertComponent(newFileDto(branch)); | |||
ComponentDto file2 = db.components().insertComponent(newFileDto(branch)); | |||
ComponentDto anotherBranch = db.components().insertProjectBranch(project, b -> b.setKey("another_branch")); | |||
ComponentDto fileOnAnotherBranch = db.components().insertComponent(newFileDto(anotherBranch)); | |||
assertThat(underTest.selectByKeysAndBranch(dbSession, asList(branch.getKey(), file1.getKey(), file2.getKey()), "my_branch")).extracting(ComponentDto::uuid) | |||
.containsExactlyInAnyOrder(branch.uuid(), file1.uuid(), file2.uuid()); | |||
assertThat(underTest.selectByKeysAndBranch(dbSession, asList(file1.getKey(), file2.getKey(), fileOnAnotherBranch.getKey()), "my_branch")).extracting(ComponentDto::uuid) | |||
.containsExactlyInAnyOrder(file1.uuid(), file2.uuid()); | |||
assertThat(underTest.selectByKeysAndBranch(dbSession, singletonList(fileOnAnotherBranch.getKey()), "my_branch")).isEmpty(); | |||
assertThat(underTest.selectByKeysAndBranch(dbSession, singletonList(file1.getKey()), "unknown")).isEmpty(); | |||
assertThat(underTest.selectByKeysAndBranch(dbSession, singletonList("unknown"), "my_branch")).isEmpty(); | |||
} | |||
@Test | |||
public void get_by_ids() { | |||
ComponentDto project1 = db.components().insertPrivateProject(); |
@@ -205,7 +205,7 @@ public class ComponentDbTester { | |||
public final ComponentDto insertProjectBranch(ComponentDto project, Consumer<BranchDto>... dtoPopulators) { | |||
String uuid = Uuids.createFast(); | |||
BranchDto branchDto = new BranchDto() | |||
.setKey(randomAlphanumeric(255)) | |||
.setKey("branch_" + randomAlphanumeric(248)) | |||
.setUuid(uuid) | |||
.setProjectUuid(project.uuid()) | |||
.setKeeType(BRANCH) |
@@ -81,6 +81,7 @@ public class IssueQuery { | |||
private final Boolean asc; | |||
private final String facetMode; | |||
private final String organizationUuid; | |||
private final String branchUuid; | |||
private final boolean checkAuthorization; | |||
private IssueQuery(Builder builder) { | |||
@@ -113,6 +114,7 @@ public class IssueQuery { | |||
this.checkAuthorization = builder.checkAuthorization; | |||
this.facetMode = builder.facetMode; | |||
this.organizationUuid = builder.organizationUuid; | |||
this.branchUuid = builder.branchUuid; | |||
} | |||
public Collection<String> issueKeys() { | |||
@@ -236,6 +238,11 @@ public class IssueQuery { | |||
return organizationUuid; | |||
} | |||
@CheckForNull | |||
public String branchUuid() { | |||
return branchUuid; | |||
} | |||
public String facetMode() { | |||
return facetMode; | |||
} | |||
@@ -279,6 +286,7 @@ public class IssueQuery { | |||
private boolean checkAuthorization = true; | |||
private String facetMode; | |||
private String organizationUuid; | |||
private String branchUuid; | |||
private Builder() { | |||
@@ -450,6 +458,11 @@ public class IssueQuery { | |||
this.organizationUuid = s; | |||
return this; | |||
} | |||
public Builder branchUuid(@Nullable String s) { | |||
this.branchUuid = s; | |||
return this; | |||
} | |||
} | |||
private static <T> Collection<T> defaultCollection(@Nullable Collection<T> c) { |
@@ -25,6 +25,7 @@ import com.google.common.base.Splitter; | |||
import com.google.common.base.Strings; | |||
import com.google.common.collect.Collections2; | |||
import com.google.common.collect.Lists; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.Collection; | |||
import java.util.Date; | |||
@@ -46,7 +47,6 @@ import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.server.ServerSide; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.core.util.stream.MoreCollectors; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
@@ -64,8 +64,10 @@ import static org.sonar.api.utils.DateUtils.longToDate; | |||
import static org.sonar.api.utils.DateUtils.parseDateOrDateTime; | |||
import static org.sonar.api.utils.DateUtils.parseEndingDateOrDateTime; | |||
import static org.sonar.api.utils.DateUtils.parseStartingDateOrDateTime; | |||
import static org.sonar.core.util.stream.MoreCollectors.toHashSet; | |||
import static org.sonar.core.util.stream.MoreCollectors.toList; | |||
import static org.sonar.core.util.stream.MoreCollectors.toSet; | |||
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; | |||
import static org.sonar.server.ws.WsUtils.checkFoundWithOptional; | |||
import static org.sonar.server.ws.WsUtils.checkRequest; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENTS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS; | |||
@@ -84,6 +86,9 @@ public class IssueQueryFactory { | |||
public static final String LOGIN_MYSELF = "__me__"; | |||
private static final String UNKNOWN = "<UNKNOWN>"; | |||
private static final ComponentDto UNKNOWN_COMPONENT = new ComponentDto().setUuid(UNKNOWN).setProjectUuid(UNKNOWN); | |||
private final DbClient dbClient; | |||
private final System2 system; | |||
private final UserSession userSession; | |||
@@ -113,30 +118,17 @@ public class IssueQueryFactory { | |||
.facetMode(request.getFacetMode()) | |||
.organizationUuid(convertOrganizationKeyToUuid(dbSession, request.getOrganization())); | |||
Set<String> allComponentUuids = new HashSet<>(); | |||
boolean effectiveOnComponentOnly = mergeDeprecatedComponentParameters(dbSession, | |||
request.getOnComponentOnly(), | |||
request.getComponents(), | |||
request.getComponentUuids(), | |||
request.getComponentKeys(), | |||
request.getComponentRootUuids(), | |||
request.getComponentRoots(), | |||
allComponentUuids); | |||
addComponentParameters(builder, dbSession, | |||
effectiveOnComponentOnly, | |||
allComponentUuids, | |||
request); | |||
builder.createdAfter(buildCreatedAfterFromRequest(dbSession, request, allComponentUuids)); | |||
List<ComponentDto> allComponents = new ArrayList<>(); | |||
boolean effectiveOnComponentOnly = mergeDeprecatedComponentParameters(dbSession, request, allComponents); | |||
addComponentParameters(builder, dbSession, effectiveOnComponentOnly, allComponents, request); | |||
builder.createdAfter(buildCreatedAfterFromRequest(dbSession, request, allComponents)); | |||
String sort = request.getSort(); | |||
if (!Strings.isNullOrEmpty(sort)) { | |||
builder.sort(sort); | |||
builder.asc(request.getAsc()); | |||
} | |||
return builder.build(); | |||
} | |||
} | |||
@@ -161,7 +153,7 @@ public class IssueQueryFactory { | |||
return organization.map(OrganizationDto::getUuid).orElse(UNKNOWN); | |||
} | |||
private Date buildCreatedAfterFromRequest(DbSession dbSession, SearchWsRequest request, Set<String> componentUuids) { | |||
private Date buildCreatedAfterFromRequest(DbSession dbSession, SearchWsRequest request, List<ComponentDto> componentUuids) { | |||
Date createdAfter = parseStartingDateOrDateTime(request.getCreatedAfter()); | |||
String createdInLast = request.getCreatedInLast(); | |||
@@ -170,16 +162,14 @@ public class IssueQueryFactory { | |||
} | |||
checkRequest(createdAfter == null, "Parameters '%s' and '%s' cannot be set simultaneously", PARAM_CREATED_AFTER, PARAM_SINCE_LEAK_PERIOD); | |||
checkArgument(componentUuids.size() == 1, "One and only one component must be provided when searching since leak period"); | |||
String uuid = componentUuids.iterator().next(); | |||
Date createdAfterFromSnapshot = findCreatedAfterFromComponentUuid(dbSession, uuid); | |||
ComponentDto component = componentUuids.iterator().next(); | |||
Date createdAfterFromSnapshot = findCreatedAfterFromComponentUuid(dbSession, component); | |||
return buildCreatedAfterFromDates(createdAfterFromSnapshot, createdInLast); | |||
} | |||
@CheckForNull | |||
private Date findCreatedAfterFromComponentUuid(DbSession dbSession, String uuid) { | |||
ComponentDto component = checkFoundWithOptional(dbClient.componentDao().selectByUuid(dbSession, uuid), "Component with id '%s' not found", uuid); | |||
private Date findCreatedAfterFromComponentUuid(DbSession dbSession, ComponentDto component) { | |||
Optional<SnapshotDto> snapshot = dbClient.snapshotDao().selectLastAnalysisByComponentUuid(dbSession, component.uuid()); | |||
return snapshot.map(s -> longToDate(s.getPeriodDate())).orElse(null); | |||
} | |||
@@ -200,13 +190,15 @@ public class IssueQueryFactory { | |||
return assignees; | |||
} | |||
private boolean mergeDeprecatedComponentParameters(DbSession session, @Nullable Boolean onComponentOnly, | |||
@Nullable Collection<String> components, | |||
@Nullable Collection<String> componentUuids, | |||
@Nullable Collection<String> componentKeys, | |||
@Nullable Collection<String> componentRootUuids, | |||
@Nullable Collection<String> componentRoots, | |||
Set<String> allComponentUuids) { | |||
private boolean mergeDeprecatedComponentParameters(DbSession session, SearchWsRequest request, List<ComponentDto> allComponents) { | |||
Boolean onComponentOnly = request.getOnComponentOnly(); | |||
Collection<String> components = request.getComponents(); | |||
Collection<String> componentUuids = request.getComponentUuids(); | |||
Collection<String> componentKeys = request.getComponentKeys(); | |||
Collection<String> componentRootUuids = request.getComponentRootUuids(); | |||
Collection<String> componentRoots = request.getComponentRoots(); | |||
String branch = request.getBranch(); | |||
boolean effectiveOnComponentOnly = false; | |||
checkArgument(atMostOneNonNullElement(components, componentUuids, componentKeys, componentRootUuids, componentRoots), | |||
@@ -214,19 +206,22 @@ public class IssueQueryFactory { | |||
PARAM_COMPONENT_KEYS, PARAM_COMPONENT_UUIDS, PARAM_COMPONENTS, PARAM_COMPONENT_ROOTS, PARAM_COMPONENT_UUIDS); | |||
if (componentRootUuids != null) { | |||
allComponentUuids.addAll(componentRootUuids); | |||
allComponents.addAll(getComponentsFromUuids(session, componentRootUuids)); | |||
effectiveOnComponentOnly = false; | |||
} else if (componentRoots != null) { | |||
allComponentUuids.addAll(convertComponentKeysToUuids(session, componentRoots)); | |||
allComponents.addAll(getComponentsFromKeys(session, componentRoots, branch)); | |||
effectiveOnComponentOnly = false; | |||
} else if (components != null) { | |||
allComponentUuids.addAll(convertComponentKeysToUuids(session, components)); | |||
allComponents.addAll(getComponentsFromKeys(session, components, branch)); | |||
effectiveOnComponentOnly = true; | |||
} else if (componentUuids != null) { | |||
allComponentUuids.addAll(componentUuids); | |||
allComponents.addAll(getComponentsFromUuids(session, componentUuids)); | |||
effectiveOnComponentOnly = BooleanUtils.isTrue(onComponentOnly); | |||
} else if (componentKeys != null) { | |||
allComponentUuids.addAll(convertComponentKeysToUuids(session, componentKeys)); | |||
allComponents.addAll(getComponentsFromKeys(session, componentKeys, branch)); | |||
effectiveOnComponentOnly = BooleanUtils.isTrue(onComponentOnly); | |||
} | |||
return effectiveOnComponentOnly; | |||
} | |||
@@ -236,14 +231,14 @@ public class IssueQueryFactory { | |||
.count() <= 1; | |||
} | |||
private void addComponentParameters(IssueQuery.Builder builder, DbSession session, | |||
boolean onComponentOnly, | |||
Collection<String> componentUuids, | |||
SearchWsRequest request) { | |||
private void addComponentParameters(IssueQuery.Builder builder, DbSession session, boolean onComponentOnly, | |||
List<ComponentDto> components, SearchWsRequest request) { | |||
String branch = request.getBranch(); | |||
builder.onComponentOnly(onComponentOnly); | |||
if (onComponentOnly) { | |||
builder.componentUuids(componentUuids); | |||
builder.componentUuids(components.stream().map(ComponentDto::uuid).collect(toList())); | |||
builder.branchUuid(branch == null ? null : components.get(0).projectUuid()); | |||
return; | |||
} | |||
@@ -254,64 +249,63 @@ public class IssueQueryFactory { | |||
if (projectUuids != null) { | |||
builder.projectUuids(projectUuids); | |||
} else if (projectKeys != null) { | |||
builder.projectUuids(convertComponentKeysToUuids(session, projectKeys)); | |||
List<ComponentDto> projects = getComponentsFromKeys(session, projectKeys, branch); | |||
builder.projectUuids(projects.stream().map(p -> branch == null ? p.projectUuid() : p.getMainBranchProjectUuid()).collect(toList())); | |||
builder.branchUuid(branch == null ? null : projects.get(0).projectUuid()); | |||
} | |||
builder.moduleUuids(request.getModuleUuids()); | |||
builder.directories(request.getDirectories()); | |||
builder.fileUuids(request.getFileUuids()); | |||
if (!componentUuids.isEmpty()) { | |||
addComponentsBasedOnQualifier(builder, session, componentUuids, request); | |||
} | |||
addComponentsBasedOnQualifier(builder, session, components, request); | |||
} | |||
private void addComponentsBasedOnQualifier(IssueQuery.Builder builder, DbSession dbSession, Collection<String> componentUuids, SearchWsRequest request) { | |||
if (componentUuids.isEmpty()) { | |||
builder.componentUuids(componentUuids); | |||
private void addComponentsBasedOnQualifier(IssueQuery.Builder builder, DbSession dbSession, List<ComponentDto> components, SearchWsRequest request) { | |||
if (components.isEmpty()) { | |||
return; | |||
} | |||
List<ComponentDto> components = dbClient.componentDao().selectByUuids(dbSession, componentUuids); | |||
if (components.isEmpty()) { | |||
builder.componentUuids(componentUuids); | |||
if (components.stream().map(ComponentDto::uuid).anyMatch(uuid -> uuid.equals(UNKNOWN))) { | |||
builder.componentUuids(singleton(UNKNOWN)); | |||
return; | |||
} | |||
Set<String> qualifiers = components.stream().map(ComponentDto::qualifier).collect(MoreCollectors.toHashSet()); | |||
Set<String> qualifiers = components.stream().map(ComponentDto::qualifier).collect(toHashSet()); | |||
checkArgument(qualifiers.size() == 1, "All components must have the same qualifier, found %s", String.join(",", qualifiers)); | |||
String branch = request.getBranch(); | |||
builder.branchUuid(branch == null ? null : components.get(0).projectUuid()); | |||
String qualifier = qualifiers.iterator().next(); | |||
switch (qualifier) { | |||
case Qualifiers.VIEW: | |||
case Qualifiers.SUBVIEW: | |||
addViewsOrSubViews(builder, componentUuids); | |||
addViewsOrSubViews(builder, components); | |||
break; | |||
case Qualifiers.APP: | |||
addApplications(builder, dbSession, components, request); | |||
break; | |||
case Qualifiers.PROJECT: | |||
builder.projectUuids(componentUuids); | |||
builder.projectUuids(components.stream().map(c -> branch == null ? c.projectUuid() : c.getMainBranchProjectUuid()).collect(toList())); | |||
break; | |||
case Qualifiers.MODULE: | |||
builder.moduleRootUuids(componentUuids); | |||
builder.moduleRootUuids(components.stream().map(ComponentDto::uuid).collect(toList())); | |||
break; | |||
case Qualifiers.DIRECTORY: | |||
addDirectories(builder, components); | |||
break; | |||
case Qualifiers.FILE: | |||
case Qualifiers.UNIT_TEST_FILE: | |||
builder.fileUuids(componentUuids); | |||
builder.fileUuids(components.stream().map(ComponentDto::uuid).collect(toList())); | |||
break; | |||
default: | |||
throw new IllegalArgumentException("Unable to set search root context for components " + Joiner.on(',').join(componentUuids)); | |||
throw new IllegalArgumentException("Unable to set search root context for components " + Joiner.on(',').join(components)); | |||
} | |||
} | |||
private void addViewsOrSubViews(IssueQuery.Builder builder, Collection<String> viewOrSubViewUuids) { | |||
private void addViewsOrSubViews(IssueQuery.Builder builder, Collection<ComponentDto> viewOrSubViewUuids) { | |||
List<String> filteredViewUuids = viewOrSubViewUuids.stream() | |||
.filter(uuid -> userSession.hasComponentUuidPermission(UserRole.USER, uuid)) | |||
.filter(uuid -> userSession.hasComponentPermission(UserRole.USER, uuid)) | |||
.map(ComponentDto::uuid) | |||
.collect(Collectors.toList()); | |||
if (filteredViewUuids.isEmpty()) { | |||
filteredViewUuids.add(UNKNOWN); | |||
} | |||
@@ -322,7 +316,7 @@ public class IssueQueryFactory { | |||
Set<String> authorizedApplicationUuids = applications.stream() | |||
.filter(app -> userSession.hasComponentPermission(UserRole.USER, app)) | |||
.map(ComponentDto::uuid) | |||
.collect(MoreCollectors.toSet()); | |||
.collect(toSet()); | |||
builder.viewUuids(authorizedApplicationUuids.isEmpty() ? singleton(UNKNOWN) : authorizedApplicationUuids); | |||
addCreatedAfterByProjects(builder, dbSession, request, authorizedApplicationUuids); | |||
@@ -335,7 +329,7 @@ public class IssueQueryFactory { | |||
Set<String> projectUuids = applicationUuids.stream() | |||
.flatMap(app -> dbClient.componentDao().selectProjectsFromView(dbSession, app, app).stream()) | |||
.collect(MoreCollectors.toSet()); | |||
.collect(toSet()); | |||
Map<String, Date> leakByProjects = dbClient.snapshotDao().selectLastAnalysesByRootComponentUuids(dbSession, projectUuids) | |||
.stream() | |||
@@ -355,14 +349,22 @@ public class IssueQueryFactory { | |||
builder.directories(directoryPaths); | |||
} | |||
private Collection<String> convertComponentKeysToUuids(DbSession dbSession, Collection<String> componentKeys) { | |||
List<String> componentUuids = dbClient.componentDao().selectByKeys(dbSession, componentKeys).stream().map(ComponentDto::uuid).collect(MoreCollectors.toList()); | |||
// If unknown components are given, but no components are found, then all issues will be returned, | |||
// so we add this hack in order to return no issue in this case. | |||
if (!componentKeys.isEmpty() && componentUuids.isEmpty()) { | |||
return singletonList(UNKNOWN); | |||
private List<ComponentDto> getComponentsFromKeys(DbSession dbSession, Collection<String> componentKeys, @Nullable String branch) { | |||
List<ComponentDto> componentDtos = branch == null | |||
? dbClient.componentDao().selectByKeys(dbSession, componentKeys) | |||
: dbClient.componentDao().selectByKeysAndBranch(dbSession, componentKeys, branch); | |||
if (!componentKeys.isEmpty() && componentDtos.isEmpty()) { | |||
return singletonList(UNKNOWN_COMPONENT); | |||
} | |||
return componentDtos; | |||
} | |||
private List<ComponentDto> getComponentsFromUuids(DbSession dbSession, Collection<String> componentUuids) { | |||
List<ComponentDto> componentDtos = dbClient.componentDao().selectByUuids(dbSession, componentUuids); | |||
if (!componentUuids.isEmpty() && componentDtos.isEmpty()) { | |||
return singletonList(UNKNOWN_COMPONENT); | |||
} | |||
return componentUuids; | |||
return componentDtos; | |||
} | |||
@VisibleForTesting |
@@ -76,8 +76,8 @@ import org.sonar.server.permission.index.AuthorizationTypeSupport; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonar.server.view.index.ViewIndexDefinition; | |||
import static com.google.common.base.Preconditions.checkState; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static com.google.common.base.Preconditions.checkState; | |||
import static java.lang.String.format; | |||
import static java.util.Collections.emptyList; | |||
import static org.elasticsearch.index.query.QueryBuilders.boolQuery; | |||
@@ -205,12 +205,15 @@ public class IssueIndex { | |||
QueryBuilder moduleFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, query.moduleUuids()); | |||
QueryBuilder directoryFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, query.directories()); | |||
QueryBuilder fileFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.fileUuids()); | |||
QueryBuilder branchFilter = createTermFilter(IssueIndexDefinition.FIELD_ISSUE_BRANCH_UUID, query.branchUuid()); | |||
filters.put("__is_main_branch", createTermFilter(IssueIndexDefinition.FIELD_ISSUE_IS_MAIN_BRANCH, Boolean.toString(query.branchUuid() == null))); | |||
if (BooleanUtils.isTrue(query.onComponentOnly())) { | |||
filters.put(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, componentFilter); | |||
} else { | |||
filters.put("__view", viewFilter); | |||
filters.put(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, projectFilter); | |||
filters.put(IssueIndexDefinition.FIELD_ISSUE_BRANCH_UUID, branchFilter); | |||
filters.put("__module", moduleRootFilter); | |||
filters.put(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, moduleFilter); | |||
filters.put(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, directoryFilter); |
@@ -57,6 +57,7 @@ import static java.lang.String.format; | |||
import static java.util.Collections.singletonList; | |||
import static org.sonar.api.utils.Paging.forPageIndex; | |||
import static org.sonar.server.es.SearchOptions.MAX_LIMIT; | |||
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001; | |||
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; | |||
import static org.sonar.server.ws.WsUtils.writeProtobuf; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.ACTION_SEARCH; | |||
@@ -71,6 +72,7 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ASC; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ASSIGNED; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ASSIGNEES; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_AUTHORS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_BRANCH; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENTS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_ROOTS; | |||
@@ -113,7 +115,7 @@ public class SearchAction implements IssuesWsAction { | |||
private final SearchResponseFormat searchResponseFormat; | |||
public SearchAction(UserSession userSession, IssueIndex issueIndex, IssueQueryFactory issueQueryFactory, | |||
SearchResponseLoader searchResponseLoader, SearchResponseFormat searchResponseFormat) { | |||
SearchResponseLoader searchResponseLoader, SearchResponseFormat searchResponseFormat) { | |||
this.userSession = userSession; | |||
this.issueIndex = issueIndex; | |||
this.issueQueryFactory = issueQueryFactory; | |||
@@ -288,6 +290,12 @@ public class SearchAction implements IssuesWsAction { | |||
.setInternal(true) | |||
.setExampleValue("bdd82933-3070-4903-9188-7d8749e8bb92"); | |||
action.createParam(PARAM_BRANCH) | |||
.setDescription("Branch key") | |||
.setExampleValue(KEY_BRANCH_EXAMPLE_001) | |||
.setInternal(true) | |||
.setSince("6.6"); | |||
action.createParam(PARAM_ORGANIZATION) | |||
.setDescription("Organization key") | |||
.setRequired(false) | |||
@@ -465,6 +473,7 @@ public class SearchAction implements IssuesWsAction { | |||
.setLanguages(request.paramAsStrings(PARAM_LANGUAGES)) | |||
.setModuleUuids(request.paramAsStrings(PARAM_MODULE_UUIDS)) | |||
.setOnComponentOnly(request.paramAsBoolean(PARAM_ON_COMPONENT_ONLY)) | |||
.setBranch(request.param(PARAM_BRANCH)) | |||
.setOrganization(request.param(PARAM_ORGANIZATION)) | |||
.setPage(request.mandatoryParamAsInt(Param.PAGE)) | |||
.setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE)) |
@@ -33,11 +33,13 @@ import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentTesting; | |||
import org.sonar.db.component.ResourceTypesRule; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.property.PropertyDto; | |||
import org.sonar.db.source.FileSourceDto; | |||
import org.sonar.scanner.protocol.input.FileData; | |||
import org.sonar.scanner.protocol.input.ProjectRepositories; | |||
import org.sonar.server.component.ComponentFinder; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
@@ -64,8 +66,8 @@ public class ProjectDataLoaderTest { | |||
private DbClient dbClient = db.getDbClient(); | |||
private DbSession dbSession = db.getSession(); | |||
private int uuidCounter = 0; | |||
private ProjectDataLoader underTest = new ProjectDataLoader(dbClient, userSession); | |||
private ResourceTypesRule resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT); | |||
private ProjectDataLoader underTest = new ProjectDataLoader(dbClient, userSession, new ComponentFinder(dbClient, resourceTypes)); | |||
@Test | |||
public void return_project_settings_with_global_scan_permission() { |
@@ -36,6 +36,25 @@ import static org.sonar.api.issue.Issue.STATUS_OPEN; | |||
public class IssueDocTesting { | |||
public static IssueDoc newDoc(ComponentDto componentDto) { | |||
return newDoc(Uuids.createFast(), componentDto); | |||
} | |||
public static IssueDoc newDoc(String key, ComponentDto componentDto) { | |||
String mainBranchProjectUuid = componentDto.getMainBranchProjectUuid(); | |||
return newDoc() | |||
.setKey(key) | |||
.setBranchUuid(componentDto.projectUuid()) | |||
.setComponentUuid(componentDto.uuid()) | |||
.setModuleUuid(!componentDto.scope().equals(Scopes.PROJECT) ? componentDto.moduleUuid() : componentDto.uuid()) | |||
.setModuleUuidPath(componentDto.moduleUuidPath()) | |||
.setProjectUuid(mainBranchProjectUuid == null ? componentDto.projectUuid() : mainBranchProjectUuid) | |||
.setOrganizationUuid(componentDto.getOrganizationUuid()) | |||
// File path make no sens on modules and projects | |||
.setFilePath(!componentDto.scope().equals(Scopes.PROJECT) ? componentDto.path() : null) | |||
.setIsMainBranch(mainBranchProjectUuid == null); | |||
} | |||
public static IssueDoc newDoc() { | |||
IssueDoc doc = new IssueDoc(Maps.<String, Object>newHashMap()); | |||
doc.setKey(Uuids.createFast()); | |||
@@ -60,16 +79,4 @@ public class IssueDocTesting { | |||
doc.setFuncCloseDate(null); | |||
return doc; | |||
} | |||
public static IssueDoc newDoc(String key, ComponentDto componentDto) { | |||
return newDoc() | |||
.setKey(key) | |||
.setComponentUuid(componentDto.uuid()) | |||
.setModuleUuid(!componentDto.scope().equals(Scopes.PROJECT) ? componentDto.moduleUuid() : componentDto.uuid()) | |||
.setModuleUuidPath(componentDto.moduleUuidPath()) | |||
.setProjectUuid(componentDto.projectUuid()) | |||
.setOrganizationUuid(componentDto.getOrganizationUuid()) | |||
// File path make no sens on modules and projects | |||
.setFilePath(!componentDto.scope().equals(Scopes.PROJECT) ? componentDto.path() : null); | |||
} | |||
} |
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.server.issue; | |||
import java.util.ArrayList; | |||
import java.util.Date; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
@@ -29,14 +30,12 @@ import org.sonar.api.utils.DateUtils; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentTesting; | |||
import org.sonar.db.component.SnapshotDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.server.exceptions.BadRequestException; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonarqube.ws.client.issue.SearchWsRequest; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
@@ -45,7 +44,11 @@ import static org.junit.Assert.fail; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.api.utils.DateUtils.addDays; | |||
import static org.sonar.db.component.ComponentTesting.newDirectory; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.db.component.ComponentTesting.newModuleDto; | |||
import static org.sonar.db.component.ComponentTesting.newProjectCopy; | |||
import static org.sonar.db.component.ComponentTesting.newSubView; | |||
public class IssueQueryFactoryTest { | |||
@@ -63,8 +66,8 @@ public class IssueQueryFactoryTest { | |||
public void create_from_parameters() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto project = db.components().insertPrivateProject(organization); | |||
ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project)); | |||
ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); | |||
ComponentDto module = db.components().insertComponent(newModuleDto(project)); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||
SearchWsRequest request = new SearchWsRequest() | |||
.setIssues(asList("anIssueKey")) | |||
@@ -133,6 +136,23 @@ public class IssueQueryFactoryTest { | |||
assertThat(query.componentUuids()).containsOnly("<UNKNOWN>"); | |||
} | |||
@Test | |||
public void query_without_any_parameter() { | |||
SearchWsRequest request = new SearchWsRequest(); | |||
IssueQuery query = underTest.create(request); | |||
assertThat(query.componentUuids()).isEmpty(); | |||
assertThat(query.projectUuids()).isEmpty(); | |||
assertThat(query.moduleUuids()).isEmpty(); | |||
assertThat(query.moduleRootUuids()).isEmpty(); | |||
assertThat(query.directories()).isEmpty(); | |||
assertThat(query.fileUuids()).isEmpty(); | |||
assertThat(query.viewUuids()).isEmpty(); | |||
assertThat(query.organizationUuid()).isNull(); | |||
assertThat(query.branchUuid()).isNull(); | |||
} | |||
@Test | |||
public void parse_list_of_rules() { | |||
assertThat(IssueQueryFactory.toRules(null)).isNull(); | |||
@@ -181,7 +201,7 @@ public class IssueQueryFactoryTest { | |||
@Test | |||
public void fail_if_componentRoots_references_components_with_different_qualifier() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||
SearchWsRequest request = new SearchWsRequest() | |||
.setComponentRoots(asList(project.getDbKey(), file.getDbKey())); | |||
@@ -234,18 +254,17 @@ public class IssueQueryFactoryTest { | |||
IssueQuery result = underTest.create(new SearchWsRequest() | |||
.setComponentUuids(singletonList(application.uuid())) | |||
.setSinceLeakPeriod(true) | |||
); | |||
.setSinceLeakPeriod(true)); | |||
assertThat(result.createdAfterByProjectUuids()).containsOnly( | |||
entry(project1.uuid(), new Date(analysis1.getPeriodDate()))); | |||
entry(project1.uuid(), new Date(analysis1.getPeriodDate()))); | |||
assertThat(result.viewUuids()).containsExactlyInAnyOrder(application.uuid()); | |||
} | |||
@Test | |||
public void return_empty_results_if_not_allowed_to_search_for_subview() { | |||
ComponentDto view = db.components().insertView(); | |||
ComponentDto subView = db.components().insertComponent(ComponentTesting.newSubView(view)); | |||
ComponentDto subView = db.components().insertComponent(newSubView(view)); | |||
SearchWsRequest request = new SearchWsRequest() | |||
.setComponentRootUuids(asList(subView.uuid())); | |||
@@ -282,7 +301,7 @@ public class IssueQueryFactoryTest { | |||
@Test | |||
public void should_search_in_tree_with_module_uuid() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project)); | |||
ComponentDto module = db.components().insertComponent(newModuleDto(project)); | |||
SearchWsRequest request = new SearchWsRequest() | |||
.setComponentUuids(asList(module.uuid())); | |||
@@ -294,7 +313,7 @@ public class IssueQueryFactoryTest { | |||
@Test | |||
public void param_componentUuids_enables_search_in_directory_tree() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto dir = db.components().insertComponent(ComponentTesting.newDirectory(project, "src/main/java/foo")); | |||
ComponentDto dir = db.components().insertComponent(newDirectory(project, "src/main/java/foo")); | |||
SearchWsRequest request = new SearchWsRequest() | |||
.setComponentUuids(asList(dir.uuid())); | |||
@@ -308,7 +327,7 @@ public class IssueQueryFactoryTest { | |||
@Test | |||
public void param_componentUuids_enables_search_by_file() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project)); | |||
SearchWsRequest request = new SearchWsRequest() | |||
.setComponentUuids(asList(file.uuid())); | |||
@@ -320,7 +339,7 @@ public class IssueQueryFactoryTest { | |||
@Test | |||
public void param_componentUuids_enables_search_by_test_file() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project).setQualifier(Qualifiers.UNIT_TEST_FILE)); | |||
ComponentDto file = db.components().insertComponent(newFileDto(project).setQualifier(Qualifiers.UNIT_TEST_FILE)); | |||
SearchWsRequest request = new SearchWsRequest() | |||
.setComponentUuids(asList(file.uuid())); | |||
@@ -329,6 +348,65 @@ public class IssueQueryFactoryTest { | |||
assertThat(query.fileUuids()).containsExactly(file.uuid()); | |||
} | |||
@Test | |||
public void search_issue_from_branch() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
assertThat(underTest.create(new SearchWsRequest() | |||
.setProjectKeys(singletonList(branch.getKey())) | |||
.setBranch(branch.getBranch()))) | |||
.extracting(IssueQuery::branchUuid, query -> new ArrayList<>(query.projectUuids())) | |||
.containsOnly(branch.uuid(), singletonList(project.uuid())); | |||
assertThat(underTest.create(new SearchWsRequest() | |||
.setComponentKeys(singletonList(branch.getKey())) | |||
.setBranch(branch.getBranch()))) | |||
.extracting(IssueQuery::branchUuid, query -> new ArrayList<>(query.projectUuids())) | |||
.containsOnly(branch.uuid(), singletonList(project.uuid())); | |||
} | |||
@Test | |||
public void search_file_issue_from_branch() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
ComponentDto file = db.components().insertComponent(newFileDto(branch)); | |||
assertThat(underTest.create(new SearchWsRequest() | |||
.setComponentKeys(singletonList(file.getKey())) | |||
.setBranch(branch.getBranch()))) | |||
.extracting(IssueQuery::branchUuid, query -> new ArrayList<>(query.fileUuids())) | |||
.containsOnly(branch.uuid(), singletonList(file.uuid())); | |||
assertThat(underTest.create(new SearchWsRequest() | |||
.setComponentKeys(singletonList(branch.getKey())) | |||
.setFileUuids(singletonList(file.uuid())) | |||
.setBranch(branch.getBranch()))) | |||
.extracting(IssueQuery::branchUuid, query -> new ArrayList<>(query.fileUuids())) | |||
.containsOnly(branch.uuid(), singletonList(file.uuid())); | |||
assertThat(underTest.create(new SearchWsRequest() | |||
.setProjectKeys(singletonList(branch.getKey())) | |||
.setFileUuids(singletonList(file.uuid())) | |||
.setBranch(branch.getBranch()))) | |||
.extracting(IssueQuery::branchUuid, query -> new ArrayList<>(query.fileUuids())) | |||
.containsOnly(branch.uuid(), singletonList(file.uuid())); | |||
} | |||
@Test | |||
public void search_issue_on_component_only_from_branch() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
ComponentDto file = db.components().insertComponent(newFileDto(branch)); | |||
assertThat(underTest.create(new SearchWsRequest() | |||
.setComponentKeys(singletonList(file.getKey())) | |||
.setBranch(branch.getBranch()) | |||
.setOnComponentOnly(true))) | |||
.extracting(IssueQuery::branchUuid, query -> new ArrayList<>(query.componentUuids())) | |||
.containsOnly(branch.uuid(), singletonList(file.uuid())); | |||
} | |||
@Test | |||
public void fail_if_created_after_and_created_since_are_both_set() { | |||
SearchWsRequest request = new SearchWsRequest() | |||
@@ -372,12 +450,15 @@ public class IssueQueryFactoryTest { | |||
@Test | |||
public void fail_if_several_components_provided_with_since_leak_period() { | |||
ComponentDto project1 = db.components().insertPrivateProject(); | |||
ComponentDto project2 = db.components().insertPrivateProject(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("One and only one component must be provided when searching since leak period"); | |||
underTest.create(new SearchWsRequest() | |||
.setSinceLeakPeriod(true) | |||
.setComponentUuids(newArrayList("foo", "bar"))); | |||
.setComponentKeys(asList(project1.getKey(), project2.getKey()))); | |||
} | |||
@Test |
@@ -48,6 +48,8 @@ public class IssueQueryTest { | |||
.languages(newArrayList("xoo")) | |||
.tags(newArrayList("tag1", "tag2")) | |||
.types(newArrayList("RELIABILITY", "SECURITY")) | |||
.organizationUuid("orga") | |||
.branchUuid("my_branch") | |||
.createdAfterByProjectUuids(ImmutableMap.of("PROJECT", new Date(10_000_000_000L))) | |||
.assigned(true) | |||
.createdAfter(new Date()) | |||
@@ -68,6 +70,8 @@ public class IssueQueryTest { | |||
assertThat(query.languages()).containsOnly("xoo"); | |||
assertThat(query.tags()).containsOnly("tag1", "tag2"); | |||
assertThat(query.types()).containsOnly("RELIABILITY", "SECURITY"); | |||
assertThat(query.organizationUuid()).isEqualTo("orga"); | |||
assertThat(query.branchUuid()).isEqualTo("my_branch"); | |||
assertThat(query.createdAfterByProjectUuids()).containsOnly(entry("PROJECT", new Date(10_000_000_000L))); | |||
assertThat(query.assigned()).isTrue(); | |||
assertThat(query.rules()).containsOnly(RuleKey.of("squid", "AvoidCycle")); | |||
@@ -151,6 +155,9 @@ public class IssueQueryTest { | |||
assertThat(query.severities()).isEmpty(); | |||
assertThat(query.languages()).isEmpty(); | |||
assertThat(query.tags()).isEmpty(); | |||
assertThat(query.types()).isEmpty(); | |||
assertThat(query.organizationUuid()).isNull(); | |||
assertThat(query.branchUuid()).isNull(); | |||
assertThat(query.assigned()).isNull(); | |||
assertThat(query.createdAfter()).isNull(); | |||
assertThat(query.createdBefore()).isNull(); |
@@ -74,6 +74,7 @@ import static org.sonar.api.utils.DateUtils.addDays; | |||
import static org.sonar.api.utils.DateUtils.parseDate; | |||
import static org.sonar.api.utils.DateUtils.parseDateTime; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.db.component.ComponentTesting.newModuleDto; | |||
import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; | |||
import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto; | |||
import static org.sonar.db.user.GroupTesting.newGroupDto; | |||
@@ -125,8 +126,8 @@ public class IssueIndexTest { | |||
@Test | |||
public void filter_by_projects() { | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(newOrganizationDto()); | |||
ComponentDto module = ComponentTesting.newModuleDto(project); | |||
ComponentDto subModule = ComponentTesting.newModuleDto(module); | |||
ComponentDto module = newModuleDto(project); | |||
ComponentDto subModule = newModuleDto(module); | |||
indexIssues( | |||
newDoc("I1", project), | |||
@@ -157,8 +158,8 @@ public class IssueIndexTest { | |||
@Test | |||
public void filter_by_modules() { | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(newOrganizationDto()); | |||
ComponentDto module = ComponentTesting.newModuleDto(project); | |||
ComponentDto subModule = ComponentTesting.newModuleDto(module); | |||
ComponentDto module = newModuleDto(project); | |||
ComponentDto subModule = newModuleDto(module); | |||
ComponentDto file = newFileDto(subModule, null); | |||
indexIssues( | |||
@@ -176,8 +177,8 @@ public class IssueIndexTest { | |||
@Test | |||
public void filter_by_components_on_contextualized_search() { | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(newOrganizationDto()); | |||
ComponentDto module = ComponentTesting.newModuleDto(project); | |||
ComponentDto subModule = ComponentTesting.newModuleDto(module); | |||
ComponentDto module = newModuleDto(project); | |||
ComponentDto subModule = newModuleDto(module); | |||
ComponentDto file1 = newFileDto(project, null); | |||
ComponentDto file2 = newFileDto(module, null); | |||
ComponentDto file3 = newFileDto(subModule, null); | |||
@@ -205,9 +206,9 @@ public class IssueIndexTest { | |||
public void filter_by_components_on_non_contextualized_search() { | |||
ComponentDto project = newPrivateProjectDto(newOrganizationDto(), "project"); | |||
ComponentDto file1 = newFileDto(project, null, "file1"); | |||
ComponentDto module = ComponentTesting.newModuleDto(project).setUuid("module"); | |||
ComponentDto module = newModuleDto(project).setUuid("module"); | |||
ComponentDto file2 = newFileDto(module, null, "file2"); | |||
ComponentDto subModule = ComponentTesting.newModuleDto(module).setUuid("subModule"); | |||
ComponentDto subModule = newModuleDto(module).setUuid("subModule"); | |||
ComponentDto file3 = newFileDto(subModule, null, "file3"); | |||
String view = "ABCD"; | |||
indexView(view, asList(project.uuid())); | |||
@@ -318,39 +319,90 @@ public class IssueIndexTest { | |||
Date now = new Date(); | |||
OrganizationDto organizationDto = newOrganizationDto(); | |||
ComponentDto project1 = newPrivateProjectDto(organizationDto); | |||
IssueDoc project1Issue1 = newDoc().setProjectUuid(project1.uuid()).setFuncCreationDate(addDays(now, -10)); | |||
IssueDoc project1Issue2 = newDoc().setProjectUuid(project1.uuid()).setFuncCreationDate(addDays(now, -20)); | |||
IssueDoc project1Issue1 = newDoc(project1).setFuncCreationDate(addDays(now, -10)); | |||
IssueDoc project1Issue2 = newDoc(project1).setFuncCreationDate(addDays(now, -20)); | |||
ComponentDto project2 = newPrivateProjectDto(organizationDto); | |||
IssueDoc project2Issue1 = newDoc().setProjectUuid(project2.uuid()).setFuncCreationDate(addDays(now, -15)); | |||
IssueDoc project2Issue2 = newDoc().setProjectUuid(project2.uuid()).setFuncCreationDate(addDays(now, -30)); | |||
IssueDoc project2Issue1 = newDoc(project2).setFuncCreationDate(addDays(now, -15)); | |||
IssueDoc project2Issue2 = newDoc(project2).setFuncCreationDate(addDays(now, -30)); | |||
indexIssues(project1Issue1, project1Issue2, project2Issue1, project2Issue2); | |||
// Search for issues of project 1 having less than 15 days | |||
assertThatSearchReturnsOnly(IssueQuery.builder() | |||
.createdAfterByProjectUuids(ImmutableMap.of(project1.uuid(), addDays(now, -15))), | |||
.createdAfterByProjectUuids(ImmutableMap.of(project1.uuid(), addDays(now, -15))), | |||
project1Issue1.key()); | |||
// Search for issues of project 1 having less than 14 days and project 2 having less then 25 days | |||
assertThatSearchReturnsOnly(IssueQuery.builder() | |||
.createdAfterByProjectUuids(ImmutableMap.of( | |||
project1.uuid(), addDays(now, -14), | |||
project2.uuid(), addDays(now, -25) | |||
)), | |||
project2.uuid(), addDays(now, -25))), | |||
project1Issue1.key(), project2Issue1.key()); | |||
// Search for issues of project 1 having less than 30 days | |||
assertThatSearchReturnsOnly(IssueQuery.builder() | |||
.createdAfterByProjectUuids(ImmutableMap.of( | |||
project1.uuid(), addDays(now, -30) | |||
)), | |||
.createdAfterByProjectUuids(ImmutableMap.of( | |||
project1.uuid(), addDays(now, -30))), | |||
project1Issue1.key(), project1Issue2.key()); | |||
// Search for issues of project 1 and project 2 having less than 5 days | |||
assertThatSearchReturnsOnly(IssueQuery.builder() | |||
.createdAfterByProjectUuids(ImmutableMap.of( | |||
project1.uuid(), addDays(now, -5), | |||
project2.uuid(), addDays(now, -5) | |||
))); | |||
.createdAfterByProjectUuids(ImmutableMap.of( | |||
project1.uuid(), addDays(now, -5), | |||
project2.uuid(), addDays(now, -5)))); | |||
} | |||
@Test | |||
public void filter_one_issue_by_project_and_branch() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
ComponentDto anotherbBranch = db.components().insertProjectBranch(project); | |||
IssueDoc issueOnProject = newDoc(project); | |||
IssueDoc issueOnBranch = newDoc(branch); | |||
IssueDoc issueOnAnotherBranch = newDoc(anotherbBranch); | |||
indexIssues(issueOnProject, issueOnBranch, issueOnAnotherBranch); | |||
assertThatSearchReturnsOnly(IssueQuery.builder().branchUuid(branch.uuid()), issueOnBranch.key()); | |||
assertThatSearchReturnsOnly(IssueQuery.builder().componentUuids(singletonList(branch.uuid())).branchUuid(branch.uuid()), issueOnBranch.key()); | |||
assertThatSearchReturnsOnly(IssueQuery.builder().projectUuids(singletonList(project.uuid())).branchUuid(branch.uuid()), issueOnBranch.key()); | |||
assertThatSearchReturnsOnly(IssueQuery.builder().componentUuids(singletonList(branch.uuid())).projectUuids(singletonList(project.uuid())).branchUuid(branch.uuid()), | |||
issueOnBranch.key()); | |||
assertThatSearchReturnsEmpty(IssueQuery.builder().branchUuid("unknown")); | |||
} | |||
@Test | |||
public void issues_from_branch_component_children() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto projectModule = db.components().insertComponent(newModuleDto(project)); | |||
ComponentDto projectFile = db.components().insertComponent(newFileDto(projectModule)); | |||
ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch")); | |||
ComponentDto branchModule = db.components().insertComponent(newModuleDto(branch)); | |||
ComponentDto branchFile = db.components().insertComponent(newFileDto(branchModule)); | |||
indexIssues( | |||
newDoc("I1", project), | |||
newDoc("I2", projectFile), | |||
newDoc("I3", projectModule), | |||
newDoc("I4", branch), | |||
newDoc("I5", branchModule), | |||
newDoc("I6", branchFile)); | |||
assertThatSearchReturnsOnly(IssueQuery.builder().branchUuid(branch.uuid()), "I4", "I5", "I6"); | |||
assertThatSearchReturnsOnly(IssueQuery.builder().moduleUuids(singletonList(branchModule.uuid())).branchUuid(branch.uuid()), "I5", "I6"); | |||
assertThatSearchReturnsOnly(IssueQuery.builder().fileUuids(singletonList(branchFile.uuid())).branchUuid(branch.uuid()), "I6"); | |||
assertThatSearchReturnsEmpty(IssueQuery.builder().fileUuids(singletonList(branchFile.uuid())).branchUuid("unknown")); | |||
} | |||
@Test | |||
public void branch_issues_are_ignored_when_no_branch_param() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch")); | |||
IssueDoc projectIssue = newDoc(project); | |||
IssueDoc branchIssue = newDoc(branch); | |||
indexIssues(projectIssue, branchIssue); | |||
assertThatSearchReturnsOnly(IssueQuery.builder(), projectIssue.key()); | |||
} | |||
@Test |
@@ -462,7 +462,7 @@ public class IssueIndexerTest { | |||
assertThat(doc.getId()).isEqualTo(issue.getKey()); | |||
assertThat(doc.organizationUuid()).isEqualTo(organization.getUuid()); | |||
assertThat(doc.componentUuid()).isEqualTo(file.uuid()); | |||
assertThat(doc.projectUuid()).isEqualTo(project.uuid()); | |||
assertThat(doc.projectUuid()).isEqualTo(branch.getMainBranchProjectUuid()); | |||
assertThat(doc.branchUuid()).isEqualTo(branch.uuid()); | |||
assertThat(doc.isMainBranch()).isFalse(); | |||
} |
@@ -31,12 +31,14 @@ import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.utils.Durations; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.issue.IssueDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.rule.RuleDefinitionDto; | |||
import org.sonar.db.rule.RuleDefinitionDto; | |||
import org.sonar.server.es.EsTester; | |||
import org.sonar.server.issue.ActionFinder; | |||
import org.sonar.server.issue.IssueFieldsSetter; | |||
@@ -56,10 +58,13 @@ import org.sonar.server.view.index.ViewIndexer; | |||
import org.sonar.server.ws.WsActionTester; | |||
import org.sonar.server.ws.WsResponseCommonFormat; | |||
import org.sonarqube.ws.Issues.Component; | |||
import org.sonarqube.ws.Issues; | |||
import org.sonarqube.ws.Issues.Issue; | |||
import org.sonarqube.ws.Issues.SearchWsResponse; | |||
import org.sonarqube.ws.client.issue.IssuesWsParameters; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
import static java.util.Collections.emptySet; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.sonar.api.utils.DateUtils.addDays; | |||
@@ -72,6 +77,8 @@ import static org.sonar.db.component.ComponentTesting.newModuleDto; | |||
import static org.sonar.db.component.ComponentTesting.newProjectCopy; | |||
import static org.sonar.db.component.ComponentTesting.newSubView; | |||
import static org.sonar.db.component.ComponentTesting.newView; | |||
import static org.sonar.db.issue.IssueTesting.newIssue; | |||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BRANCH; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECT_KEYS; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SINCE_LEAK_PERIOD; | |||
@@ -100,6 +107,21 @@ public class SearchActionComponentsTest { | |||
private WsActionTester ws = new WsActionTester(new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat)); | |||
@Test | |||
public void search_all_issues_when_no_parameter() { | |||
RuleDefinitionDto rule = db.rules().insert(); | |||
ComponentDto project = db.components().insertPublicProject(); | |||
ComponentDto projectFile = db.components().insertComponent(newFileDto(project)); | |||
IssueDto issue = db.issues().insertIssue(newIssue(rule, project, projectFile)); | |||
allowAnyoneOnProjects(project); | |||
indexIssues(); | |||
SearchWsResponse result = ws.newRequest().executeProtobuf(SearchWsResponse.class); | |||
assertThat(result.getIssuesList()).extracting(Issues.Issue::getKey) | |||
.containsExactlyInAnyOrder(issue.getKey()); | |||
} | |||
@Test | |||
public void issues_on_different_projects() throws Exception { | |||
RuleDefinitionDto rule = db.rules().insert(r -> r.setRuleKey(RuleKey.of("xoo", "x1"))); | |||
@@ -525,8 +547,9 @@ public class SearchActionComponentsTest { | |||
ComponentDto application = db.components().insertApplication(db.getDefaultOrganization()); | |||
db.components().insertComponents(newProjectCopy("PC1", project1, application)); | |||
db.components().insertComponents(newProjectCopy("PC2", project2, application)); | |||
IssueDto issue1 = db.issues().insertIssue(i -> i.setProject(project1)); | |||
IssueDto issue2 = db.issues().insertIssue(i -> i.setProject(project2)); | |||
RuleDefinitionDto rule = db.rules().insert(); | |||
IssueDto issue1 = db.issues().insert(rule, project1, project1); | |||
IssueDto issue2 = db.issues().insert(rule, project2, project2); | |||
allowAnyoneOnProjects(project1, project2, application); | |||
indexIssuesAndViews(); | |||
@@ -543,7 +566,8 @@ public class SearchActionComponentsTest { | |||
ComponentDto project = db.components().insertPublicProject(); | |||
ComponentDto application = db.components().insertApplication(db.getDefaultOrganization()); | |||
db.components().insertComponents(newProjectCopy("PC1", project, application)); | |||
db.issues().insertIssue(i -> i.setProject(project)); | |||
RuleDefinitionDto rule = db.rules().insert(); | |||
db.issues().insert(rule, project, project); | |||
allowAnyoneOnProjects(project); | |||
indexIssuesAndViews(); | |||
@@ -558,7 +582,8 @@ public class SearchActionComponentsTest { | |||
public void search_application_without_projects() { | |||
ComponentDto project = db.components().insertPublicProject(); | |||
ComponentDto application = db.components().insertApplication(db.getDefaultOrganization()); | |||
db.issues().insertIssue(i -> i.setProject(project)); | |||
RuleDefinitionDto rule = db.rules().insert(); | |||
db.issues().insert(rule, project, project); | |||
allowAnyoneOnProjects(project, application); | |||
indexIssuesAndViews(); | |||
@@ -572,19 +597,20 @@ public class SearchActionComponentsTest { | |||
@Test | |||
public void search_by_application_and_by_leak() throws Exception { | |||
Date now = new Date(); | |||
RuleDefinitionDto rule = db.rules().insert(); | |||
ComponentDto application = db.components().insertApplication(db.getDefaultOrganization()); | |||
// Project 1 | |||
ComponentDto project1 = db.components().insertPublicProject(); | |||
db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime())); | |||
db.components().insertComponents(newProjectCopy("PC1", project1, application)); | |||
IssueDto project1Issue1 = db.issues().insertIssue(i -> i.setProject(project1).setIssueCreationDate(addDays(now, -10))); | |||
IssueDto project1Issue2 = db.issues().insertIssue(i -> i.setProject(project1).setIssueCreationDate(addDays(now, -20))); | |||
IssueDto project1Issue1 = db.issues().insert(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -10))); | |||
IssueDto project1Issue2 = db.issues().insert(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -20))); | |||
// Project 2 | |||
ComponentDto project2 = db.components().insertPublicProject(); | |||
db.components().insertSnapshot(project2, s -> s.setPeriodDate(addDays(now, -25).getTime())); | |||
db.components().insertComponents(newProjectCopy("PC2", project2, application)); | |||
IssueDto project2Issue1 = db.issues().insertIssue(i -> i.setProject(project2).setIssueCreationDate(addDays(now, -15))); | |||
IssueDto project2Issue2 = db.issues().insertIssue(i -> i.setProject(project2).setIssueCreationDate(addDays(now, -30))); | |||
IssueDto project2Issue1 = db.issues().insert(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -15))); | |||
IssueDto project2Issue2 = db.issues().insert(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -30))); | |||
// Permissions and index | |||
allowAnyoneOnProjects(project1, project2, application); | |||
indexIssuesAndViews(); | |||
@@ -606,8 +632,9 @@ public class SearchActionComponentsTest { | |||
ComponentDto application = db.components().insertApplication(db.getDefaultOrganization()); | |||
db.components().insertComponents(newProjectCopy("PC1", project1, application)); | |||
db.components().insertComponents(newProjectCopy("PC2", project2, application)); | |||
IssueDto issue1 = db.issues().insertIssue(i -> i.setProject(project1)); | |||
IssueDto issue2 = db.issues().insertIssue(i -> i.setProject(project2)); | |||
RuleDefinitionDto rule = db.rules().insert(); | |||
IssueDto issue1 = db.issues().insert(rule, project1, project1); | |||
IssueDto issue2 = db.issues().insert(rule, project2, project2); | |||
allowAnyoneOnProjects(project1, project2, application); | |||
indexIssuesAndViews(); | |||
@@ -624,19 +651,20 @@ public class SearchActionComponentsTest { | |||
@Test | |||
public void search_by_application_and_project_and_leak() throws Exception { | |||
Date now = new Date(); | |||
RuleDefinitionDto rule = db.rules().insert(); | |||
ComponentDto application = db.components().insertApplication(db.getDefaultOrganization()); | |||
// Project 1 | |||
ComponentDto project1 = db.components().insertPublicProject(); | |||
db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime())); | |||
db.components().insertComponents(newProjectCopy("PC1", project1, application)); | |||
IssueDto project1Issue1 = db.issues().insertIssue(i -> i.setProject(project1).setIssueCreationDate(addDays(now, -10))); | |||
IssueDto project1Issue2 = db.issues().insertIssue(i -> i.setProject(project1).setIssueCreationDate(addDays(now, -20))); | |||
IssueDto project1Issue1 = db.issues().insert(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -10))); | |||
IssueDto project1Issue2 = db.issues().insert(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -20))); | |||
// Project 2 | |||
ComponentDto project2 = db.components().insertPublicProject(); | |||
db.components().insertSnapshot(project2, s -> s.setPeriodDate(addDays(now, -25).getTime())); | |||
db.components().insertComponents(newProjectCopy("PC2", project2, application)); | |||
IssueDto project2Issue1 = db.issues().insertIssue(i -> i.setProject(project2).setIssueCreationDate(addDays(now, -15))); | |||
IssueDto project2Issue2 = db.issues().insertIssue(i -> i.setProject(project2).setIssueCreationDate(addDays(now, -30))); | |||
IssueDto project2Issue1 = db.issues().insert(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -15))); | |||
IssueDto project2Issue2 = db.issues().insert(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -30))); | |||
// Permissions and index | |||
allowAnyoneOnProjects(project1, project2, application); | |||
indexIssuesAndViews(); | |||
@@ -655,19 +683,20 @@ public class SearchActionComponentsTest { | |||
@Test | |||
public void search_by_application_and_by_leak_when_one_project_has_no_leak() throws Exception { | |||
Date now = new Date(); | |||
RuleDefinitionDto rule = db.rules().insert(); | |||
ComponentDto application = db.components().insertApplication(db.getDefaultOrganization()); | |||
// Project 1 | |||
ComponentDto project1 = db.components().insertPublicProject(); | |||
db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime())); | |||
db.components().insertComponents(newProjectCopy("PC1", project1, application)); | |||
IssueDto project1Issue1 = db.issues().insertIssue(i -> i.setProject(project1).setIssueCreationDate(addDays(now, -10))); | |||
IssueDto project1Issue2 = db.issues().insertIssue(i -> i.setProject(project1).setIssueCreationDate(addDays(now, -20))); | |||
IssueDto project1Issue1 = db.issues().insert(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -10))); | |||
IssueDto project1Issue2 = db.issues().insert(rule, project1, project1, i -> i.setIssueCreationDate(addDays(now, -20))); | |||
// Project 2, without leak => no issue form it should be returned | |||
ComponentDto project2 = db.components().insertPublicProject(); | |||
db.components().insertSnapshot(project2, s -> s.setPeriodDate(null)); | |||
db.components().insertComponents(newProjectCopy("PC2", project2, application)); | |||
IssueDto project2Issue1 = db.issues().insertIssue(i -> i.setProject(project2).setIssueCreationDate(addDays(now, -15))); | |||
IssueDto project2Issue2 = db.issues().insertIssue(i -> i.setProject(project2).setIssueCreationDate(addDays(now, -30))); | |||
IssueDto project2Issue1 = db.issues().insert(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -15))); | |||
IssueDto project2Issue2 = db.issues().insert(rule, project2, project2, i -> i.setIssueCreationDate(addDays(now, -30))); | |||
// Permissions and index | |||
allowAnyoneOnProjects(project1, project2, application); | |||
indexIssuesAndViews(); | |||
@@ -682,6 +711,48 @@ public class SearchActionComponentsTest { | |||
.doesNotContain(project1Issue2.getKey(), project2Issue1.getKey(), project2Issue2.getKey()); | |||
} | |||
@Test | |||
public void search_by_branch() { | |||
RuleDefinitionDto rule = db.rules().insert(); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
userSession.addProjectPermission(UserRole.USER, project); | |||
ComponentDto projectFile = db.components().insertComponent(newFileDto(project)); | |||
IssueDto projectIssue = db.issues().insertIssue(newIssue(rule, project, projectFile)); | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
ComponentDto branchFile = db.components().insertComponent(newFileDto(branch)); | |||
IssueDto branchIssue = db.issues().insertIssue(newIssue(rule, branch, branchFile)); | |||
allowAnyoneOnProjects(project); | |||
indexIssuesAndViews(); | |||
SearchWsResponse result = ws.newRequest() | |||
.setParam(PARAM_COMPONENT_KEYS, branch.getKey()) | |||
.setParam(PARAM_BRANCH, branch.getBranch()) | |||
.executeProtobuf(SearchWsResponse.class); | |||
assertThat(result.getIssuesList()).extracting(Issues.Issue::getKey) | |||
.containsExactlyInAnyOrder(branchIssue.getKey()) | |||
.doesNotContain(projectIssue.getKey()); | |||
} | |||
@Test | |||
public void does_not_return_branch_issues_on_not_contextualized_search() { | |||
RuleDefinitionDto rule = db.rules().insert(); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto projectFile = db.components().insertComponent(newFileDto(project)); | |||
IssueDto projectIssue = db.issues().insertIssue(newIssue(rule, project, projectFile)); | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
ComponentDto branchFile = db.components().insertComponent(newFileDto(branch)); | |||
IssueDto branchIssue = db.issues().insertIssue(newIssue(rule, branch, branchFile)); | |||
allowAnyoneOnProjects(project); | |||
indexIssuesAndViews(); | |||
SearchWsResponse result = ws.newRequest().executeProtobuf(SearchWsResponse.class); | |||
assertThat(result.getIssuesList()).extracting(Issues.Issue::getKey) | |||
.containsExactlyInAnyOrder(projectIssue.getKey()) | |||
.doesNotContain(branchIssue.getKey()); | |||
} | |||
private void allowAnyoneOnProjects(ComponentDto... projects) { | |||
userSession.registerComponents(projects); | |||
Arrays.stream(projects).forEach(p -> permissionIndexer.allowOnlyAnyone(p)); |
@@ -70,6 +70,7 @@ import org.sonar.server.ws.WsResponseCommonFormat; | |||
import static java.util.Arrays.asList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.api.web.UserRole.ISSUE_ADMIN; | |||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BRANCH; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.DEPRECATED_FACET_MODE_DEBT; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.FACET_MODE_EFFORT; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ADDITIONAL_FIELDS; | |||
@@ -128,13 +129,20 @@ public class SearchActionTest { | |||
assertThat(def.responseExampleAsString()).isNotEmpty(); | |||
assertThat(def.params()).extracting("key").containsExactlyInAnyOrder( | |||
"additionalFields", "asc", "assigned", "assignees", "authors", "componentKeys", "componentRootUuids", "componentRoots", "componentUuids", "components", | |||
"additionalFields", "asc", "assigned", "assignees", "authors", "componentKeys", "componentRootUuids", "componentRoots", "componentUuids", "components", "branch", | |||
"organization", | |||
"createdAfter", "createdAt", "createdBefore", "createdInLast", "directories", "facetMode", "facets", "fileUuids", "issues", "languages", "moduleUuids", "onComponentOnly", | |||
"organization", "p", "projectUuids", "projects", "ps", "resolutions", "resolved", "rules", "s", "severities", "sinceLeakPeriod", | |||
"p", "projectUuids", "projects", "ps", "resolutions", "resolved", "rules", "s", "severities", "sinceLeakPeriod", | |||
"statuses", "tags", "types"); | |||
assertThat(def.param("organization")) | |||
.matches(WebService.Param::isInternal) | |||
.matches(p -> p.since().equals("6.4")); | |||
WebService.Param branch = def.param(PARAM_BRANCH); | |||
assertThat(branch.isInternal()).isTrue(); | |||
assertThat(branch.isRequired()).isFalse(); | |||
assertThat(branch.since()).isEqualTo("6.6"); | |||
} | |||
@Test |
@@ -69,6 +69,7 @@ public class IssuesWsParameters { | |||
public static final String PARAM_DIRECTORIES = "directories"; | |||
public static final String PARAM_FILE_UUIDS = "fileUuids"; | |||
public static final String PARAM_ON_COMPONENT_ONLY = "onComponentOnly"; | |||
public static final String PARAM_BRANCH = "branch"; | |||
public static final String PARAM_ORGANIZATION = "organization"; | |||
public static final String PARAM_RULES = "rules"; | |||
public static final String PARAM_ACTIONS = "actions"; |
@@ -47,6 +47,7 @@ public class SearchWsRequest { | |||
private List<String> languages; | |||
private List<String> moduleUuids; | |||
private Boolean onComponentOnly; | |||
private String branch; | |||
private String organization; | |||
private Integer page; | |||
private Integer pageSize; | |||
@@ -442,4 +443,14 @@ public class SearchWsRequest { | |||
this.projects = projects; | |||
return this; | |||
} | |||
@CheckForNull | |||
public String getBranch() { | |||
return branch; | |||
} | |||
public SearchWsRequest setBranch(@Nullable String branch) { | |||
this.branch = branch; | |||
return this; | |||
} | |||
} |