Merge branch 'stable-2.16' into stable-3.0

* stable-2.16: (27 commits)
  Use shallow clone while expanding definitions
  Move match() and matchOrNull() to MatchCache
  fixup! Cache Task definition lists for ChangeNodes
  Cache Task definition lists for ChangeNodes
  Split SubNodeFactory out of SubNodeAdder
  Moving caching logic out of loadSubNodes()
  Use a TaskTree.Node.Invalid instead of nulls
  Use overloading for special cases instead of nulls
  Add a TaskTree ApplicableNodeFilter
  Add an isCacheableByBranch() to the PredicateCache
  Track whether Task.applicable needs to be refreshed
  Allow Expander to expand a single Task's field
  Minor cleanup of task Properties.expandText()
  Remove cached Change subNodes on Node completion
  Explicitly signal end of Task Properties expansion
  Use a SubNodeAdder to add TaskTree SubNodes
  Avoid hard coding the refs/meta/config ref
  Inject All-Projects in TaskConfigFactory
  Change TaskExpressions to iterate over TaskKeys
  Avoid passing isTrusted in TaskConfigFactory.getTaskConfig()
  ...

Change-Id: I1d65c0fbd5f5326867526977d1ee82652737eab1
diff --git a/.bazelversion b/.bazelversion
index fd2a018..7c69a55 100644
--- a/.bazelversion
+++ b/.bazelversion
@@ -1 +1 @@
-3.1.0
+3.7.0
diff --git a/BUILD b/BUILD
index dbe73f9..39b3d0d 100644
--- a/BUILD
+++ b/BUILD
@@ -37,8 +37,6 @@
         "Implementation-Title: Task Plugin",
         "Implementation-URL: https://gerrit-review.googlesource.com/#/admin/projects/plugins/" + plugin_name,
         "Gerrit-Module: com.googlesource.gerrit.plugins.task.Modules$Module",
-        "Gerrit-SshModule: com.googlesource.gerrit.plugins.task.Modules$SshModule",
-        "Gerrit-HttpModule: com.googlesource.gerrit.plugins.task.Modules$HttpModule",
     ],
     resource_jars = [":gr-task-plugin-static"],
     resources = glob(["src/main/resources/**/*"]),
diff --git a/WORKSPACE b/WORKSPACE
index b254afa..0c9c56f 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,7 +3,7 @@
 load("//:bazlets.bzl", "load_bazlets")
 
 load_bazlets(
-    commit = "0ccc066431ad7e88a5cd9e06000ce677de1116ee",
+    commit = "a88174652e6f853ead5bbc5dacc1030dbb2d50c3",
     #local_path = "/home/<user>/projects/bazlets",
 )
 
@@ -51,20 +51,11 @@
     sha1 = "eff48ed53995db2dadf0456426cc1f8700136f86",
 )
 
-# Release Plugin API
+# Load plugin API
 load(
     "@com_googlesource_gerrit_bazlets//:gerrit_api.bzl",
     "gerrit_api",
 )
 
-# Snapshot Plugin API
-#load(
-#    "@com_googlesource_gerrit_bazlets//:gerrit_api_maven_local.bzl",
-#    "gerrit_api_maven_local",
-#)
-
-# Load release Plugin API
+# Release Plugin API
 gerrit_api()
-
-# Load snapshot Plugin API
-#gerrit_api_maven_local()
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/MatchCache.java b/src/main/java/com/googlesource/gerrit/plugins/task/MatchCache.java
index f802720..ef5af15 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/MatchCache.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/MatchCache.java
@@ -14,9 +14,9 @@
 
 package com.googlesource.gerrit.plugins.task;
 
+import com.google.gerrit.exceptions.StorageException;
 import com.google.gerrit.index.query.QueryParseException;
 import com.google.gerrit.server.query.change.ChangeData;
-import com.google.gwtorm.server.OrmException;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -31,7 +31,7 @@
     this.changeData = changeData;
   }
 
-  public boolean match(String query) throws OrmException, QueryParseException {
+  public boolean match(String query) throws StorageException, QueryParseException {
     if (query == null) {
       return true;
     }
@@ -51,7 +51,7 @@
     if (isMatched == null) {
       try {
         isMatched = predicateCache.matchWithExceptions(changeData, query);
-      } catch (OrmException | QueryParseException | RuntimeException e) {
+      } catch (QueryParseException | RuntimeException e) {
       }
       matchResultByQuery.put(query, isMatched);
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/Modules.java b/src/main/java/com/googlesource/gerrit/plugins/task/Modules.java
index 6346a73..11786e6 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/Modules.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/Modules.java
@@ -19,7 +19,8 @@
 import com.google.gerrit.extensions.webui.JavaScriptPlugin;
 import com.google.gerrit.extensions.webui.WebUiPlugin;
 import com.google.gerrit.server.DynamicOptions.DynamicBean;
-import com.google.gerrit.server.query.change.ChangeQueryProcessor.ChangeAttributeFactory;
+import com.google.gerrit.server.change.ChangeAttributeFactory;
+import com.google.gerrit.server.restapi.change.GetChange;
 import com.google.gerrit.server.restapi.change.QueryChanges;
 import com.google.gerrit.sshd.commands.Query;
 import com.google.inject.AbstractModule;
@@ -36,19 +37,9 @@
       bind(ChangeAttributeFactory.class)
           .annotatedWith(Exports.named("task"))
           .to(TaskAttributeFactory.class);
-    }
-  }
 
-  public static class SshModule extends AbstractModule {
-    @Override
-    protected void configure() {
+      bind(DynamicBean.class).annotatedWith(Exports.named(GetChange.class)).to(MyOptions.class);
       bind(DynamicBean.class).annotatedWith(Exports.named(Query.class)).to(MyOptions.class);
-    }
-  }
-
-  public static class HttpModule extends AbstractModule {
-    @Override
-    protected void configure() {
       bind(DynamicBean.class).annotatedWith(Exports.named(QueryChanges.class)).to(MyOptions.class);
       DynamicSet.bind(binder(), WebUiPlugin.class)
           .toInstance(new JavaScriptPlugin("gr-task-plugin.html"));
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/PredicateCache.java b/src/main/java/com/googlesource/gerrit/plugins/task/PredicateCache.java
index 4da59e4..6540ad2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/PredicateCache.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/PredicateCache.java
@@ -14,6 +14,7 @@
 
 package com.googlesource.gerrit.plugins.task;
 
+import com.google.gerrit.exceptions.StorageException;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.index.query.AndPredicate;
 import com.google.gerrit.index.query.NotPredicate;
@@ -29,7 +30,6 @@
 import com.google.gerrit.server.query.change.RefPredicate;
 import com.google.gerrit.server.query.change.RegexProjectPredicate;
 import com.google.gerrit.server.query.change.RegexRefPredicate;
-import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -61,7 +61,7 @@
   }
 
   public boolean matchWithExceptions(ChangeData c, String query)
-      throws QueryParseException, OrmException {
+      throws QueryParseException, StorageException {
     if ("true".equalsIgnoreCase(query)) {
       return true;
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/Properties.java b/src/main/java/com/googlesource/gerrit/plugins/task/Properties.java
index 952b9a3..609511b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/Properties.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/Properties.java
@@ -15,9 +15,9 @@
 package com.googlesource.gerrit.plugins.task;
 
 import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.exceptions.StorageException;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.query.change.ChangeData;
-import com.google.gwtorm.server.OrmException;
 import com.googlesource.gerrit.plugins.task.TaskConfig.NamesFactory;
 import com.googlesource.gerrit.plugins.task.TaskConfig.Task;
 import java.lang.reflect.Field;
@@ -64,7 +64,7 @@
   }
 
   /** Use to expand properties specifically for Tasks. */
-  public Task getTask(ChangeData changeData) throws OrmException {
+  public Task getTask(ChangeData changeData) throws StorageException {
     loader = new Loader(changeData);
     expander = new Expander(n -> loader.load(n));
     if (isTaskRefreshNeeded || init) {
@@ -148,14 +148,14 @@
       if (changeProp != name) {
         try {
           return change(changeProp);
-        } catch (OrmException e) {
+        } catch (StorageException e) {
           throw new RuntimeException(e);
         }
       }
       return "";
     }
 
-    protected String change(String changeProp) throws OrmException {
+    protected String change(String changeProp) throws StorageException {
       switch (changeProp) {
         case "number":
           return String.valueOf(change().getId().get());
@@ -178,7 +178,7 @@
       if (change == null) {
         try {
           change = changeData.change();
-        } catch (OrmException e) {
+        } catch (StorageException e) {
           throw new RuntimeException(e);
         }
       }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java b/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java
index ae40471..9367d23 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java
@@ -15,12 +15,12 @@
 package com.googlesource.gerrit.plugins.task;
 
 import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.exceptions.StorageException;
 import com.google.gerrit.extensions.common.PluginDefinedInfo;
 import com.google.gerrit.index.query.QueryParseException;
+import com.google.gerrit.server.DynamicOptions.BeanProvider;
+import com.google.gerrit.server.change.ChangeAttributeFactory;
 import com.google.gerrit.server.query.change.ChangeData;
-import com.google.gerrit.server.query.change.ChangeQueryProcessor;
-import com.google.gerrit.server.query.change.ChangeQueryProcessor.ChangeAttributeFactory;
-import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.googlesource.gerrit.plugins.task.TaskConfig.Task;
 import com.googlesource.gerrit.plugins.task.TaskTree.Node;
@@ -80,8 +80,8 @@
   }
 
   @Override
-  public PluginDefinedInfo create(ChangeData c, ChangeQueryProcessor qp, String plugin) {
-    options = (Modules.MyOptions) qp.getDynamicBean(plugin);
+  public PluginDefinedInfo create(ChangeData c, BeanProvider beanProvider, String plugin) {
+    options = (Modules.MyOptions) beanProvider.getDynamicBean(plugin);
     if (options.all || options.onlyApplicable || options.onlyInvalid) {
       for (PatchSetArgument psa : options.patchSetArguments) {
         definitions.masquerade(psa);
@@ -102,7 +102,7 @@
           new AttributeFactory(node, matchCache).create().ifPresent(t -> a.roots.add(t));
         }
       }
-    } catch (ConfigInvalidException | IOException | OrmException e) {
+    } catch (ConfigInvalidException | IOException | StorageException e) {
       a.roots.add(invalid());
     }
 
@@ -174,17 +174,13 @@
             }
           }
         }
-      } catch (ConfigInvalidException
-          | IOException
-          | OrmException
-          | QueryParseException
-          | RuntimeException e) {
+      } catch (ConfigInvalidException | IOException | QueryParseException | RuntimeException e) {
         return Optional.of(invalid()); // bad applicability query
       }
       return Optional.empty();
     }
 
-    protected Status getStatusWithExceptions() throws OrmException, QueryParseException {
+    protected Status getStatusWithExceptions() throws StorageException, QueryParseException {
       if (node.isDuplicate) {
         return Status.DUPLICATE;
       }
@@ -252,13 +248,13 @@
     protected Status getStatus() {
       try {
         return getStatusWithExceptions();
-      } catch (OrmException | QueryParseException | RuntimeException e) {
+      } catch (QueryParseException | RuntimeException e) {
         return Status.INVALID;
       }
     }
 
     protected List<TaskAttribute> getSubTasks()
-        throws ConfigInvalidException, IOException, OrmException {
+        throws ConfigInvalidException, IOException, StorageException {
       List<TaskAttribute> subTasks = new ArrayList<>();
       for (Node subNode :
           options.onlyApplicable ? node.getSubNodes(matchCache) : node.getSubNodes()) {
@@ -284,7 +280,7 @@
         matchCache.match(task.fail);
         matchCache.match(task.pass);
         return true;
-      } catch (OrmException | QueryParseException | RuntimeException e) {
+      } catch (QueryParseException | RuntimeException e) {
         return false;
       }
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/TaskTree.java b/src/main/java/com/googlesource/gerrit/plugins/task/TaskTree.java
index ab4d48f..c99b6a2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/TaskTree.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/TaskTree.java
@@ -17,6 +17,8 @@
 import static java.util.stream.Collectors.toList;
 
 import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.exceptions.StorageException;
+import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
 import com.google.gerrit.index.query.QueryParseException;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Branch;
@@ -28,7 +30,6 @@
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.ChangeQueryBuilder;
 import com.google.gerrit.server.query.change.ChangeQueryProcessor;
-import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.googlesource.gerrit.plugins.task.TaskConfig.External;
@@ -101,7 +102,7 @@
   }
 
   public List<Node> getRootNodes(ChangeData changeData)
-      throws ConfigInvalidException, IOException, OrmException {
+      throws ConfigInvalidException, IOException, StorageException {
     this.changeData = changeData;
     root.path = Collections.emptyList();
     root.duplicateKeys = Collections.emptyList();
@@ -115,14 +116,16 @@
     protected Map<TaskKey, Node> cachedNodeByTask = new HashMap<>();
     protected List<Node> cachedNodes;
 
-    public List<Node> getSubNodes() throws ConfigInvalidException, IOException, OrmException {
+    protected List<Node> getSubNodes()
+        throws ConfigInvalidException, IOException, StorageException {
       if (cachedNodes != null) {
         return refresh(cachedNodes);
       }
       return cachedNodes = loadSubNodes();
     }
 
-    protected List<Node> loadSubNodes() throws ConfigInvalidException, IOException, OrmException {
+    protected List<Node> loadSubNodes()
+        throws ConfigInvalidException, IOException, StorageException {
       return new SubNodeFactory().createFromPreloaded(preloader.getRootTasks());
     }
 
@@ -138,7 +141,7 @@
       protected Set<String> names = new HashSet<>();
 
       public List<Node> createFromPreloaded(List<Task> defs)
-          throws ConfigInvalidException, OrmException {
+          throws ConfigInvalidException, StorageException {
         List<Node> nodes = new ArrayList<>();
         for (Task def : defs) {
           nodes.add(createFromPreloaded(def));
@@ -146,12 +149,12 @@
         return nodes;
       }
 
-      public Node createFromPreloaded(Task def) throws ConfigInvalidException, OrmException {
+      public Node createFromPreloaded(Task def) throws ConfigInvalidException, StorageException {
         return createFromPreloaded(def, (parent, definition) -> new Node(parent, definition));
       }
 
       public Node createFromPreloaded(Task def, ChangeData changeData)
-          throws ConfigInvalidException, OrmException {
+          throws ConfigInvalidException, StorageException {
         return createFromPreloaded(
             def,
             (parent, definition) ->
@@ -169,7 +172,7 @@
       }
 
       protected Node createFromPreloaded(Task def, NodeFactory nodeFactory)
-          throws ConfigInvalidException, OrmException {
+          throws ConfigInvalidException, StorageException {
         if (def != null) {
           try {
             Node node = cachedNodeByTask.get(def.key());
@@ -200,7 +203,7 @@
   public class Node extends NodeList {
     public class Invalid extends Node {
       @Override
-      public void refreshTask() throws ConfigInvalidException, OrmException {}
+      public void refreshTask() throws ConfigInvalidException, StorageException {}
 
       @Override
       public Task getDefinition() {
@@ -221,7 +224,7 @@
       properties = null;
     }
 
-    public Node(NodeList parent, Task task) throws ConfigInvalidException, OrmException {
+    public Node(NodeList parent, Task task) throws ConfigInvalidException, StorageException {
       this.parent = parent;
       taskKey = task.key();
       properties = new Properties(this, task);
@@ -232,7 +235,7 @@
       return String.valueOf(getChangeData().getId().get()) + TaskConfig.SEP + taskKey;
     }
 
-    public List<Node> getSubNodes() throws ConfigInvalidException, IOException, OrmException {
+    public List<Node> getSubNodes() throws ConfigInvalidException, IOException, StorageException {
       if (cachedNodes != null) {
         return refresh(cachedNodes);
       }
@@ -255,7 +258,7 @@
     }
 
     public List<Node> getSubNodes(MatchCache matchCache)
-        throws ConfigInvalidException, IOException, OrmException {
+        throws ConfigInvalidException, IOException, StorageException {
       if (hasUnfilterableSubNodes) {
         return getSubNodes();
       }
@@ -263,7 +266,8 @@
     }
 
     @Override
-    protected List<Node> loadSubNodes() throws ConfigInvalidException, IOException, OrmException {
+    protected List<Node> loadSubNodes()
+        throws ConfigInvalidException, IOException, StorageException {
       List<Task> cachedDefinitions = definitionsBySubSection.get(task.key().subSection());
       if (cachedDefinitions != null) {
         return new SubNodeFactory().createFromPreloaded(cachedDefinitions);
@@ -276,7 +280,7 @@
     /* The task needs to be refreshed before a node is used, however
     subNode refreshing can wait until they are fetched since they may
     not be needed. */
-    public void refreshTask() throws ConfigInvalidException, OrmException {
+    public void refreshTask() throws ConfigInvalidException, StorageException {
       this.path = new LinkedList<>(parent.path);
       String key = key();
       isDuplicate = path.contains(key);
@@ -317,7 +321,7 @@
       protected List<Node> nodes = new ArrayList<>();
       protected SubNodeFactory factory = new SubNodeFactory();
 
-      public List<Node> getSubNodes() throws ConfigInvalidException, IOException, OrmException {
+      public List<Node> getSubNodes() throws ConfigInvalidException, IOException, StorageException {
         addSubTasks();
         addSubTasksFactoryTasks();
         addSubTasksFiles();
@@ -325,7 +329,7 @@
         return nodes;
       }
 
-      protected void addSubTasks() throws ConfigInvalidException, IOException, OrmException {
+      protected void addSubTasks() throws ConfigInvalidException, IOException, StorageException {
         for (String expression : task.subTasks) {
           try {
             Optional<Task> def =
@@ -339,7 +343,7 @@
         }
       }
 
-      protected void addSubTasksFiles() throws ConfigInvalidException, OrmException {
+      protected void addSubTasksFiles() throws ConfigInvalidException, StorageException {
         for (String file : task.subTasksFiles) {
           try {
             addPreloaded(
@@ -350,7 +354,7 @@
         }
       }
 
-      protected void addSubTasksExternals() throws ConfigInvalidException, OrmException {
+      protected void addSubTasksExternals() throws ConfigInvalidException, StorageException {
         for (String external : task.subTasksExternals) {
           try {
             External ext = task.config.getExternal(external);
@@ -366,7 +370,7 @@
       }
 
       protected void addSubTasksFactoryTasks()
-          throws ConfigInvalidException, IOException, OrmException {
+          throws ConfigInvalidException, IOException, StorageException {
         for (String tasksFactoryName : task.subTasksFactories) {
           TasksFactory tasksFactory = task.config.getTasksFactory(tasksFactoryName);
           if (tasksFactory != null) {
@@ -388,14 +392,14 @@
       }
 
       protected void addStaticTypeTasks(TasksFactory tasksFactory, NamesFactory namesFactory)
-          throws ConfigInvalidException, IOException, OrmException {
+          throws ConfigInvalidException, IOException, StorageException {
         for (String name : namesFactory.names) {
           addPreloaded(preloader.preload(task.config.new Task(tasksFactory, name)));
         }
       }
 
       protected void addChangeTypeTasks(TasksFactory tasksFactory, NamesFactory namesFactory)
-          throws ConfigInvalidException, IOException, OrmException {
+          throws ConfigInvalidException, IOException, StorageException {
         try {
           if (namesFactory.changes != null) {
             List<ChangeData> changeDataList =
@@ -411,23 +415,23 @@
             }
             return;
           }
-        } catch (OrmException e) {
+        } catch (StorageException e) {
           log.atSevere().withCause(e).log("ERROR: running changes query: " + namesFactory.changes);
         } catch (QueryParseException e) {
         }
         addInvalidNode();
       }
 
-      public void addPreloaded(List<Task> defs) throws ConfigInvalidException, OrmException {
+      public void addPreloaded(List<Task> defs) throws ConfigInvalidException, StorageException {
         nodes.addAll(factory.createFromPreloaded(defs));
       }
 
       public void addPreloaded(Task def, ChangeData changeData)
-          throws ConfigInvalidException, OrmException {
+          throws ConfigInvalidException, StorageException {
         nodes.add(factory.createFromPreloaded(def, changeData));
       }
 
-      public void addPreloaded(Task def) throws ConfigInvalidException, OrmException {
+      public void addPreloaded(Task def) throws ConfigInvalidException, StorageException {
         nodes.add(factory.createFromPreloaded(def));
       }
 
@@ -436,7 +440,7 @@
       }
 
       protected List<Task> getPreloadedTasks(External external)
-          throws ConfigInvalidException, IOException, OrmException {
+          throws ConfigInvalidException, IOException, StorageException {
         return preloader.getTasks(
             FileKey.create(resolveUserBranch(external.user), resolveTaskFileName(external.file)));
       }
@@ -448,12 +452,12 @@
       protected Branch.NameKey branch = getChangeData().change().getDest();
 
       public ApplicableNodeFilter(MatchCache matchCache)
-          throws ConfigInvalidException, IOException, OrmException {
+          throws ConfigInvalidException, IOException, StorageException {
         this.matchCache = matchCache;
         this.pcache = matchCache.predicateCache;
       }
 
-      public List<Node> getSubNodes() throws ConfigInvalidException, IOException, OrmException {
+      public List<Node> getSubNodes() throws ConfigInvalidException, IOException, StorageException {
         if (nodesByBranch != null) {
           List<Node> nodes = nodesByBranch.get(branch);
           if (nodes != null) {
@@ -477,7 +481,7 @@
       }
 
       protected Optional<List<Node>> getOptionalApplicableForBranch(List<Node> nodes)
-          throws ConfigInvalidException, IOException, OrmException {
+          throws ConfigInvalidException, IOException, StorageException {
         int filterable = 0;
         List<Node> applicableNodes = new ArrayList<>();
         for (Node node : nodes) {
@@ -530,19 +534,21 @@
   }
 
   protected Branch.NameKey resolveUserBranch(String user)
-      throws ConfigInvalidException, IOException, OrmException {
+      throws ConfigInvalidException, IOException, StorageException {
     if (user == null) {
       throw new ConfigInvalidException("External user not defined");
     }
-    Account acct = accountResolver.find(user);
-    if (acct == null) {
+    Account.Id acct;
+    try {
+      acct = accountResolver.resolve(user).asUnique().getAccount().getId();
+    } catch (UnprocessableEntityException e) {
       throw new ConfigInvalidException("Cannot resolve user: " + user);
     }
-    return new Branch.NameKey(allUsers.get(), RefNames.refsUsers(acct.getId()));
+    return new Branch.NameKey(allUsers.get(), RefNames.refsUsers(acct));
   }
 
   protected static List<Node> refresh(List<Node> nodes)
-      throws ConfigInvalidException, OrmException {
+      throws ConfigInvalidException, StorageException {
     for (Node node : nodes) {
       node.refreshTask();
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/cli/PatchSetArgument.java b/src/main/java/com/googlesource/gerrit/plugins/task/cli/PatchSetArgument.java
index bcbb972..9fbddeb 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/cli/PatchSetArgument.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/cli/PatchSetArgument.java
@@ -13,10 +13,10 @@
 // limitations under the License.
 package com.googlesource.gerrit.plugins.task.cli;
 
+import com.google.gerrit.exceptions.StorageException;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.PatchSetUtil;
 import com.google.gerrit.server.notedb.ChangeNotes;
@@ -24,14 +24,12 @@
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.sshd.BaseCommand.UnloggedFailure;
-import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 
 public class PatchSetArgument {
   public static class Factory {
     protected final PermissionBackend permissionBackend;
     protected final ChangeNotes.Factory notesFactory;
-    protected final ReviewDb reviewDb;
     protected final PatchSetUtil psUtil;
     protected final CurrentUser user;
 
@@ -39,12 +37,10 @@
     protected Factory(
         ChangeNotes.Factory notesFactory,
         PermissionBackend permissionBackend,
-        ReviewDb reviewDb,
         PatchSetUtil psUtil,
         CurrentUser user) {
       this.notesFactory = notesFactory;
       this.permissionBackend = permissionBackend;
-      this.reviewDb = reviewDb;
       this.psUtil = psUtil;
       this.user = user;
     }
@@ -53,18 +49,13 @@
       try {
         PatchSet.Id patchSetId = parsePatchSet(token);
         ChangeNotes changeNotes = notesFactory.createChecked(patchSetId.getParentKey());
-        permissionBackend
-            .user(user)
-            .database(reviewDb)
-            .change(changeNotes)
-            .check(ChangePermission.READ);
-        return new PatchSetArgument(
-            changeNotes.getChange(), psUtil.get(reviewDb, changeNotes, patchSetId));
+        permissionBackend.user(user).change(changeNotes).check(ChangePermission.READ);
+        return new PatchSetArgument(changeNotes.getChange(), psUtil.get(changeNotes, patchSetId));
       } catch (PermissionBackendException | AuthException e) {
         throw new IllegalArgumentException("database error", e);
       } catch (UnloggedFailure e) {
         throw new IllegalArgumentException(e.getMessage(), e);
-      } catch (OrmException e) {
+      } catch (StorageException e) {
         throw new IllegalArgumentException("database error", e);
       }
     }
diff --git a/test/check_task_statuses.sh b/test/check_task_statuses.sh
index a28a15d..1d3efbd 100755
--- a/test/check_task_statuses.sh
+++ b/test/check_task_statuses.sh
@@ -223,7 +223,7 @@
 }
 
 get_change_num() { # < gerrit_push_response > changenum
-    local url=$(awk '/New Changes:/ { getline; print $2 }')
+    local url=$(awk '$NF ~ /\[NEW\]/ { print $2 }')
     echo "${url##*\/}" | tr -d -c '[:digit:]'
 }
 
diff --git a/test/docker/gerrit/Dockerfile b/test/docker/gerrit/Dockerfile
index 059f3c0..b9d1715 100755
--- a/test/docker/gerrit/Dockerfile
+++ b/test/docker/gerrit/Dockerfile
@@ -1,4 +1,4 @@
-FROM gerritcodereview/gerrit:2.16.27-ubuntu16
+FROM gerritcodereview/gerrit:3.0.16-ubuntu18
 
 USER root