in rest-api/src/jetbrains/buildServer/server/rest/data/finder/impl/BranchFinder.java [220:313]
private ItemHolder<BranchData> getPrefilteredItemsInternal(@NotNull final Locator locator, boolean existenseCheck) {
String buildLocator = locator.getSingleDimensionValue(BUILD);
if (!StringUtil.isEmpty(buildLocator)) {
BuildPromotion build = myServiceLocator.getSingletonService(BuildPromotionFinder.class).getItem(buildLocator);
return ItemHolder.of(Collections.singleton(BranchData.fromBuild(build)));
}
final String buildTypeLocator = locator.getSingleDimensionValue(BUILD_TYPE);
if (buildTypeLocator == null) {
throw new BadRequestException("No '" + BUILD_TYPE + "' dimension is present but it is required for searching branches. Locator: '" + locator.getStringRepresentation() + "'");
}
final List<SBuildType> buildTypes = myBuildTypeFinder.getBuildTypes(null, buildTypeLocator);
List<ItemHolder<BranchData>> result = new ArrayList<>();
final String groupsInclude = locator.getSingleDimensionValue(GROUP_INCLUDE);
if (groupsInclude != null) {
SUser user = validateAndgetGroupIncludeUser(groupsInclude);
result.add(ItemHolder.of(
buildTypes
.stream()
.flatMap(buildType -> myBranchGroupsService.getAvailableBranchGroups(
new BranchGroupsProvider.Context((BuildTypeEx)buildType, user)
).stream())
.distinct()
.map(branchGroup -> BranchData.fromBranchGroup(branchGroup))
));
}
final String groupDimension = locator.getSingleDimensionValue(BRANCH_GROUP);
if (groupDimension != null) {
BranchGroupFilterDetails groupDetails = getBranchGroupFilterDetails(groupDimension, buildTypes.get(0));
result.add(processor -> {
try {
buildTypes.forEach(buildType -> {
BranchGroupsProvider.Context ctx = new BranchGroupsProvider.Context((BuildTypeEx)buildType, groupDetails.getUser());
myBranchGroupsService.collectBranches(
groupDetails.getBranchGroupId(),
ctx,
branchEx -> processor.processItem(BranchData.fromBranchEx(branchEx, myServiceLocator, null, true))
);
});
} catch (IllegalStateException e) {
throw new BadRequestException("Error retrieving branch groups: " + e.getMessage());
}
});
return ItemHolder.concat(result);
}
BranchSearchOptions searchOptions = getBranchSearchOptions(locator);
boolean lookingForDefaultBranch = BooleanUtils.isTrue(locator.getSingleDimensionValueAsBoolean(DEFAULT));
// We must make sure that no unused dimensions are present as otherwise we may stop too early and then get filtered,
// i.e. loose relevant item.
if(lookingForDefaultBranch && existenseCheck && locator.getUnusedDimensions().isEmpty()) {
for (SBuildType buildType : buildTypes) {
final BranchData branch = detectDefaultBranch(buildType, searchOptions);
// As soon as default branch is found, create a simple processor and don't look into other buildTypes.
if(branch != null) {
result.add(processor -> processor.processItem(branch));
break;
}
}
} else {
locator.markUnused(DEFAULT);
Filter<SBuildType> dependenciesFilter = getBranchDependenciesFilter(buildTypes);
if(existenseCheck) {
// We don't use deduplication here as in this case we have a chance to stop earlier
// using lazy stream evaluation and avoid getting branches from all build types.
// We also skip computing timestamps as that is unnecessary for an existence check.
locator.markUsed(COMPUTE_TIMESTAMPS);
Stream<BranchData> branchStream = buildTypes.stream()
.flatMap(buildType -> getBranches(buildType, searchOptions, false, dependenciesFilter));
result.add(ItemHolder.of(branchStream));
} else {
DeduplicatingAccumulator resultAccumulator = new DeduplicatingAccumulator();
for (SBuildType buildType : buildTypes) {
Boolean locatorComputeTimestamps = locator.getSingleDimensionValueAsBoolean(COMPUTE_TIMESTAMPS);
boolean finalComputeTimestamps = locatorComputeTimestamps != null ? locatorComputeTimestamps : TeamCityProperties.getBoolean("rest.beans.branch.defaultComputeTimestamp");
Stream<BranchData> branchStream = getBranches(buildType, searchOptions, finalComputeTimestamps, dependenciesFilter);
resultAccumulator.addAll(branchStream);
}
result.add(ItemHolder.of(resultAccumulator.get()));
}
}
return ItemHolder.concat(result);
}