Support alias "self" in queries
Writing an expression like "owner:self status:open" will now identify changes that the caller owns and are still open. This self alias is valid in contexts where a user is expected as an argument to a query operator. Change-Id: I87e58dda43d8da560b31400f1257857b0ea96175
This commit is contained in:
@@ -75,7 +75,8 @@ Change-Id that was scraped out of the commit message.
|
||||
[[owner]]
|
||||
owner:'USER'::
|
||||
+
|
||||
Changes originally submitted by 'USER'.
|
||||
Changes originally submitted by 'USER'. The special case of
|
||||
`owner:self` will find changes owned by the caller.
|
||||
|
||||
[[ownerin]]
|
||||
ownerin:'GROUP'::
|
||||
@@ -85,7 +86,9 @@ Changes originally submitted by a user in 'GROUP'.
|
||||
[[reviewer]]
|
||||
reviewer:'USER'::
|
||||
+
|
||||
Changes that have been, or need to be, reviewed by 'USER'.
|
||||
Changes that have been, or need to be, reviewed by 'USER'. The
|
||||
special case of `reviewer:self` will find changes where the caller
|
||||
has been added as a reviewer.
|
||||
|
||||
[[reviewerin]]
|
||||
reviewerin:'GROUP'::
|
||||
@@ -213,6 +216,16 @@ is:reviewed::
|
||||
True if there is at least one non-zero score on the change, in any
|
||||
approval category, by any user.
|
||||
|
||||
is:owner::
|
||||
+
|
||||
True on any change where the current user is the change owner.
|
||||
Same as `owner:self`.
|
||||
|
||||
is:reviewer::
|
||||
+
|
||||
True on any change where the current user is a reviewer.
|
||||
Same as `reviewer:self`.
|
||||
|
||||
is:open::
|
||||
+
|
||||
True if the change is other open or submitted, merge pending.
|
||||
@@ -373,16 +386,20 @@ the change. This flag is always added to any query.
|
||||
starredby:'USER'::
|
||||
+
|
||||
Matches changes that have been starred by 'USER'.
|
||||
The special case `starredby:self` applies to the caller.
|
||||
|
||||
watchedby:'USER'::
|
||||
+
|
||||
Matches changes that 'USER' has configured watch filters for.
|
||||
The special case `watchedby:self` applies to the caller.
|
||||
|
||||
draftby:'USER'::
|
||||
+
|
||||
Matches changes that 'USER' has left unpublished drafts on.
|
||||
Since the drafts are unpublished, it is not possible to see the
|
||||
draft text, or even how many drafts there are.
|
||||
draft text, or even how many drafts there are. The special case
|
||||
of `draftby:self` will find changes where the caller has created
|
||||
a draft comment.
|
||||
|
||||
limit:'CNT'::
|
||||
+
|
||||
|
@@ -14,6 +14,7 @@
|
||||
|
||||
package com.google.gerrit.server.query;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -44,23 +45,35 @@ import java.util.List;
|
||||
public abstract class Predicate<T> {
|
||||
/** Combine the passed predicates into a single AND node. */
|
||||
public static <T> Predicate<T> and(final Predicate<T>... that) {
|
||||
if (that.length == 1) {
|
||||
return that[0];
|
||||
}
|
||||
return new AndPredicate<T>(that);
|
||||
}
|
||||
|
||||
/** Combine the passed predicates into a single AND node. */
|
||||
public static <T> Predicate<T> and(
|
||||
final Collection<? extends Predicate<T>> that) {
|
||||
if (that.size() == 1) {
|
||||
return Iterables.getOnlyElement(that);
|
||||
}
|
||||
return new AndPredicate<T>(that);
|
||||
}
|
||||
|
||||
/** Combine the passed predicates into a single OR node. */
|
||||
public static <T> Predicate<T> or(final Predicate<T>... that) {
|
||||
if (that.length == 1) {
|
||||
return that[0];
|
||||
}
|
||||
return new OrPredicate<T>(that);
|
||||
}
|
||||
|
||||
/** Combine the passed predicates into a single OR node. */
|
||||
public static <T> Predicate<T> or(
|
||||
final Collection<? extends Predicate<T>> that) {
|
||||
if (that.size() == 1) {
|
||||
return Iterables.getOnlyElement(that);
|
||||
}
|
||||
return new OrPredicate<T>(that);
|
||||
}
|
||||
|
||||
|
@@ -14,6 +14,7 @@
|
||||
|
||||
package com.google.gerrit.server.query.change;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gerrit.common.data.ApprovalTypes;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
@@ -44,6 +45,7 @@ import org.eclipse.jgit.lib.AbbreviatedObjectId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -206,10 +208,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
}
|
||||
|
||||
if ("draft".equalsIgnoreCase(value)) {
|
||||
if (currentUser instanceof IdentifiedUser) {
|
||||
return new HasDraftByPredicate(args.dbProvider,
|
||||
((IdentifiedUser) currentUser).getAccountId());
|
||||
}
|
||||
return new HasDraftByPredicate(args.dbProvider, self());
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException();
|
||||
@@ -233,6 +232,14 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
return new IsReviewedPredicate(args.dbProvider);
|
||||
}
|
||||
|
||||
if ("owner".equalsIgnoreCase(value)) {
|
||||
return new OwnerPredicate(args.dbProvider, self());
|
||||
}
|
||||
|
||||
if ("reviewer".equalsIgnoreCase(value)) {
|
||||
return new ReviewerPredicate(args.dbProvider, self());
|
||||
}
|
||||
|
||||
try {
|
||||
return status(value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
@@ -303,42 +310,59 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
@Operator
|
||||
public Predicate<ChangeData> starredby(String who)
|
||||
throws QueryParseException, OrmException {
|
||||
Account account = args.accountResolver.find(who);
|
||||
if (account == null) {
|
||||
throw error("User " + who + " not found");
|
||||
if ("self".equals(who)) {
|
||||
return new IsStarredByPredicate(args.dbProvider, currentUser);
|
||||
}
|
||||
return new IsStarredByPredicate(args.dbProvider, //
|
||||
args.userFactory.create(args.dbProvider, account.getId()));
|
||||
Set<Account.Id> m = parseAccount(who);
|
||||
List<IsStarredByPredicate> p = Lists.newArrayListWithCapacity(m.size());
|
||||
for (Account.Id id : m) {
|
||||
p.add(new IsStarredByPredicate(args.dbProvider,
|
||||
args.userFactory.create(args.dbProvider, id)));
|
||||
}
|
||||
return Predicate.or(p);
|
||||
}
|
||||
|
||||
@Operator
|
||||
public Predicate<ChangeData> watchedby(String who)
|
||||
throws QueryParseException, OrmException {
|
||||
Account account = args.accountResolver.find(who);
|
||||
if (account == null) {
|
||||
throw error("User " + who + " not found");
|
||||
Set<Account.Id> m = parseAccount(who);
|
||||
List<IsWatchedByPredicate> p = Lists.newArrayListWithCapacity(m.size());
|
||||
for (Account.Id id : m) {
|
||||
if (currentUser instanceof IdentifiedUser
|
||||
&& id.equals(((IdentifiedUser) currentUser).getAccountId())) {
|
||||
p.add(new IsWatchedByPredicate(args, currentUser));
|
||||
} else {
|
||||
p.add(new IsWatchedByPredicate(args,
|
||||
args.userFactory.create(args.dbProvider, id)));
|
||||
}
|
||||
}
|
||||
return new IsWatchedByPredicate(args, args.userFactory.create(
|
||||
args.dbProvider, account.getId()));
|
||||
return Predicate.or(p);
|
||||
}
|
||||
|
||||
@Operator
|
||||
public Predicate<ChangeData> draftby(String who) throws QueryParseException,
|
||||
OrmException {
|
||||
Account account = args.accountResolver.find(who);
|
||||
if (account == null) {
|
||||
throw error("User " + who + " not found");
|
||||
Set<Account.Id> m = parseAccount(who);
|
||||
List<HasDraftByPredicate> p = Lists.newArrayListWithCapacity(m.size());
|
||||
for (Account.Id id : m) {
|
||||
p.add(new HasDraftByPredicate(args.dbProvider, id));
|
||||
}
|
||||
return new HasDraftByPredicate(args.dbProvider, account.getId());
|
||||
return Predicate.or(p);
|
||||
}
|
||||
|
||||
@Operator
|
||||
public Predicate<ChangeData> visibleto(String who)
|
||||
throws QueryParseException, OrmException {
|
||||
Account account = args.accountResolver.find(who);
|
||||
if (account != null) {
|
||||
return visibleto(args.userFactory
|
||||
.create(args.dbProvider, account.getId()));
|
||||
if ("self".equals(who)) {
|
||||
return is_visible();
|
||||
}
|
||||
Set<Account.Id> m = args.accountResolver.findAll(who);
|
||||
if (!m.isEmpty()) {
|
||||
List<Predicate<ChangeData>> p = Lists.newArrayListWithCapacity(m.size());
|
||||
for (Account.Id id : m) {
|
||||
return visibleto(args.userFactory.create(args.dbProvider, id));
|
||||
}
|
||||
return Predicate.or(p);
|
||||
}
|
||||
|
||||
// If its not an account, maybe its a group?
|
||||
@@ -375,24 +399,17 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
@Operator
|
||||
public Predicate<ChangeData> owner(String who) throws QueryParseException,
|
||||
OrmException {
|
||||
Set<Account.Id> m = args.accountResolver.findAll(who);
|
||||
if (m.isEmpty()) {
|
||||
throw error("User " + who + " not found");
|
||||
} else if (m.size() == 1) {
|
||||
Account.Id id = m.iterator().next();
|
||||
return new OwnerPredicate(args.dbProvider, id);
|
||||
} else {
|
||||
List<OwnerPredicate> p = new ArrayList<OwnerPredicate>(m.size());
|
||||
for (Account.Id id : m) {
|
||||
p.add(new OwnerPredicate(args.dbProvider, id));
|
||||
}
|
||||
return Predicate.or(p);
|
||||
Set<Account.Id> m = parseAccount(who);
|
||||
List<OwnerPredicate> p = Lists.newArrayListWithCapacity(m.size());
|
||||
for (Account.Id id : m) {
|
||||
p.add(new OwnerPredicate(args.dbProvider, id));
|
||||
}
|
||||
return Predicate.or(p);
|
||||
}
|
||||
|
||||
@Operator
|
||||
public Predicate<ChangeData> ownerin(String group) throws QueryParseException,
|
||||
OrmException {
|
||||
public Predicate<ChangeData> ownerin(String group)
|
||||
throws QueryParseException {
|
||||
AccountGroup g = args.groupCache.get(new AccountGroup.NameKey(group));
|
||||
if (g == null) {
|
||||
throw error("Group " + group + " not found");
|
||||
@@ -403,24 +420,17 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
@Operator
|
||||
public Predicate<ChangeData> reviewer(String who)
|
||||
throws QueryParseException, OrmException {
|
||||
Set<Account.Id> m = args.accountResolver.findAll(who);
|
||||
if (m.isEmpty()) {
|
||||
throw error("User " + who + " not found");
|
||||
} else if (m.size() == 1) {
|
||||
Account.Id id = m.iterator().next();
|
||||
return new ReviewerPredicate(args.dbProvider, id);
|
||||
} else {
|
||||
List<ReviewerPredicate> p = new ArrayList<ReviewerPredicate>(m.size());
|
||||
for (Account.Id id : m) {
|
||||
p.add(new ReviewerPredicate(args.dbProvider, id));
|
||||
}
|
||||
return Predicate.or(p);
|
||||
Set<Account.Id> m = parseAccount(who);
|
||||
List<ReviewerPredicate> p = Lists.newArrayListWithCapacity(m.size());
|
||||
for (Account.Id id : m) {
|
||||
p.add(new ReviewerPredicate(args.dbProvider, id));
|
||||
}
|
||||
return Predicate.or(p);
|
||||
}
|
||||
|
||||
@Operator
|
||||
public Predicate<ChangeData> reviewerin(String group)
|
||||
throws QueryParseException, OrmException {
|
||||
throws QueryParseException {
|
||||
AccountGroup g = args.groupCache.get(new AccountGroup.NameKey(group));
|
||||
if (g == null) {
|
||||
throw error("Group " + group + " not found");
|
||||
@@ -532,4 +542,23 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
||||
throw error("Unsupported query:" + query);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<Account.Id> parseAccount(String who)
|
||||
throws QueryParseException, OrmException {
|
||||
if ("self".equals(who)) {
|
||||
return Collections.singleton(self());
|
||||
}
|
||||
Set<Account.Id> matches = args.accountResolver.findAll(who);
|
||||
if (matches.isEmpty()) {
|
||||
throw error("User " + who + " not found");
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
private Account.Id self() {
|
||||
if (currentUser instanceof IdentifiedUser) {
|
||||
return ((IdentifiedUser) currentUser).getAccountId();
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user