Merge "Enable aliases for change query operators"
This commit is contained in:
@@ -3594,6 +3594,39 @@ information.
|
||||
+
|
||||
Default is false.
|
||||
|
||||
[[operator-alias]]
|
||||
=== Section operator alias
|
||||
|
||||
Operator aliasing allows global aliases to be defined for query operators.
|
||||
Currently only change queries are supported. The alias name is the git
|
||||
config key name, and the operator being aliased is the git config value.
|
||||
|
||||
For example:
|
||||
|
||||
----
|
||||
[operator-alias "change"]
|
||||
oldage = age
|
||||
number = change
|
||||
----
|
||||
|
||||
This section is particularly useful to alias operator names which may be
|
||||
long and clunky because they include a plugin name in them to a shorter
|
||||
name without the plugin name.
|
||||
|
||||
Aliases are resolved dynamically at invocation time to any currently
|
||||
loaded versions of plugins. If the alias points to an operator provided
|
||||
by a plugin which is not currently loaded, or the plugin does not define
|
||||
the operator, then "unsupported operator" is returned to the user.
|
||||
|
||||
Aliases will override existing operators. In the case of multiple aliases
|
||||
with the same name, the last one defined will be used.
|
||||
|
||||
When the target of an alias doesn't exist, the operator with the name
|
||||
of the alias will be used (if present). This enables an admin to config
|
||||
the system to override a core operator with an operator provided by a
|
||||
plugin when present and otherwise fall back to the operator provided by
|
||||
core.
|
||||
|
||||
[[pack]]
|
||||
=== Section pack
|
||||
|
||||
|
@@ -29,6 +29,7 @@ import static com.google.gerrit.index.query.QueryParser.SINGLE_WORD;
|
||||
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gerrit.common.Nullable;
|
||||
@@ -42,7 +43,9 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.antlr.runtime.tree.Tree;
|
||||
|
||||
/**
|
||||
@@ -184,6 +187,7 @@ public abstract class QueryBuilder<T, Q extends QueryBuilder<T, Q>> {
|
||||
|
||||
protected final Definition<T, Q> builderDef;
|
||||
private final ImmutableMap<String, OperatorFactory<T, Q>> opFactories;
|
||||
protected Map<String, String> opAliases = Collections.emptyMap();
|
||||
|
||||
protected QueryBuilder(
|
||||
Definition<T, Q> def,
|
||||
@@ -220,6 +224,10 @@ public abstract class QueryBuilder<T, Q extends QueryBuilder<T, Q>> {
|
||||
return toPredicate(QueryParser.parse(query));
|
||||
}
|
||||
|
||||
public void setOperatorAliases(Map<String, String> opAliases) {
|
||||
this.opAliases = opAliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse multiple user-supplied query strings into a list of predicates.
|
||||
*
|
||||
@@ -290,8 +298,12 @@ public abstract class QueryBuilder<T, Q extends QueryBuilder<T, Q>> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Predicate<T> operator(String name, String value) throws QueryParseException {
|
||||
String opName = MoreObjects.firstNonNull(opAliases.get(name), name);
|
||||
@SuppressWarnings("rawtypes")
|
||||
OperatorFactory f = opFactories.get(name);
|
||||
OperatorFactory f = opFactories.get(opName);
|
||||
if (f == null && !opName.equals(name)) {
|
||||
f = opFactories.get(name);
|
||||
}
|
||||
if (f == null) {
|
||||
throw error("Unsupported operator " + name + ":" + value);
|
||||
}
|
||||
|
@@ -0,0 +1,46 @@
|
||||
// Copyright (C) 2019 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.server.config;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
|
||||
@Singleton
|
||||
public class OperatorAliasConfig {
|
||||
private static final String SECTION = "operator-alias";
|
||||
private static final String SUBSECTION_CHANGE = "change";
|
||||
private final Config cfg;
|
||||
private final Map<String, String> changeQueryOperatorAliases;
|
||||
|
||||
@Inject
|
||||
OperatorAliasConfig(@GerritServerConfig Config cfg) {
|
||||
this.cfg = cfg;
|
||||
changeQueryOperatorAliases = new HashMap<>();
|
||||
loadChangeOperatorAliases();
|
||||
}
|
||||
|
||||
public Map<String, String> getChangeQueryOperatorAliases() {
|
||||
return changeQueryOperatorAliases;
|
||||
}
|
||||
|
||||
private void loadChangeOperatorAliases() {
|
||||
for (String name : cfg.getNames(SECTION, SUBSECTION_CHANGE)) {
|
||||
changeQueryOperatorAliases.put(name, cfg.getString(SECTION, SUBSECTION_CHANGE, name));
|
||||
}
|
||||
}
|
||||
}
|
@@ -63,6 +63,7 @@ import com.google.gerrit.server.account.VersionedAccountQueries;
|
||||
import com.google.gerrit.server.change.ChangeTriplet;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.config.AllUsersName;
|
||||
import com.google.gerrit.server.config.OperatorAliasConfig;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.index.change.ChangeField;
|
||||
import com.google.gerrit.server.index.change.ChangeIndex;
|
||||
@@ -219,6 +220,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil
|
||||
final SubmitDryRun submitDryRun;
|
||||
final GroupMembers groupMembers;
|
||||
final Provider<AnonymousUser> anonymousUserProvider;
|
||||
final OperatorAliasConfig operatorAliasConfig;
|
||||
|
||||
private final Provider<CurrentUser> self;
|
||||
|
||||
@@ -250,7 +252,8 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil
|
||||
StarredChangesUtil starredChangesUtil,
|
||||
AccountCache accountCache,
|
||||
GroupMembers groupMembers,
|
||||
Provider<AnonymousUser> anonymousUserProvider) {
|
||||
Provider<AnonymousUser> anonymousUserProvider,
|
||||
OperatorAliasConfig operatorAliasConfig) {
|
||||
this(
|
||||
queryProvider,
|
||||
rewriter,
|
||||
@@ -277,7 +280,8 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil
|
||||
starredChangesUtil,
|
||||
accountCache,
|
||||
groupMembers,
|
||||
anonymousUserProvider);
|
||||
anonymousUserProvider,
|
||||
operatorAliasConfig);
|
||||
}
|
||||
|
||||
private Arguments(
|
||||
@@ -306,7 +310,8 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil
|
||||
StarredChangesUtil starredChangesUtil,
|
||||
AccountCache accountCache,
|
||||
GroupMembers groupMembers,
|
||||
Provider<AnonymousUser> anonymousUserProvider) {
|
||||
Provider<AnonymousUser> anonymousUserProvider,
|
||||
OperatorAliasConfig operatorAliasConfig) {
|
||||
this.queryProvider = queryProvider;
|
||||
this.rewriter = rewriter;
|
||||
this.opFactories = opFactories;
|
||||
@@ -333,6 +338,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil
|
||||
this.hasOperands = hasOperands;
|
||||
this.groupMembers = groupMembers;
|
||||
this.anonymousUserProvider = anonymousUserProvider;
|
||||
this.operatorAliasConfig = operatorAliasConfig;
|
||||
}
|
||||
|
||||
Arguments asUser(CurrentUser otherUser) {
|
||||
@@ -362,7 +368,8 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil
|
||||
starredChangesUtil,
|
||||
accountCache,
|
||||
groupMembers,
|
||||
anonymousUserProvider);
|
||||
anonymousUserProvider,
|
||||
operatorAliasConfig);
|
||||
}
|
||||
|
||||
Arguments asUser(Account.Id otherId) {
|
||||
@@ -407,6 +414,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil
|
||||
@Inject
|
||||
ChangeQueryBuilder(Arguments args) {
|
||||
this(mydef, args);
|
||||
setupAliases();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -415,6 +423,10 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
private void setupAliases() {
|
||||
setOperatorAliases(args.operatorAliasConfig.getChangeQueryOperatorAliases());
|
||||
}
|
||||
|
||||
public Arguments getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||
import com.google.gerrit.acceptance.GerritConfig;
|
||||
import com.google.gerrit.acceptance.NoHttpd;
|
||||
import com.google.gerrit.extensions.common.ChangeInfo;
|
||||
import com.google.gerrit.extensions.restapi.TopLevelResource;
|
||||
@@ -97,6 +98,31 @@ public class QueryChangeIT extends AbstractDaemonTest {
|
||||
assertThat(result2.get(1).get(0)._moreChanges).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
@GerritConfig(name = "operator-alias.change.numberaliastest", value = "change")
|
||||
public void aliasQuery() throws Exception {
|
||||
String cId1 = createChange().getChangeId();
|
||||
String cId2 = createChange().getChangeId();
|
||||
int numericId1 = gApi.changes().id(cId1).get()._number;
|
||||
int numericId2 = gApi.changes().id(cId2).get()._number;
|
||||
|
||||
QueryChanges queryChanges = queryChangesProvider.get();
|
||||
queryChanges.addQuery("numberaliastest:12345");
|
||||
queryChanges.addQuery("numberaliastest:" + numericId1);
|
||||
queryChanges.addQuery("numberaliastest:" + numericId2);
|
||||
|
||||
List<List<ChangeInfo>> result =
|
||||
(List<List<ChangeInfo>>) queryChanges.apply(TopLevelResource.INSTANCE).value();
|
||||
assertThat(result).hasSize(3);
|
||||
assertThat(result.get(0)).hasSize(0);
|
||||
assertThat(result.get(1)).hasSize(1);
|
||||
assertThat(result.get(2)).hasSize(1);
|
||||
|
||||
assertThat(result.get(1).get(0)._number).isEqualTo(numericId1);
|
||||
assertThat(result.get(2).get(0)._number).isEqualTo(numericId2);
|
||||
}
|
||||
|
||||
private static void assertNoChangeHasMoreChangesSet(List<ChangeInfo> results) {
|
||||
for (ChangeInfo info : results) {
|
||||
assertThat(info._moreChanges).isNull();
|
||||
|
@@ -27,7 +27,7 @@ public class FakeQueryBuilder extends ChangeQueryBuilder {
|
||||
new ChangeQueryBuilder.Definition<>(FakeQueryBuilder.class),
|
||||
new ChangeQueryBuilder.Arguments(
|
||||
null, null, null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
null, null, null, null, indexes, null, null, null, null, null, null, null));
|
||||
null, null, null, null, indexes, null, null, null, null, null, null, null, null));
|
||||
}
|
||||
|
||||
@Operator
|
||||
|
Reference in New Issue
Block a user