Merge "Support IsOperands in change queries from plugins"
This commit is contained in:
@@ -742,7 +742,8 @@ Plugins can define new search operands to extend change searching.
|
|||||||
Plugin methods implementing search operands (returning a
|
Plugin methods implementing search operands (returning a
|
||||||
`Predicate<ChangeData>`), must be defined on a class implementing
|
`Predicate<ChangeData>`), must be defined on a class implementing
|
||||||
one of the `ChangeQueryBuilder.ChangeOperandsFactory` interfaces
|
one of the `ChangeQueryBuilder.ChangeOperandsFactory` interfaces
|
||||||
(.e.g., ChangeQueryBuilder.ChangeHasOperandFactory). The specific
|
(.e.g., ChangeQueryBuilder.ChangeHasOperandFactory or
|
||||||
|
ChangeQueryBuilder.ChangeIsOperandFactory). The specific
|
||||||
`ChangeOperandFactory` class must also be bound to the `DynamicSet` from
|
`ChangeOperandFactory` class must also be bound to the `DynamicSet` from
|
||||||
a module's `configure()` method in the plugin.
|
a module's `configure()` method in the plugin.
|
||||||
|
|
||||||
|
@@ -433,6 +433,7 @@ public class GerritGlobalModule extends FactoryModule {
|
|||||||
DynamicMap.mapOf(binder(), DynamicOptions.DynamicBean.class);
|
DynamicMap.mapOf(binder(), DynamicOptions.DynamicBean.class);
|
||||||
DynamicMap.mapOf(binder(), ChangeQueryBuilder.ChangeOperatorFactory.class);
|
DynamicMap.mapOf(binder(), ChangeQueryBuilder.ChangeOperatorFactory.class);
|
||||||
DynamicMap.mapOf(binder(), ChangeQueryBuilder.ChangeHasOperandFactory.class);
|
DynamicMap.mapOf(binder(), ChangeQueryBuilder.ChangeHasOperandFactory.class);
|
||||||
|
DynamicMap.mapOf(binder(), ChangeQueryBuilder.ChangeIsOperandFactory.class);
|
||||||
DynamicSet.setOf(binder(), ChangeAttributeFactory.class);
|
DynamicSet.setOf(binder(), ChangeAttributeFactory.class);
|
||||||
|
|
||||||
install(new GitwebConfig.LegacyModule(cfg));
|
install(new GitwebConfig.LegacyModule(cfg));
|
||||||
|
@@ -117,12 +117,14 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil
|
|||||||
* <p>bind(ChangeHasOperandFactory.class) .annotatedWith(Exports.named("your has operand"))
|
* <p>bind(ChangeHasOperandFactory.class) .annotatedWith(Exports.named("your has operand"))
|
||||||
* .to(YourClass.class);
|
* .to(YourClass.class);
|
||||||
*/
|
*/
|
||||||
private interface ChangeOperandFactory {
|
public interface ChangeOperandFactory {
|
||||||
Predicate<ChangeData> create(ChangeQueryBuilder builder) throws QueryParseException;
|
Predicate<ChangeData> create(ChangeQueryBuilder builder) throws QueryParseException;
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ChangeHasOperandFactory extends ChangeOperandFactory {}
|
public interface ChangeHasOperandFactory extends ChangeOperandFactory {}
|
||||||
|
|
||||||
|
public interface ChangeIsOperandFactory extends ChangeOperandFactory {}
|
||||||
|
|
||||||
private static final Pattern PAT_LEGACY_ID = Pattern.compile("^[1-9][0-9]*$");
|
private static final Pattern PAT_LEGACY_ID = Pattern.compile("^[1-9][0-9]*$");
|
||||||
private static final Pattern PAT_CHANGE_ID = Pattern.compile(CHANGE_ID_PATTERN);
|
private static final Pattern PAT_CHANGE_ID = Pattern.compile(CHANGE_ID_PATTERN);
|
||||||
private static final Pattern DEF_CHANGE =
|
private static final Pattern DEF_CHANGE =
|
||||||
@@ -218,6 +220,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil
|
|||||||
final CommentsUtil commentsUtil;
|
final CommentsUtil commentsUtil;
|
||||||
final ConflictsCache conflictsCache;
|
final ConflictsCache conflictsCache;
|
||||||
final DynamicMap<ChangeHasOperandFactory> hasOperands;
|
final DynamicMap<ChangeHasOperandFactory> hasOperands;
|
||||||
|
final DynamicMap<ChangeIsOperandFactory> isOperands;
|
||||||
final DynamicMap<ChangeOperatorFactory> opFactories;
|
final DynamicMap<ChangeOperatorFactory> opFactories;
|
||||||
final GitRepositoryManager repoManager;
|
final GitRepositoryManager repoManager;
|
||||||
final GroupBackend groupBackend;
|
final GroupBackend groupBackend;
|
||||||
@@ -244,6 +247,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil
|
|||||||
ChangeIndexRewriter rewriter,
|
ChangeIndexRewriter rewriter,
|
||||||
DynamicMap<ChangeOperatorFactory> opFactories,
|
DynamicMap<ChangeOperatorFactory> opFactories,
|
||||||
DynamicMap<ChangeHasOperandFactory> hasOperands,
|
DynamicMap<ChangeHasOperandFactory> hasOperands,
|
||||||
|
DynamicMap<ChangeIsOperandFactory> isOperands,
|
||||||
IdentifiedUser.GenericFactory userFactory,
|
IdentifiedUser.GenericFactory userFactory,
|
||||||
Provider<CurrentUser> self,
|
Provider<CurrentUser> self,
|
||||||
PermissionBackend permissionBackend,
|
PermissionBackend permissionBackend,
|
||||||
@@ -273,6 +277,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil
|
|||||||
rewriter,
|
rewriter,
|
||||||
opFactories,
|
opFactories,
|
||||||
hasOperands,
|
hasOperands,
|
||||||
|
isOperands,
|
||||||
userFactory,
|
userFactory,
|
||||||
self,
|
self,
|
||||||
permissionBackend,
|
permissionBackend,
|
||||||
@@ -304,6 +309,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil
|
|||||||
ChangeIndexRewriter rewriter,
|
ChangeIndexRewriter rewriter,
|
||||||
DynamicMap<ChangeOperatorFactory> opFactories,
|
DynamicMap<ChangeOperatorFactory> opFactories,
|
||||||
DynamicMap<ChangeHasOperandFactory> hasOperands,
|
DynamicMap<ChangeHasOperandFactory> hasOperands,
|
||||||
|
DynamicMap<ChangeIsOperandFactory> isOperands,
|
||||||
IdentifiedUser.GenericFactory userFactory,
|
IdentifiedUser.GenericFactory userFactory,
|
||||||
Provider<CurrentUser> self,
|
Provider<CurrentUser> self,
|
||||||
PermissionBackend permissionBackend,
|
PermissionBackend permissionBackend,
|
||||||
@@ -351,6 +357,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil
|
|||||||
this.starredChangesUtil = starredChangesUtil;
|
this.starredChangesUtil = starredChangesUtil;
|
||||||
this.accountCache = accountCache;
|
this.accountCache = accountCache;
|
||||||
this.hasOperands = hasOperands;
|
this.hasOperands = hasOperands;
|
||||||
|
this.isOperands = isOperands;
|
||||||
this.groupMembers = groupMembers;
|
this.groupMembers = groupMembers;
|
||||||
this.changeIsVisbleToPredicateFactory = changeIsVisbleToPredicateFactory;
|
this.changeIsVisbleToPredicateFactory = changeIsVisbleToPredicateFactory;
|
||||||
this.operatorAliasConfig = operatorAliasConfig;
|
this.operatorAliasConfig = operatorAliasConfig;
|
||||||
@@ -364,6 +371,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil
|
|||||||
rewriter,
|
rewriter,
|
||||||
opFactories,
|
opFactories,
|
||||||
hasOperands,
|
hasOperands,
|
||||||
|
isOperands,
|
||||||
userFactory,
|
userFactory,
|
||||||
Providers.of(otherUser),
|
Providers.of(otherUser),
|
||||||
permissionBackend,
|
permissionBackend,
|
||||||
@@ -643,6 +651,14 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil
|
|||||||
throw new QueryParseException("'is:wip' operator is not supported by change index version");
|
throw new QueryParseException("'is:wip' operator is not supported by change index version");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for plugins the value will be operandName_pluginName
|
||||||
|
List<String> names = Lists.newArrayList(Splitter.on('_').split(value));
|
||||||
|
if (names.size() == 2) {
|
||||||
|
ChangeIsOperandFactory op = args.isOperands.get(names.get(1), names.get(0));
|
||||||
|
if (op != null) {
|
||||||
|
return op.create(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
return status(value);
|
return status(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,102 @@
|
|||||||
|
// Copyright (C) 2020 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package com.google.gerrit.acceptance.api.change;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||||
|
import com.google.gerrit.extensions.annotations.Exports;
|
||||||
|
import com.google.gerrit.extensions.common.ChangeInfo;
|
||||||
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
|
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||||
|
import com.google.gerrit.extensions.restapi.TopLevelResource;
|
||||||
|
import com.google.gerrit.index.query.Matchable;
|
||||||
|
import com.google.gerrit.index.query.OperatorPredicate;
|
||||||
|
import com.google.gerrit.index.query.Predicate;
|
||||||
|
import com.google.gerrit.index.query.QueryParseException;
|
||||||
|
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||||
|
import com.google.gerrit.server.query.change.ChangeData;
|
||||||
|
import com.google.gerrit.server.query.change.ChangeQueryBuilder;
|
||||||
|
import com.google.gerrit.server.restapi.change.QueryChanges;
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
import java.util.List;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class PluginOperatorsIT extends AbstractDaemonTest {
|
||||||
|
@Inject private Provider<QueryChanges> queryChangesProvider;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getChangeWithIsOperator() throws Exception {
|
||||||
|
QueryChanges queryChanges = queryChangesProvider.get();
|
||||||
|
queryChanges.addQuery("is:changeNumberEven_myplugin");
|
||||||
|
|
||||||
|
String oddChangeId = createChange().getChangeId();
|
||||||
|
String evenChangeId = createChange().getChangeId();
|
||||||
|
assertThat(getChanges(queryChanges)).hasSize(0);
|
||||||
|
|
||||||
|
try (AutoCloseable ignored = installPlugin("myplugin", IsOperatorModule.class)) {
|
||||||
|
List<ChangeInfo> changes = getChanges(queryChanges);
|
||||||
|
assertThat(changes).hasSize(1);
|
||||||
|
|
||||||
|
String outputChangeId = ((ChangeInfo) changes.get(0)).changeId;
|
||||||
|
assertThat(outputChangeId).isEqualTo(evenChangeId);
|
||||||
|
assertThat(outputChangeId).isNotEqualTo(oddChangeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(getChanges(queryChanges)).hasSize(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class IsOperatorModule extends AbstractModule {
|
||||||
|
@Override
|
||||||
|
public void configure() {
|
||||||
|
bind(ChangeQueryBuilder.ChangeIsOperandFactory.class)
|
||||||
|
.annotatedWith(Exports.named("changeNumberEven"))
|
||||||
|
.to(SampleIsOperand.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SampleIsOperand implements ChangeQueryBuilder.ChangeIsOperandFactory {
|
||||||
|
@Override
|
||||||
|
public Predicate<ChangeData> create(ChangeQueryBuilder builder) throws QueryParseException {
|
||||||
|
return new IsSamplePredicate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class IsSamplePredicate extends OperatorPredicate<ChangeData>
|
||||||
|
implements Matchable<ChangeData> {
|
||||||
|
|
||||||
|
public IsSamplePredicate() {
|
||||||
|
super("is", "changeNumberEven");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean match(ChangeData changeData) {
|
||||||
|
int id = changeData.getId().get();
|
||||||
|
return id % 2 == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCost() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ChangeInfo> getChanges(QueryChanges queryChanges)
|
||||||
|
throws AuthException, PermissionBackendException, BadRequestException {
|
||||||
|
return (List<ChangeInfo>) queryChanges.apply(TopLevelResource.INSTANCE).value();
|
||||||
|
}
|
||||||
|
}
|
@@ -44,6 +44,7 @@ public class FakeQueryBuilder extends ChangeQueryBuilder {
|
|||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
null,
|
||||||
indexes,
|
indexes,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
Reference in New Issue
Block a user