in rest-api/src/jetbrains/buildServer/server/rest/data/finder/impl/ChangeFinder.java [260:430]
public ItemFilter<SVcsModificationOrChangeDescriptor> getFilter(@NotNull final Locator locator) {
final MultiCheckerFilter<SVcsModification> result = new MultiCheckerFilter<>();
//myBuildType, myProject and myBranchName are handled on getting initial collection to filter
final String vcsRootInstanceLocator = locator.getSingleDimensionValue(VCS_ROOT_INSTANCE);
if (vcsRootInstanceLocator != null) {
final VcsRootInstance vcsRootInstance = myVcsRootInstanceFinder.getItem(vcsRootInstanceLocator);
result.add(item -> {
return !item.isPersonal() && vcsRootInstance.getId() == item.getVcsRoot().getId(); //todo: check personal change applicability to the root
});
}
final String vcsRootLocator = locator.getSingleDimensionValue(VCS_ROOT);
if (vcsRootLocator != null) {
final VcsRoot vcsRoot = myVcsRootFinder.getItem(vcsRootLocator);
//todo: check personal change applicability to the root
result.add(item -> !item.isPersonal() && vcsRoot.getId() == item.getVcsRoot().getParent().getId());
}
final String sinceChangeLocator = locator.getSingleDimensionValue(SINCE_CHANGE); //todo: deprecate this
if (sinceChangeLocator != null) {
final long sinceChangeId = getChangeIdBySinceChangeLocator(sinceChangeLocator);
result.add(item -> sinceChangeId < item.getId());
}
if (locator.isUnused(USERNAME)) {
final String username = locator.getSingleDimensionValue(USERNAME);
if (username != null) {
//todo: is ignoreCase is right here?
result.add(item -> username.equalsIgnoreCase(item.getUserName()));
}
}
if (locator.isUnused(USER)) {
final String userLocator = locator.getSingleDimensionValue(USER);
if (userLocator != null) {
final SUser user = myUserFinder.getItem(userLocator);
result.add(item -> item.getCommitters().contains(user));
}
}
//TeamCity API: exclude "fake" personal changes created by TeamCity for personal builds without personal changes
result.add(item -> !item.isPersonal() || item.getChanges().size() > 0);
final Boolean personal = locator.getSingleDimensionValueAsBoolean(PERSONAL);
if (personal != null) {
result.add(item -> FilterUtil.isIncludedByBooleanFilter(personal, item.isPersonal()));
}
if (personal != null && personal) {
//initial collection can contain changes from any buildType/project
final String buildTypeLocator = locator.getSingleDimensionValue(BUILD_TYPE);
if (buildTypeLocator != null) {
final SBuildType buildType = myBuildTypeFinder.getBuildType(null, buildTypeLocator, false);
result.add(item -> isPersonalChangeMatchesBuildType(item, buildType));
}
}
if (locator.getUnusedDimensions().contains(BUILD)) {
final String buildLocator = locator.getSingleDimensionValue(BUILD);
if (buildLocator != null) {
final Set<Long> buildChanges = getBuildChangeDescriptors(myBuildFinder.getBuildPromotion(null, buildLocator), locator)
.map(mord -> mord.getRelatedVcsChange().getId())
.collect(Collectors.toSet());
result.add(item -> buildChanges.contains(item.getId()));
}
}
//pre-9.0 dimension compatibility
if (locator.getUnusedDimensions().contains(PROMOTION)) {
final Long promotionLocator = locator.getSingleDimensionValueAsLong(PROMOTION);
if (promotionLocator != null) {
@SuppressWarnings("ConstantConditions") final Set<Long> buildChanges =
getBuildChangeDescriptors(myBuildPromotionFinder.getBuildPromotion(promotionLocator), null)
.map(mord -> mord.getRelatedVcsChange().getId()).collect(Collectors.toSet());
result.add(item -> buildChanges.contains(item.getId()));
}
}
if (locator.isUnused(BUILD_TYPE)) {
final String buildTypeLocator = locator.getSingleDimensionValue(BUILD_TYPE); //todo: support multiple buildTypes here
if (buildTypeLocator != null) {
SBuildType buildType = myBuildTypeFinder.getBuildType(null, buildTypeLocator, false);
//todo: this does not include "show changes from dependencies", relates to https://youtrack.jetbrains.com/issue/TW-63704
result.add(item -> ((VcsModificationEx)item).isRelatedTo(buildType));
}
}
final String projectLocator = locator.getSingleDimensionValue(PROJECT);
if (projectLocator != null) {
final SProject project = myProjectFinder.getItem(projectLocator);
result.add(getInBuildTypesListChecker(project.getOwnBuildTypes().stream()));
}
final String affectedProjectLocator = locator.getSingleDimensionValue(AFFECTED_PROJECT);
if (affectedProjectLocator != null) {
final SProject affectedProject = myProjectFinder.getItem(affectedProjectLocator);
result.add(getInBuildTypesListChecker(affectedProject.getBuildTypes().stream()));
}
if (locator.isUnused(INTERNAL_VERSION)) {
final String internalVersion = locator.getSingleDimensionValue(INTERNAL_VERSION);
if (internalVersion != null) {
result.add(item -> internalVersion.equals(item.getVersion()));
}
}
if (locator.isUnused(VERSION)) {
final String displayVersion = locator.getSingleDimensionValue(VERSION);
ValueCondition condition = ParameterCondition.createValueCondition(displayVersion);
if (displayVersion != null) {
result.add(item -> condition.matches(item.getDisplayVersion()));
}
}
final String commentLocatorText = locator.getSingleDimensionValue(COMMENT);
if (commentLocatorText != null) {
final String containsText = new Locator(commentLocatorText).getSingleDimensionValue("contains");
// Preserve legacy behaviour
if (containsText != null) {
result.add(item -> item.getDescription().contains(containsText));
//todo: check unprocessed dimensions
} else {
ValueCondition condition = ParameterCondition.createValueCondition(commentLocatorText);
result.add(item -> condition.matches(item.getDescription()));
}
}
if (locator.getUnusedDimensions().contains(PENDING)) {
final Boolean pending = locator.getSingleDimensionValueAsBoolean(PENDING);
if (pending != null) {
final String buildTypeLocator = locator.getSingleDimensionValue(BUILD_TYPE); //todo: support multiple buildTypes here
final SBuildType buildType = buildTypeLocator == null ? null : myBuildTypeFinder.getBuildType(null, buildTypeLocator, false);
final Set<SVcsModification> pendingChanges = getPendingChanges(buildType, locator).map(mcd -> mcd.getSVcsModification()).collect(Collectors.toSet());
result.add(item -> FilterUtil.isIncludedByBooleanFilter(pending, pendingChanges.contains(item)));
}
}
final String fileLocator = locator.getSingleDimensionValue(FILE);
if (fileLocator != null) {
final String pathLocatorText = new Locator(fileLocator).getSingleDimensionValue("path"); //todo: use conditions here
//todo: check unknown locator dimensions
if (pathLocatorText != null) {
final String containsText = new Locator(pathLocatorText).getSingleDimensionValue("contains");
if (containsText != null) {
result.add(item -> item.getChanges().stream().anyMatch(vcsFileModification -> vcsFileModification.getFileName().contains(containsText)));
//todo: check unknown locator dimensions
} else {
ValueCondition condition = ParameterCondition.createValueCondition(pathLocatorText);
result.add(item -> item.getChanges().stream().map(m -> m.getFileName()).anyMatch(condition::matches));
}
}
}
// See FinderImp.getItemsByLocator(..) and this.createDuplicateChecker(..) for implementation details.
boolean deduplicate = locator.getSingleDimensionValueAsStrictBoolean(DIMENSION_UNIQUE, locator.isAnyPresent(DIMENSION_ITEM));
if (deduplicate) {
final KeyDuplicateChecker<SVcsModification, String> checker = new KeyDuplicateChecker<>(m -> m.getVersion());
result.add(item -> !checker.checkDuplicateAndRemember(item));
}
// include by build should be already handled by this time on the upper level
if (TeamCityProperties.getBoolean("rest.request.changes.check.enforceChangeViewPermission")) {
result.add(myPermissionChecker::checkCanView);
}
return new UnwrappingFilter<>(result.toItemFilter(), SVcsModificationOrChangeDescriptor::getSVcsModification);
}