Merge branch 'stable-2.14' into stable-2.15

* stable-2.14:
  Do not assign reviewers that cannot see the change

Change-Id: Id9e193d08c34d5779e2ff2154c89d20142afa42b
diff --git a/.gitignore b/.gitignore
index f07afcd..6042b9d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,6 @@
 *.ipr
 .idea
 /.classpath
-/.primary_build_tool
 /.project
 /.settings/
 /bazel-*
diff --git a/WORKSPACE b/WORKSPACE
index 4482bd9..7b6285e 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,7 +3,7 @@
 load("//:bazlets.bzl", "load_bazlets")
 
 load_bazlets(
-    commit = "2c39029a585bd1d5b785150948f162730f7b7e42",
+    commit = "70d6ae0cee03c456fa4b32c807f3d13c032ef498",
     #local_path = "/home/<user>/projects/bazlets",
 )
 
diff --git a/lib/prolog/prolog.bzl b/lib/prolog/prolog.bzl
index ae46601..5ba004b 100644
--- a/lib/prolog/prolog.bzl
+++ b/lib/prolog/prolog.bzl
@@ -1 +1,3 @@
-load("@com_googlesource_gerrit_bazlets//lib/prolog:prolog.bzl", "prolog_cafe_library")
+load("@com_googlesource_gerrit_bazlets//lib/prolog:prolog.bzl", _prolog_cafe_library = "prolog_cafe_library")
+
+prolog_cafe_library = _prolog_cafe_library
diff --git a/owners-autoassign/BUILD b/owners-autoassign/BUILD
index 1dfc3a3..42a32bc 100644
--- a/owners-autoassign/BUILD
+++ b/owners-autoassign/BUILD
@@ -1,19 +1,42 @@
-load("//tools/bzl:plugin.bzl", "gerrit_plugin")
+load("//tools/bzl:junit.bzl", "junit_tests")
+load("//tools/bzl:plugin.bzl", "PLUGIN_DEPS", "PLUGIN_DEPS_NEVERLINK", "PLUGIN_TEST_DEPS", "gerrit_plugin")
 
 gerrit_plugin(
     name = "owners-autoassign",
     srcs = glob([
         "src/main/java/**/*.java",
     ]),
+    dir_name = "owners",
     manifest_entries = [
         "Implementation-Title: Gerrit OWNERS autoassign plugin",
         "Implementation-URL: https://gerrit.googlesource.com/plugins/owners",
         "Gerrit-PluginName: owners-autoassign",
         "Gerrit-Module: com.vmware.gerrit.owners.common.AutoassignModule",
-        "Gerrit-ApiVersion: 2.14",
+        "Gerrit-ApiVersion: 2.15",
     ],
     resources = glob(["src/main/**/*"]),
     deps = [
         "//owners-common",
     ],
 )
+
+java_library(
+    name = "owners-autoassign_deps",
+    srcs = glob([
+        "src/main/java/**/*.java",
+    ]),
+    visibility = ["//visibility:public"],
+    deps = PLUGIN_DEPS_NEVERLINK + [
+        "//owners-common",
+    ],
+)
+
+junit_tests(
+    name = "owners_autoassign_tests",
+    testonly = 1,
+    srcs = glob(["src/test/java/**/*.java"]),
+    deps = PLUGIN_DEPS + PLUGIN_TEST_DEPS + [
+        "//owners-common",
+        ":owners-autoassign_deps",
+    ],
+)
diff --git a/owners-autoassign/src/main/java/com/vmware/gerrit/owners/common/GitRefListener.java b/owners-autoassign/src/main/java/com/vmware/gerrit/owners/common/GitRefListener.java
index aeb5960..eae0cb8 100644
--- a/owners-autoassign/src/main/java/com/vmware/gerrit/owners/common/GitRefListener.java
+++ b/owners-autoassign/src/main/java/com/vmware/gerrit/owners/common/GitRefListener.java
@@ -20,16 +20,25 @@
 
 import com.google.common.collect.Sets;
 import com.google.gerrit.extensions.annotations.Listen;
+import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.changes.ChangeApi;
+import com.google.gerrit.extensions.api.changes.Changes;
+import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.common.ChangeInfo;
 import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.patch.PatchList;
 import com.google.gerrit.server.patch.PatchListCache;
 import com.google.gerrit.server.patch.PatchListKey;
 import com.google.gerrit.server.patch.PatchListNotAvailableException;
+import com.google.gerrit.server.util.ManualRequestContext;
+import com.google.gerrit.server.util.OneOffRequestContext;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -44,9 +53,7 @@
 public class GitRefListener implements GitReferenceUpdatedListener {
   private static final Logger logger = LoggerFactory.getLogger(GitRefListener.class);
 
-  private static final String CHANGES_REF = "refs/changes/";
-
-  private final Provider<ReviewDb> db;
+  private final GerritApi api;
 
   private final PatchListCache patchListCache;
 
@@ -56,28 +63,67 @@
 
   private final ReviewerManager reviewerManager;
 
+  private final OneOffRequestContext oneOffReqCtx;
+
+  private Provider<CurrentUser> currentUserProvider;
+
   @Inject
   public GitRefListener(
-      Provider<ReviewDb> db,
+      GerritApi api,
       PatchListCache patchListCache,
       GitRepositoryManager repositoryManager,
       Accounts accounts,
-      ReviewerManager reviewerManager) {
-    this.db = db;
+      ReviewerManager reviewerManager,
+      OneOffRequestContext oneOffReqCtx,
+      Provider<CurrentUser> currentUserProvider) {
+    this.api = api;
     this.patchListCache = patchListCache;
     this.repositoryManager = repositoryManager;
     this.accounts = accounts;
     this.reviewerManager = reviewerManager;
+    this.oneOffReqCtx = oneOffReqCtx;
+    this.currentUserProvider = currentUserProvider;
   }
 
   @Override
   public void onGitReferenceUpdated(Event event) {
+    AccountInfo updaterAccountInfo = event.getUpdater();
+    CurrentUser currentUser = currentUserProvider.get();
+    if (currentUser.isIdentifiedUser()) {
+      handleGitReferenceUpdated(event);
+    } else if (updaterAccountInfo != null) {
+      handleGitReferenceUpdatedAsUser(event, new Account.Id(updaterAccountInfo._accountId));
+    } else {
+      handleGitReferenceUpdatedAsServer(event);
+    }
+  }
+
+  private void handleGitReferenceUpdatedAsUser(Event event, Account.Id updaterAccountId) {
+    try (ManualRequestContext ctx = oneOffReqCtx.openAs(updaterAccountId)) {
+      handleGitReferenceUpdated(event);
+    } catch (OrmException e) {
+      logger.warn("Unable to process event {} on project {}", event, event.getProjectName(), e);
+    }
+  }
+
+  private void handleGitReferenceUpdatedAsServer(Event event) {
+    try (ManualRequestContext ctx = oneOffReqCtx.open()) {
+      handleGitReferenceUpdated(event);
+    } catch (OrmException e) {
+      logger.warn("Unable to process event {} on project {}", event, event.getProjectName(), e);
+    }
+  }
+
+  private void handleGitReferenceUpdated(Event event) {
     String projectName = event.getProjectName();
     Repository repository;
     try {
       repository = repositoryManager.openRepository(Project.NameKey.parse(projectName));
       try {
-        processEvent(repository, event);
+        String refName = event.getRefName();
+        if (refName.startsWith(RefNames.REFS_CHANGES) && !RefNames.isNoteDbMetaRef(refName)) {
+          processEvent(repository, event);
+        }
       } finally {
         repository.close();
       }
@@ -86,43 +132,44 @@
     }
   }
 
-  private void processEvent(Repository repository, Event event) {
-    if (event.getRefName().startsWith(CHANGES_REF)) {
-      Change.Id id = Change.Id.fromRef(event.getRefName());
-      ReviewDb reviewDb = db.get();
-      // The provider injected by Gerrit is shared with other workers on the
-      // same local thread and thus cannot be closed in this event listener.
-      try {
-        Change change = reviewDb.changes().get(id);
-        PatchList patchList = getPatchList(event, change);
-        if (patchList != null) {
-          PathOwners owners =
-              new PathOwners(accounts, repository, change.getDest().get(), patchList);
-          Set<Account.Id> allReviewers = Sets.newHashSet();
-          allReviewers.addAll(owners.get().values());
-          for (Matcher matcher : owners.getMatchers().values()) {
-            allReviewers.addAll(matcher.getOwners());
-          }
-          logger.debug("Autoassigned reviewers are: {}", allReviewers.toString());
-          reviewerManager.addReviewers(change, allReviewers);
-        }
-      } catch (OrmException e) {
-        logger.warn("Could not open change: {}", id, e);
-      } catch (ReviewerManagerException e) {
-        logger.warn("Could not add reviewers for change: {}", id, e);
+  void processEvent(Repository repository, Event event) {
+    Change.Id cId = Change.Id.fromRef(event.getRefName());
+    Changes changes = api.changes();
+    // The provider injected by Gerrit is shared with other workers on the
+    // same local thread and thus cannot be closed in this event listener.
+    try {
+      ChangeApi cApi = changes.id(cId.id);
+      ChangeInfo change = cApi.get();
+      if (change == null) {
+        return;
       }
+      PatchList patchList = getPatchList(event, change);
+      if (patchList != null) {
+        PathOwners owners = new PathOwners(accounts, repository, change.branch, patchList);
+        Set<Account.Id> allReviewers = Sets.newHashSet();
+        allReviewers.addAll(owners.get().values());
+        for (Matcher matcher : owners.getMatchers().values()) {
+          allReviewers.addAll(matcher.getOwners());
+        }
+        logger.debug("Autoassigned reviewers are: {}", allReviewers.toString());
+        reviewerManager.addReviewers(cApi, allReviewers);
+      }
+    } catch (RestApiException e) {
+      logger.warn("Could not open change: {}", cId, e);
+    } catch (ReviewerManagerException e) {
+      logger.warn("Could not add reviewers for change: {}", cId, e);
     }
   }
 
-  private PatchList getPatchList(Event event, Change change) {
+  private PatchList getPatchList(Event event, ChangeInfo change) {
     ObjectId newId = null;
     if (event.getNewObjectId() != null) {
       newId = ObjectId.fromString(event.getNewObjectId());
     }
 
-    PatchListKey plKey = new PatchListKey(null, newId, IGNORE_NONE);
+    PatchListKey plKey = PatchListKey.againstCommit(null, newId, IGNORE_NONE);
     try {
-      return patchListCache.get(plKey, change.getProject());
+      return patchListCache.get(plKey, new Project.NameKey(change.project));
     } catch (PatchListNotAvailableException e) {
       logger.warn("Could not load patch list: {}", plKey, e);
     }
diff --git a/owners-autoassign/src/main/java/com/vmware/gerrit/owners/common/ReviewerManager.java b/owners-autoassign/src/main/java/com/vmware/gerrit/owners/common/ReviewerManager.java
index e35842d..c30fca9 100644
--- a/owners-autoassign/src/main/java/com/vmware/gerrit/owners/common/ReviewerManager.java
+++ b/owners-autoassign/src/main/java/com/vmware/gerrit/owners/common/ReviewerManager.java
@@ -18,11 +18,12 @@
 
 import com.google.gerrit.extensions.api.GerritApi;
 import com.google.gerrit.extensions.api.changes.AddReviewerInput;
+import com.google.gerrit.extensions.api.changes.ChangeApi;
 import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.common.ChangeInfo;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Account.Id;
-import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.change.ChangesCollection;
 import com.google.gerrit.server.project.ChangeControl;
@@ -40,46 +41,48 @@
 public class ReviewerManager {
   private static final Logger log = LoggerFactory.getLogger(ReviewerManager.class);
 
-  private final GerritApi gApi;
   private final OneOffRequestContext requestContext;
+  private final GerritApi gApi;
   private final IdentifiedUser.GenericFactory userFactory;
-
   private final ChangesCollection changes;
 
   @Inject
   public ReviewerManager(
-      GerritApi gApi,
       OneOffRequestContext requestContext,
+      GerritApi gApi,
       IdentifiedUser.GenericFactory userFactory,
       ChangesCollection changes) {
-    this.gApi = gApi;
     this.requestContext = requestContext;
+    this.gApi = gApi;
     this.userFactory = userFactory;
     this.changes = changes;
   }
 
-  public void addReviewers(Change change, Collection<Account.Id> reviewers)
+  public void addReviewers(ChangeApi cApi, Collection<Account.Id> reviewers)
       throws ReviewerManagerException {
-    try (ManualRequestContext ctx = requestContext.openAs(change.getOwner())) {
-      ChangeControl changeControl = changes.parse(change.getId()).getControl();
-
-      // TODO(davido): Switch back to using changes API again,
-      // when it supports batch mode for adding reviewers
-      ReviewInput in = new ReviewInput();
-      in.reviewers = new ArrayList<>(reviewers.size());
-      for (Account.Id account : reviewers) {
-        if (isVisibleTo(changeControl, account)) {
-          AddReviewerInput addReviewerInput = new AddReviewerInput();
-          addReviewerInput.reviewer = account.toString();
-          in.reviewers.add(addReviewerInput);
-        } else {
-          log.warn(
-              "Not adding account {} as reviewer to change {} because the associated ref is not visible",
-              account,
-              change.getId());
+    try {
+      ChangeInfo changeInfo = cApi.get();
+      try (ManualRequestContext ctx =
+          requestContext.openAs(new Account.Id(changeInfo.owner._accountId))) {
+        ChangeControl changeControl = changes.parse(change.getId()).getControl();
+        // TODO(davido): Switch back to using changes API again,
+        // when it supports batch mode for adding reviewers
+        ReviewInput in = new ReviewInput();
+        in.reviewers = new ArrayList<>(reviewers.size());
+        for (Account.Id account : reviewers) {
+          if (isVisibleTo(changeControl, account)) {
+            AddReviewerInput addReviewerInput = new AddReviewerInput();
+            addReviewerInput.reviewer = account.toString();
+            in.reviewers.add(addReviewerInput);
+          } else {
+            log.warn(
+                "Not adding account {} as reviewer to change {} because the associated ref is not visible",
+                account,
+                change.getId());
+          }
+          gApi.changes().id(changeInfo.id).current().review(in);
         }
       }
-      gApi.changes().id(change.getId().get()).current().review(in);
     } catch (RestApiException | OrmException e) {
       log.error("Couldn't add reviewers to the change", e);
       throw new ReviewerManagerException(e);
diff --git a/owners-autoassign/src/test/java/com/vmware/gerrit/owners/common/GitRefListenerIT.java b/owners-autoassign/src/test/java/com/vmware/gerrit/owners/common/GitRefListenerIT.java
new file mode 100644
index 0000000..f009bde
--- /dev/null
+++ b/owners-autoassign/src/test/java/com/vmware/gerrit/owners/common/GitRefListenerIT.java
@@ -0,0 +1,100 @@
+// 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.vmware.gerrit.owners.common;
+
+import static org.junit.Assert.assertEquals;
+
+import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
+import com.google.gerrit.acceptance.TestPlugin;
+import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
+import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.AnonymousUser;
+import com.google.gerrit.server.util.ManualRequestContext;
+import com.google.gerrit.server.util.ThreadLocalRequestContext;
+import com.google.gwtorm.server.SchemaFactory;
+import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
+import org.eclipse.jgit.transport.ReceiveCommand.Type;
+import org.junit.Test;
+
+@TestPlugin(
+    name = "owners-autoassign",
+    sysModule = "com.vmware.gerrit.owners.common.GitRefListenerIT$TestModule")
+public class GitRefListenerIT extends LightweightPluginDaemonTest {
+
+  @Inject GitRefListenerTest gitRefListener;
+  @Inject SchemaFactory<ReviewDb> schemaFactory;
+  @Inject ThreadLocalRequestContext requestContext;
+
+  String aRefChange = RefNames.REFS_CHANGES + "01/01/01";
+  String anOldObjectId = "anOldRef";
+  String aNewObjectId = "aNewRef";
+
+  public static class TestModule extends AbstractModule {
+    @Override
+    protected void configure() {
+      bind(GitReferenceUpdatedListener.class).to(GitRefListenerTest.class);
+    }
+  }
+
+  @Test
+  public void shouldNotProcessNoteDbOnlyRefs() {
+    ReferenceUpdatedEventTest refUpdatedEvent =
+        new ReferenceUpdatedEventTest(
+            project,
+            RefNames.REFS_CHANGES + "01/01" + RefNames.META_SUFFIX,
+            anOldObjectId,
+            aNewObjectId,
+            Type.CREATE,
+            admin.id);
+
+    gitRefListener.onGitReferenceUpdated(refUpdatedEvent);
+    assertEquals(0, gitRefListener.getProcessedEvents());
+  }
+
+  @Test
+  public void shouldProcessRefChanges() {
+    gitRefListener.onGitReferenceUpdated(newRefUpdateEvent());
+    assertEquals(1, gitRefListener.getProcessedEvents());
+  }
+
+  @Test
+  public void shouldRetrieveChangeFromAnonymousContext() throws Exception {
+    try (ManualRequestContext ctx =
+        new ManualRequestContext(new AnonymousUser(), schemaFactory, requestContext)) {
+      gitRefListener.onGitReferenceUpdated(newRefUpdateEvent());
+      assertEquals(1, gitRefListener.getProcessedEvents());
+    }
+  }
+
+  @Test
+  public void shouldRetrieveChangeFromAnonymousContextWithoutAccountId() throws Exception {
+    ReferenceUpdatedEventTest refUpdateWithoutAccountId =
+        new ReferenceUpdatedEventTest(
+            project, aRefChange, anOldObjectId, aNewObjectId, Type.CREATE, null);
+    try (ManualRequestContext ctx =
+        new ManualRequestContext(new AnonymousUser(), schemaFactory, requestContext)) {
+      gitRefListener.onGitReferenceUpdated(refUpdateWithoutAccountId);
+      assertEquals(1, gitRefListener.getProcessedEvents());
+    }
+  }
+
+  private ReferenceUpdatedEventTest newRefUpdateEvent() {
+    return new ReferenceUpdatedEventTest(
+        project, aRefChange, anOldObjectId, aNewObjectId, Type.CREATE, admin.id);
+  }
+}
diff --git a/owners-autoassign/src/test/java/com/vmware/gerrit/owners/common/GitRefListenerTest.java b/owners-autoassign/src/test/java/com/vmware/gerrit/owners/common/GitRefListenerTest.java
new file mode 100644
index 0000000..8fb940c
--- /dev/null
+++ b/owners-autoassign/src/test/java/com/vmware/gerrit/owners/common/GitRefListenerTest.java
@@ -0,0 +1,59 @@
+// 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.vmware.gerrit.owners.common;
+
+import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.patch.PatchListCache;
+import com.google.gerrit.server.util.OneOffRequestContext;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import org.eclipse.jgit.lib.Repository;
+import org.junit.Ignore;
+
+@Ignore
+public class GitRefListenerTest extends GitRefListener {
+  int processedEvents = 0;
+
+  @Inject
+  public GitRefListenerTest(
+      GerritApi api,
+      PatchListCache patchListCache,
+      GitRepositoryManager repositoryManager,
+      Accounts accounts,
+      ReviewerManager reviewerManager,
+      OneOffRequestContext oneOffReqCtx,
+      Provider<CurrentUser> currentUserProvider) {
+    super(
+        api,
+        patchListCache,
+        repositoryManager,
+        accounts,
+        reviewerManager,
+        oneOffReqCtx,
+        currentUserProvider);
+  }
+
+  @Override
+  void processEvent(Repository repository, Event event) {
+    processedEvents++;
+  }
+
+  int getProcessedEvents() {
+    return processedEvents;
+  }
+}
diff --git a/owners-autoassign/src/test/java/com/vmware/gerrit/owners/common/ReferenceUpdatedEventTest.java b/owners-autoassign/src/test/java/com/vmware/gerrit/owners/common/ReferenceUpdatedEventTest.java
new file mode 100644
index 0000000..9946502
--- /dev/null
+++ b/owners-autoassign/src/test/java/com/vmware/gerrit/owners/common/ReferenceUpdatedEventTest.java
@@ -0,0 +1,100 @@
+// 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.vmware.gerrit.owners.common;
+
+import com.google.gerrit.extensions.api.changes.NotifyHandling;
+import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Account.Id;
+import com.google.gerrit.reviewdb.client.Project;
+import org.eclipse.jgit.transport.ReceiveCommand;
+import org.junit.Ignore;
+
+@Ignore
+public class ReferenceUpdatedEventTest implements GitReferenceUpdatedListener.Event {
+
+  private final String projectName;
+  private final String ref;
+  private final String oldObjectId;
+  private final String newObjectId;
+  private final ReceiveCommand.Type type;
+  private final Id eventAccountId;
+
+  public ReferenceUpdatedEventTest(
+      Project.NameKey project,
+      String ref,
+      String oldObjectId,
+      String newObjectId,
+      ReceiveCommand.Type type,
+      Account.Id eventAccountId) {
+    this.projectName = project.get();
+    this.ref = ref;
+    this.oldObjectId = oldObjectId;
+    this.newObjectId = newObjectId;
+    this.type = type;
+    this.eventAccountId = eventAccountId;
+  }
+
+  @Override
+  public String getProjectName() {
+    return projectName;
+  }
+
+  @Override
+  public String getRefName() {
+    return ref;
+  }
+
+  @Override
+  public String getOldObjectId() {
+    return oldObjectId;
+  }
+
+  @Override
+  public String getNewObjectId() {
+    return newObjectId;
+  }
+
+  @Override
+  public boolean isCreate() {
+    return type == ReceiveCommand.Type.CREATE;
+  }
+
+  @Override
+  public boolean isDelete() {
+    return type == ReceiveCommand.Type.DELETE;
+  }
+
+  @Override
+  public boolean isNonFastForward() {
+    return type == ReceiveCommand.Type.UPDATE_NONFASTFORWARD;
+  }
+
+  @Override
+  public AccountInfo getUpdater() {
+    if (eventAccountId == null) {
+      return null;
+    }
+
+    return new AccountInfo(eventAccountId.get());
+  }
+
+  @Override
+  public NotifyHandling getNotify() {
+    return NotifyHandling.NONE;
+  }
+}
diff --git a/owners-common/src/main/java/com/vmware/gerrit/owners/common/AccountsImpl.java b/owners-common/src/main/java/com/vmware/gerrit/owners/common/AccountsImpl.java
index 07e9af8..a5e7d26 100644
--- a/owners-common/src/main/java/com/vmware/gerrit/owners/common/AccountsImpl.java
+++ b/owners-common/src/main/java/com/vmware/gerrit/owners/common/AccountsImpl.java
@@ -14,8 +14,9 @@
 
 package com.vmware.gerrit.owners.common;
 
-import static com.google.gerrit.server.account.ExternalId.SCHEME_GERRIT;
-import static com.google.gerrit.server.account.ExternalId.SCHEME_MAILTO;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_GERRIT;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_MAILTO;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME;
 
 import com.google.gerrit.common.errors.NoSuchGroupException;
 import com.google.gerrit.reviewdb.client.Account;
@@ -25,9 +26,10 @@
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountResolver;
 import com.google.gerrit.server.account.AccountState;
-import com.google.gerrit.server.account.ExternalId;
 import com.google.gerrit.server.account.GroupCache;
 import com.google.gerrit.server.account.GroupMembers;
+import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.group.InternalGroup;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.util.ManualRequestContext;
 import com.google.gerrit.server.util.OneOffRequestContext;
@@ -38,6 +40,7 @@
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -76,20 +79,20 @@
   }
 
   private Set<Id> findAccountsInGroup(String groupNameOrUUID) {
-    AccountGroup group =
-        Optional.ofNullable(groupCache.get(new AccountGroup.NameKey(groupNameOrUUID)))
+    Optional<InternalGroup> group =
+        groupCache
+            .get(new AccountGroup.NameKey(groupNameOrUUID))
+            .map(Optional::of)
             .orElse(groupCache.get(new AccountGroup.UUID(groupNameOrUUID)));
 
-    if (group == null) {
+    if (!group.isPresent()) {
       log.warn("Group {} was not found", groupNameOrUUID);
+      return Collections.emptySet();
     }
 
     try (ManualRequestContext ctx = oneOffRequestContext.openAs(adminUser.getAccountId())) {
 
-      return groupMembers
-          .create(adminUser)
-          .listAccounts(group.getGroupUUID(), null)
-          .stream()
+      return groupMembers.create(adminUser).listAccounts(group.get().getGroupUUID(), null).stream()
           .map(Account::getId)
           .collect(Collectors.toSet());
     } catch (NoSuchGroupException | NoSuchProjectException | OrmException | IOException e) {
@@ -100,7 +103,7 @@
 
   private Set<Account.Id> findUserOrEmail(String nameOrEmail) {
     try (ManualRequestContext ctx = oneOffRequestContext.open()) {
-      Set<Id> accountIds = resolver.findAll(ctx.getReviewDbProvider().get(), nameOrEmail);
+      Set<Id> accountIds = resolver.findAll(nameOrEmail);
       if (accountIds.isEmpty()) {
         log.warn("User '{}' does not resolve to any account.", nameOrEmail);
         return accountIds;
@@ -118,8 +121,7 @@
       }
 
       Set<Id> fulllyMatchedAccountIds =
-          activeAccountIds
-              .stream()
+          activeAccountIds.stream()
               .filter(id -> isFullMatch(id, nameOrEmail))
               .collect(Collectors.toSet());
       if (fulllyMatchedAccountIds.isEmpty()) {
@@ -132,18 +134,18 @@
       }
 
       return accountIds;
-    } catch (OrmException e) {
+    } catch (OrmException | IOException | ConfigInvalidException e) {
       log.error("Error trying to resolve user " + nameOrEmail, e);
       return Collections.emptySet();
     }
   }
 
   private boolean isFullMatch(Account.Id id, String nameOrEmail) {
-    AccountState account = byId.get(id);
-    return isFullNameMatch(account, nameOrEmail)
-        || account
-            .getExternalIds()
-            .stream()
+    AccountState accountState = byId.get(id);
+    Account account = accountState.getAccount();
+    return isFullNameMatch(accountState, nameOrEmail)
+        || nameOrEmail.equalsIgnoreCase(account.getPreferredEmail())
+        || accountState.getExternalIds().stream()
             .anyMatch(eid -> isEMailMatch(eid, nameOrEmail) || isUsernameMatch(eid, nameOrEmail));
   }
 
@@ -154,7 +156,9 @@
   }
 
   private boolean isUsernameMatch(ExternalId externalId, String username) {
-    return keySchemeRest(SCHEME_GERRIT, externalId.key())
+    return OptionalUtils.combine(
+            keySchemeRest(SCHEME_GERRIT, externalId.key()),
+            keySchemeRest(SCHEME_USERNAME, externalId.key()))
         .filter(name -> name.equals(username))
         .isPresent();
   }
diff --git a/owners-common/src/main/java/com/vmware/gerrit/owners/common/PathOwnersEntry.java b/owners-common/src/main/java/com/vmware/gerrit/owners/common/PathOwnersEntry.java
index 856a20b..a1cf85f 100644
--- a/owners-common/src/main/java/com/vmware/gerrit/owners/common/PathOwnersEntry.java
+++ b/owners-common/src/main/java/com/vmware/gerrit/owners/common/PathOwnersEntry.java
@@ -40,9 +40,7 @@
       String path, OwnersConfig config, Accounts accounts, Set<Account.Id> inheritedOwners) {
     this.ownersPath = path;
     this.owners =
-        config
-            .getOwners()
-            .stream()
+        config.getOwners().stream()
             .flatMap(o -> accounts.find(o).stream())
             .collect(Collectors.toSet());
     if (config.isInherited()) {
diff --git a/owners-common/src/test/java/com/vmware/gerrit/owners/common/Config.java b/owners-common/src/test/java/com/vmware/gerrit/owners/common/Config.java
index 81aa76f..36d2497 100644
--- a/owners-common/src/test/java/com/vmware/gerrit/owners/common/Config.java
+++ b/owners-common/src/test/java/com/vmware/gerrit/owners/common/Config.java
@@ -20,7 +20,6 @@
 
 import com.google.common.base.Charsets;
 import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.patch.PatchList;
 import com.google.gerrit.server.patch.PatchListEntry;
 import java.io.IOException;
@@ -34,7 +33,6 @@
 
 @Ignore
 public abstract class Config {
-  protected ReviewDb db;
   protected Repository repository;
   protected PatchList patchList;
   protected ConfigurationParser parser;
diff --git a/owners/BUILD b/owners/BUILD
index 8068969..d0c1efc 100644
--- a/owners/BUILD
+++ b/owners/BUILD
@@ -35,7 +35,7 @@
         "Implementation-URL: https://gerrit.googlesource.com/plugins/owners",
         "Gerrit-PluginName: owners",
         "Gerrit-Module: com.vmware.gerrit.owners.OwnersModule",
-        "Gerrit-ApiVersion: 2.14",
+        "Gerrit-ApiVersion: 2.15",
     ],
     resources = glob(["src/main/resources/**/*"]),
     deps = [
diff --git a/tools/bzl/classpath.bzl b/tools/bzl/classpath.bzl
index d5764f7..c921d01 100644
--- a/tools/bzl/classpath.bzl
+++ b/tools/bzl/classpath.bzl
@@ -1,4 +1,6 @@
 load(
     "@com_googlesource_gerrit_bazlets//tools:classpath.bzl",
-    "classpath_collector",
+    _classpath_collector = "classpath_collector",
 )
+
+classpath_collector = _classpath_collector
diff --git a/tools/bzl/junit.bzl b/tools/bzl/junit.bzl
index 3af7e58..97307bd 100644
--- a/tools/bzl/junit.bzl
+++ b/tools/bzl/junit.bzl
@@ -1,4 +1,6 @@
 load(
     "@com_googlesource_gerrit_bazlets//tools:junit.bzl",
-    "junit_tests",
+    _junit_tests = "junit_tests",
 )
+
+junit_tests = _junit_tests
diff --git a/tools/bzl/maven_jar.bzl b/tools/bzl/maven_jar.bzl
index 43393b9..ce4730f 100644
--- a/tools/bzl/maven_jar.bzl
+++ b/tools/bzl/maven_jar.bzl
@@ -1 +1,4 @@
-load("@com_googlesource_gerrit_bazlets//tools:maven_jar.bzl", "GERRIT", "maven_jar")
+load("@com_googlesource_gerrit_bazlets//tools:maven_jar.bzl", _GERRIT = "GERRIT", _maven_jar = "maven_jar")
+
+GERRIT = _GERRIT
+maven_jar = _maven_jar
diff --git a/tools/bzl/plugin.bzl b/tools/bzl/plugin.bzl
index d21bdf4..a271493 100644
--- a/tools/bzl/plugin.bzl
+++ b/tools/bzl/plugin.bzl
@@ -1,7 +1,12 @@
 load(
     "@com_googlesource_gerrit_bazlets//:gerrit_plugin.bzl",
-    "PLUGIN_DEPS",
-    "PLUGIN_DEPS_NEVERLINK",
-    "PLUGIN_TEST_DEPS",
-    "gerrit_plugin",
+    _gerrit_plugin = "gerrit_plugin",
+    _plugin_deps = "PLUGIN_DEPS",
+    _plugin_deps_neverlink = "PLUGIN_DEPS_NEVERLINK",
+    _plugin_test_deps = "PLUGIN_TEST_DEPS",
 )
+
+gerrit_plugin = _gerrit_plugin
+PLUGIN_DEPS = _plugin_deps
+PLUGIN_DEPS_NEVERLINK = _plugin_deps_neverlink
+PLUGIN_TEST_DEPS = _plugin_test_deps
diff --git a/tools/genrule2.bzl b/tools/genrule2.bzl
index de66f32..61c4e18 100644
--- a/tools/genrule2.bzl
+++ b/tools/genrule2.bzl
@@ -1 +1,3 @@
-load("@com_googlesource_gerrit_bazlets//tools:genrule2.bzl", "genrule2")
+load("@com_googlesource_gerrit_bazlets//tools:genrule2.bzl", _genrule2 = "genrule2")
+
+genrule2 = _genrule2
diff --git a/tools/workspace-status.sh b/tools/workspace-status.sh
index 35966f1..83f9cdc 100755
--- a/tools/workspace-status.sh
+++ b/tools/workspace-status.sh
@@ -14,4 +14,4 @@
   cd $1; git describe --always --match "v[0-9].*" --dirty
 }
 
-echo STABLE_BUILD_OWNERS-AUTOASSIGN_LABEL $(rev .)
+echo STABLE_BUILD_OWNERS_LABEL $(rev .)