diff --git a/Documentation/user-search.txt b/Documentation/user-search.txt index 85c0711554..a6c10696bf 100644 --- a/Documentation/user-search.txt +++ b/Documentation/user-search.txt @@ -258,6 +258,11 @@ is:submitted, is:merged, is:abandoned:: + Same as <>. +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 4c69300f69..cd473fb295 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 @@ public class SearchSuggestOracle extends HighlightSuggestOracle { 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-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java index b6d9819355..8c8f94454d 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java @@ -193,8 +193,8 @@ class RelatedChanges extends TabPanel { if (Gerrit.getConfig().hasIndex()) { StringBuilder conflictsQuery = new StringBuilder(); conflictsQuery.append("status:open"); + conflictsQuery.append(" is:mergeable"); conflictsQuery.append(" ").append(op("conflicts", info.legacy_id().get())); - conflictsQuery.append(" -age:1month"); ChangeList.query(conflictsQuery.toString(), EnumSet.of(ListChangesOption.CURRENT_REVISION, ListChangesOption.CURRENT_COMMIT), new AsyncCallback() { 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 290bd3143c..ee980d4a52 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 @@ public class ChangeField { } }; + /** Whether the change is mergeable. */ + public static final FieldDef MERGEABLE = + new FieldDef.Single( + 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 List toProtos(ProtobufCodec codec, Collection objs) throws OrmException { List 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 0654e808b0..8ce614d86d 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 @@ public class ChangeSchemas { // For upgrade to Lucene 4.4.0 index format only. static final Schema V4 = release(V3.getFields().values()); + @SuppressWarnings("unchecked") + static final Schema 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 release(Collection> fields) { return new Schema(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 cc5e30241f..f7a1ccd578 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 class ChangeQueryBuilder extends QueryBuilder { 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 @@ public class ChangeQueryBuilder extends QueryBuilder { } @Operator - public Predicate is(String value) { + public Predicate is(String value) throws QueryParseException { if ("starred".equalsIgnoreCase(value)) { return new IsStarredByPredicate(args.dbProvider, currentUser); } @@ -305,6 +306,11 @@ public class ChangeQueryBuilder extends QueryBuilder { 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 0000000000..6eb99c40a6 --- /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 { + private final Provider dbProvider; + + IsMergeablePredicate(Provider 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; + } +}