Add 'is:mergeable' operator to find changes without merge conflict
With this new search operator contributors can easily find changes
that need to be rebased.
Reviewers might find this new search operator useful to filter out
changes that are not mergeable.
This change introduces a new index schema version and reindexing the
changes is required.
Change-Id: Iba8447f643d44bc13721302e54d2059d79fee37f
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
diff --git a/Documentation/user-search.txt b/Documentation/user-search.txt
index 85c0711..a6c1069 100644
--- a/Documentation/user-search.txt
+++ b/Documentation/user-search.txt
@@ -258,6 +258,11 @@
+
Same as <<status,status:'STATE'>>.
+is:mergeable::
++
+True if the change has no merge conflicts and could be merged into its
+destination branch.
+
[[status]]
status:open::
+
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
index 4c69300..cd473fb 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchSuggestOracle.java
@@ -107,6 +107,7 @@
suggestions.add("is:submitted");
suggestions.add("is:merged");
suggestions.add("is:abandoned");
+ suggestions.add("is:mergeable");
suggestions.add("status:");
suggestions.add("status:open");
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeField.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeField.java
index 290bd31..ee980d4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeField.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeField.java
@@ -349,6 +349,17 @@
}
};
+ /** Whether the change is mergeable. */
+ public static final FieldDef<ChangeData, String> MERGEABLE =
+ new FieldDef.Single<ChangeData, String>(
+ ChangeQueryBuilder.FIELD_MERGEABLE, FieldType.EXACT, false) {
+ @Override
+ public String get(ChangeData input, FillArgs args)
+ throws OrmException {
+ return input.change(args.db).isMergeable() ? "1" : null;
+ }
+ };
+
private static <T> List<byte[]> toProtos(ProtobufCodec<T> codec, Collection<T> objs)
throws OrmException {
List<byte[]> result = Lists.newArrayListWithCapacity(objs.size());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java
index 0654e80..8ce614d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java
@@ -97,6 +97,29 @@
// For upgrade to Lucene 4.4.0 index format only.
static final Schema<ChangeData> V4 = release(V3.getFields().values());
+ @SuppressWarnings("unchecked")
+ static final Schema<ChangeData> V5 = release(
+ ChangeField.LEGACY_ID,
+ ChangeField.ID,
+ ChangeField.STATUS,
+ ChangeField.PROJECT,
+ ChangeField.REF,
+ ChangeField.TOPIC,
+ ChangeField.UPDATED,
+ ChangeField.SORTKEY,
+ ChangeField.FILE,
+ ChangeField.OWNER,
+ ChangeField.REVIEWER,
+ ChangeField.COMMIT,
+ ChangeField.TR,
+ ChangeField.LABEL,
+ ChangeField.REVIEWED,
+ ChangeField.COMMIT_MESSAGE,
+ ChangeField.COMMENT,
+ ChangeField.CHANGE,
+ ChangeField.APPROVAL,
+ ChangeField.MERGEABLE);
+
private static Schema<ChangeData> release(Collection<FieldDef<ChangeData, ?>> fields) {
return new Schema<ChangeData>(true, fields);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index cc5e302..f7a1ccd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -93,6 +93,7 @@
public static final String FIELD_HAS = "has";
public static final String FIELD_LABEL = "label";
public static final String FIELD_LIMIT = "limit";
+ public static final String FIELD_MERGEABLE = "mergeable";
public static final String FIELD_MESSAGE = "message";
public static final String FIELD_OWNER = "owner";
public static final String FIELD_OWNERIN = "ownerin";
@@ -280,7 +281,7 @@
}
@Operator
- public Predicate<ChangeData> is(String value) {
+ public Predicate<ChangeData> is(String value) throws QueryParseException {
if ("starred".equalsIgnoreCase(value)) {
return new IsStarredByPredicate(args.dbProvider, currentUser);
}
@@ -305,6 +306,11 @@
return new ReviewerPredicate(args.dbProvider, self());
}
+ if ("mergeable".equalsIgnoreCase(value)) {
+ requireIndex(FIELD_IS, "mergeable");
+ return new IsMergeablePredicate(args.dbProvider);
+ }
+
try {
return status(value);
} catch (IllegalArgumentException e) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsMergeablePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsMergeablePredicate.java
new file mode 100644
index 0000000..6eb99c4
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsMergeablePredicate.java
@@ -0,0 +1,42 @@
+// Copyright (C) 2013 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.query.change;
+
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.index.ChangeField;
+import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Provider;
+
+class IsMergeablePredicate extends IndexPredicate<ChangeData> {
+ private final Provider<ReviewDb> dbProvider;
+
+ IsMergeablePredicate(Provider<ReviewDb> dbProvider) {
+ super(ChangeField.MERGEABLE, "1");
+ this.dbProvider = dbProvider;
+ }
+
+ @Override
+ public boolean match(ChangeData object) throws OrmException {
+ Change c = object.change(dbProvider);
+ return c != null && c.isMergeable();
+ }
+
+ @Override
+ public int getCost() {
+ return 1;
+ }
+}