diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt index bb4deb3bc4..50b9b3e228 100644 --- a/Documentation/config-gerrit.txt +++ b/Documentation/config-gerrit.txt @@ -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 diff --git a/java/com/google/gerrit/index/query/QueryBuilder.java b/java/com/google/gerrit/index/query/QueryBuilder.java index d24cfebe2f..85dcf3ed79 100644 --- a/java/com/google/gerrit/index/query/QueryBuilder.java +++ b/java/com/google/gerrit/index/query/QueryBuilder.java @@ -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> { protected final Definition builderDef; private final ImmutableMap> opFactories; + protected Map opAliases = Collections.emptyMap(); protected QueryBuilder( Definition def, @@ -220,6 +224,10 @@ public abstract class QueryBuilder> { return toPredicate(QueryParser.parse(query)); } + public void setOperatorAliases(Map opAliases) { + this.opAliases = opAliases; + } + /** * Parse multiple user-supplied query strings into a list of predicates. * @@ -290,8 +298,12 @@ public abstract class QueryBuilder> { @SuppressWarnings("unchecked") private Predicate 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); } diff --git a/java/com/google/gerrit/server/config/OperatorAliasConfig.java b/java/com/google/gerrit/server/config/OperatorAliasConfig.java new file mode 100644 index 0000000000..0c5fc6e29c --- /dev/null +++ b/java/com/google/gerrit/server/config/OperatorAliasConfig.java @@ -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 changeQueryOperatorAliases; + + @Inject + OperatorAliasConfig(@GerritServerConfig Config cfg) { + this.cfg = cfg; + changeQueryOperatorAliases = new HashMap<>(); + loadChangeOperatorAliases(); + } + + public Map getChangeQueryOperatorAliases() { + return changeQueryOperatorAliases; + } + + private void loadChangeOperatorAliases() { + for (String name : cfg.getNames(SECTION, SUBSECTION_CHANGE)) { + changeQueryOperatorAliases.put(name, cfg.getString(SECTION, SUBSECTION_CHANGE, name)); + } + } +} diff --git a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java index d2fc77da2c..5d4edc931e 100644 --- a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java +++ b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java @@ -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 anonymousUserProvider; + final OperatorAliasConfig operatorAliasConfig; private final Provider self; @@ -250,7 +252,8 @@ public class ChangeQueryBuilder extends QueryBuilder anonymousUserProvider) { + Provider anonymousUserProvider, + OperatorAliasConfig operatorAliasConfig) { this( queryProvider, rewriter, @@ -277,7 +280,8 @@ public class ChangeQueryBuilder extends QueryBuilder anonymousUserProvider) { + Provider anonymousUserProvider, + OperatorAliasConfig operatorAliasConfig) { this.queryProvider = queryProvider; this.rewriter = rewriter; this.opFactories = opFactories; @@ -333,6 +338,7 @@ public class ChangeQueryBuilder extends QueryBuilder> result = + (List>) 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 results) { for (ChangeInfo info : results) { assertThat(info._moreChanges).isNull(); diff --git a/javatests/com/google/gerrit/server/index/change/FakeQueryBuilder.java b/javatests/com/google/gerrit/server/index/change/FakeQueryBuilder.java index 0753127b52..9a48a68475 100644 --- a/javatests/com/google/gerrit/server/index/change/FakeQueryBuilder.java +++ b/javatests/com/google/gerrit/server/index/change/FakeQueryBuilder.java @@ -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