Merge branch 'stable-2.13' into stable-2.14

* stable-2.13:
  Update reviewers on DraftPublishedEvent

Change-Id: I57c8fe5a498ebfa1c82e04aea14ccde7da65efe8
diff --git a/.buckconfig b/.buckconfig
deleted file mode 100644
index 3fd8d47..0000000
--- a/.buckconfig
+++ /dev/null
@@ -1,14 +0,0 @@
-[alias]
-  reviewers = //:reviewers
-  plugin = //:reviewers
-
-[java]
-  src_roots = java, resources
-
-[project]
-  ignore = .git
-
-[cache]
-  mode = dir
-  dir = buck-out/cache
-
diff --git a/.gitignore b/.gitignore
index aa42023..3245346 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,8 @@
 *.pyc
 .buckversion
 /bucklets
+/bazel-bin
+/bazel-genfiles
+/bazel-out
+/bazel-reviewers
+/bazel-testlogs
diff --git a/BUCK b/BUCK
deleted file mode 100644
index b863d0a..0000000
--- a/BUCK
+++ /dev/null
@@ -1,24 +0,0 @@
-include_defs('//bucklets/gerrit_plugin.bucklet')
-
-MODULE = 'com.googlesource.gerrit.plugins.reviewers.ReviewersForm'
-
-gerrit_plugin(
-  name = 'reviewers',
-  srcs = glob(['src/main/java/**/*.java']),
-  resources = glob(['src/main/**/*']),
-  gwt_module = MODULE,
-  manifest_entries = [
-    'Gerrit-PluginName: reviewers',
-    'Gerrit-Module: com.googlesource.gerrit.plugins.reviewers.Module',
-    'Gerrit-HttpModule: com.googlesource.gerrit.plugins.reviewers.HttpModule',
-  ]
-)
-
-java_library(
-  name = 'classpath',
-  deps = GERRIT_GWT_API + GERRIT_PLUGIN_API + [
-    ':reviewers__plugin',
-    '//lib/gwt:user',
-  ],
-)
-
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..6086d5c
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,12 @@
+load("//tools/bzl:plugin.bzl", "gerrit_plugin")
+
+gerrit_plugin(
+    name = "reviewers",
+    srcs = glob(["src/main/java/**/*.java"]),
+    gwt_module = "com.googlesource.gerrit.plugins.reviewers.ReviewersForm",
+    manifest_entries = [
+        "Gerrit-PluginName: reviewers",
+        "Gerrit-Module: com.googlesource.gerrit.plugins.reviewers.Module",
+    ],
+    resources = glob(["src/main/**/*"]),
+)
diff --git a/WORKSPACE b/WORKSPACE
new file mode 100644
index 0000000..5716471
--- /dev/null
+++ b/WORKSPACE
@@ -0,0 +1,30 @@
+workspace(name = "reviewers")
+
+load("//:bazlets.bzl", "load_bazlets")
+
+load_bazlets(
+    commit = "3bec81727c69207e591ae1761d5a78d8ec418a0b",
+    #    local_path = "/home/<user>/projects/bazlets",
+)
+
+# Release 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(
+    "@com_googlesource_gerrit_bazlets//:gerrit_gwt.bzl",
+    "gerrit_gwt",
+)
+
+# Load release Plugin API
+# gerrit_api()
+
+# Load snapshot Plugin API
+gerrit_api_maven_local()
+
+gerrit_gwt()
diff --git a/bazlets.bzl b/bazlets.bzl
new file mode 100644
index 0000000..e14e488
--- /dev/null
+++ b/bazlets.bzl
@@ -0,0 +1,17 @@
+NAME = "com_googlesource_gerrit_bazlets"
+
+def load_bazlets(
+    commit,
+    local_path = None
+  ):
+  if not local_path:
+      native.git_repository(
+          name = NAME,
+          remote = "https://gerrit.googlesource.com/bazlets",
+          commit = commit,
+      )
+  else:
+      native.local_repository(
+          name = NAME,
+          path = local_path,
+      )
diff --git a/lib/gerrit/BUCK b/lib/gerrit/BUCK
deleted file mode 100644
index 88a9696..0000000
--- a/lib/gerrit/BUCK
+++ /dev/null
@@ -1,22 +0,0 @@
-include_defs('//bucklets/maven_jar.bucklet')
-
-VER = '2.13'
-REPO = MAVEN_CENTRAL
-
-maven_jar(
-  name = 'plugin-api',
-  id = 'com.google.gerrit:gerrit-plugin-api:' + VER,
-  sha1 = 'e25d55b8f41627c4ae6b9d2069ec398638b219a3',
-  license = 'Apache2.0',
-  attach_source = False,
-  repository = REPO,
-)
-
-maven_jar(
-  name = 'gwtui-api',
-  id = 'com.google.gerrit:gerrit-plugin-gwtui:' + VER,
-  sha1 = '0890414f42fc1fd0fef0400a479836f558727234',
-  license = 'Apache2.0',
-  attach_source = False,
-  repository = REPO,
-)
diff --git a/lib/gwt/BUCK b/lib/gwt/BUCK
deleted file mode 100644
index b8d9491..0000000
--- a/lib/gwt/BUCK
+++ /dev/null
@@ -1,34 +0,0 @@
-include_defs('//bucklets/maven_jar.bucklet')
-
-VERSION = '2.7.0'
-
-maven_jar(
-  name = 'user',
-  id = 'com.google.gwt:gwt-user:' + VERSION,
-  sha1 = 'bdc7af42581745d3d79c2efe0b514f432b998a5b',
-  license = 'Apache2.0',
-  attach_source = False,
-)
-
-maven_jar(
-  name = 'dev',
-  id = 'com.google.gwt:gwt-dev:' + VERSION,
-  sha1 = 'c2c3dd5baf648a0bb199047a818be5e560f48982',
-  license = 'Apache2.0',
-  deps = [
-    ':javax-validation',
-    ':javax-validation_src',
-  ],
-  attach_source = False,
-  exclude = ['org/eclipse/jetty/*'],
-)
-
-maven_jar(
-  name = 'javax-validation',
-  id = 'javax.validation:validation-api:1.0.0.GA',
-  bin_sha1 = 'b6bd7f9d78f6fdaa3c37dae18a4bd298915f328e',
-  src_sha1 = '7a561191db2203550fbfa40d534d4997624cd369',
-  license = 'Apache2.0',
-  visibility = [],
-)
-
diff --git a/lib/ow2/BUCK b/lib/ow2/BUCK
deleted file mode 100644
index db6c76c..0000000
--- a/lib/ow2/BUCK
+++ /dev/null
@@ -1,32 +0,0 @@
-include_defs('//bucklets/maven_jar.bucklet')
-
-VERSION = '5.0.3'
-
-maven_jar(
-  name = 'ow2-asm',
-  id = 'org.ow2.asm:asm:' + VERSION,
-  sha1 = 'dcc2193db20e19e1feca8b1240dbbc4e190824fa',
-  license = 'ow2',
-)
-
-maven_jar(
-  name = 'ow2-asm-analysis',
-  id = 'org.ow2.asm:asm-analysis:' + VERSION,
-  sha1 = 'c7126aded0e8e13fed5f913559a0dd7b770a10f3',
-  license = 'ow2',
-)
-
-maven_jar(
-  name = 'ow2-asm-tree',
-  id = 'org.ow2.asm:asm-tree:' + VERSION,
-  sha1 = '287749b48ba7162fb67c93a026d690b29f410bed',
-  license = 'ow2',
-)
-
-maven_jar(
-  name = 'ow2-asm-util',
-  id = 'org.ow2.asm:asm-util:' + VERSION,
-  sha1 = '1512e5571325854b05fb1efce1db75fcced54389',
-  license = 'ow2',
-)
-
diff --git a/pom.xml b/pom.xml
index 47da116..78ead82 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
   <groupId>com.googlesource.gerrit.plugins.reviewers</groupId>
   <artifactId>reviewers</artifactId>
   <packaging>jar</packaging>
-  <version>2.13</version>
+  <version>2.14-SNAPSHOT</version>
   <name>reviewers</name>
 
   <properties>
@@ -41,7 +41,6 @@
             <manifestEntries>
               <Gerrit-PluginName>reviewers</Gerrit-PluginName>
               <Gerrit-Module>com.googlesource.gerrit.plugins.reviewers.Module</Gerrit-Module>
-              <Gerrit-HttpModule>com.googlesource.gerrit.plugins.reviewers.HttpModule</Gerrit-HttpModule>
               <Implementation-Vendor>Gerrit Code Review</Implementation-Vendor>
               <Implementation-URL>http://code.google.com/p/gerrit/</Implementation-URL>
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/Action.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/Action.java
index 315ed7d..04a15fc 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/Action.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/Action.java
@@ -15,5 +15,6 @@
 package com.googlesource.gerrit.plugins.reviewers;
 
 public enum Action {
-  ADD, REMOVE
+  ADD,
+  REMOVE
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ChangeEventListener.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ChangeEventListener.java
index 3811d01..f0419ab 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ChangeEventListener.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ChangeEventListener.java
@@ -20,8 +20,10 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
-import com.google.gerrit.common.EventListener;
 import com.google.gerrit.common.errors.NoSuchGroupException;
+import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.events.DraftPublishedListener;
+import com.google.gerrit.extensions.events.RevisionCreatedListener;
 import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Change;
@@ -32,10 +34,6 @@
 import com.google.gerrit.server.account.AccountByEmailCache;
 import com.google.gerrit.server.account.AccountResolver;
 import com.google.gerrit.server.account.GroupMembers;
-import com.google.gerrit.server.data.ChangeAttribute;
-import com.google.gerrit.server.events.DraftPublishedEvent;
-import com.google.gerrit.server.events.Event;
-import com.google.gerrit.server.events.PatchSetCreatedEvent;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.gerrit.server.group.GroupsCollection;
@@ -52,20 +50,17 @@
 import com.google.inject.Provider;
 import com.google.inject.ProvisionException;
 import com.google.inject.Singleton;
-
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
-import java.util.List;
-import java.util.Set;
-
 @Singleton
-class ChangeEventListener implements EventListener {
-  private static final Logger log = LoggerFactory
-      .getLogger(ChangeEventListener.class);
+class ChangeEventListener implements RevisionCreatedListener, DraftPublishedListener {
+  private static final Logger log = LoggerFactory.getLogger(ChangeEventListener.class);
 
   private final AccountResolver accountResolver;
   private final AccountByEmailCache byEmailCache;
@@ -115,23 +110,20 @@
   }
 
   @Override
-  public void onEvent(Event event) {
-    if (event instanceof PatchSetCreatedEvent) {
-      PatchSetCreatedEvent e = (PatchSetCreatedEvent) event;
-      ChangeAttribute c = e.change.get();
-      onEvent(new Project.NameKey(c.project),
-          Integer.parseInt(e.change.get().number), e.uploader.get().email);
-    } else if (event instanceof DraftPublishedEvent) {
-      DraftPublishedEvent e = (DraftPublishedEvent) event;
-      ChangeAttribute c = e.change.get();
-      onEvent(new Project.NameKey(c.project),
-          Integer.parseInt(e.change.get().number), e.uploader.get().email);
-    }
+  public void onRevisionCreated(
+      com.google.gerrit.extensions.events.RevisionCreatedListener.Event event) {
+    ChangeInfo c = event.getChange();
+    onEvent(new Project.NameKey(c.project), c._number, event.getWho().email);
   }
 
-  private void onEvent(Project.NameKey projectName, int changeNumber,
-      String email) {
+  @Override
+  public void onDraftPublished(
+      com.google.gerrit.extensions.events.DraftPublishedListener.Event event) {
+    ChangeInfo c = event.getChange();
+    onEvent(new Project.NameKey(c.project), c._number, event.getWho().email);
+  }
 
+  private void onEvent(Project.NameKey projectName, int changeNumber, String email) {
     // TODO(davido): we have to cache per project configuration
     ReviewersConfig config = configFactory.create(projectName);
     List<ReviewerFilterSection> sections = config.getReviewerFilterSections();
@@ -143,67 +135,71 @@
     try (Repository git = repoManager.openRepository(projectName);
         RevWalk rw = new RevWalk(git);
         ReviewDb reviewDb = schemaFactory.open()) {
-      ChangeData changeData = changeDataFactory.create(
-          reviewDb, projectName, new Change.Id(changeNumber));
+      ChangeData changeData =
+          changeDataFactory.create(reviewDb, projectName, new Change.Id(changeNumber));
       Set<String> reviewers = findReviewers(sections, changeData);
       if (reviewers.isEmpty()) {
         return;
       }
 
       final Change change = changeData.change();
-      final Runnable task = reviewersFactory.create(change,
-          toAccounts(reviewDb, reviewers, projectName, email));
+      final Runnable task =
+          reviewersFactory.create(change, toAccounts(reviewDb, reviewers, projectName, email));
 
-      workQueue.getDefaultQueue().submit(new Runnable() {
-        ReviewDb db = null;
+      workQueue
+          .getDefaultQueue()
+          .submit(
+              new Runnable() {
+                ReviewDb db = null;
 
-        @Override
-        public void run() {
-          RequestContext old = tl.setContext(new RequestContext() {
-
-            @Override
-            public CurrentUser getUser() {
-              return identifiedUserFactory.create(change.getOwner());
-            }
-
-            @Override
-            public Provider<ReviewDb> getReviewDbProvider() {
-              return new Provider<ReviewDb>() {
                 @Override
-                public ReviewDb get() {
-                  if (db == null) {
-                    try {
-                      db = schemaFactory.open();
-                    } catch (OrmException e) {
-                      throw new ProvisionException("Cannot open ReviewDb", e);
+                public void run() {
+                  RequestContext old =
+                      tl.setContext(
+                          new RequestContext() {
+
+                            @Override
+                            public CurrentUser getUser() {
+                              return identifiedUserFactory.create(change.getOwner());
+                            }
+
+                            @Override
+                            public Provider<ReviewDb> getReviewDbProvider() {
+                              return new Provider<ReviewDb>() {
+                                @Override
+                                public ReviewDb get() {
+                                  if (db == null) {
+                                    try {
+                                      db = schemaFactory.open();
+                                    } catch (OrmException e) {
+                                      throw new ProvisionException("Cannot open ReviewDb", e);
+                                    }
+                                  }
+                                  return db;
+                                }
+                              };
+                            }
+                          });
+                  try {
+                    task.run();
+                  } finally {
+                    tl.setContext(old);
+                    if (db != null) {
+                      db.close();
+                      db = null;
                     }
                   }
-                  return db;
                 }
-              };
-            }
-          });
-          try {
-            task.run();
-          } finally {
-            tl.setContext(old);
-            if (db != null) {
-              db.close();
-              db = null;
-            }
-          }
-        }
-      });
+              });
     } catch (OrmException | IOException | QueryParseException x) {
       log.error(x.getMessage(), x);
     }
   }
 
-  private Set<String> findReviewers(List<ReviewerFilterSection> sections,
-      ChangeData changeData) throws OrmException, QueryParseException {
+  private Set<String> findReviewers(List<ReviewerFilterSection> sections, ChangeData changeData)
+      throws OrmException, QueryParseException {
     ImmutableSet.Builder<String> reviewers = ImmutableSet.builder();
-    List<ReviewerFilterSection> found = findReviewerSections(sections,
-        changeData);
+    List<ReviewerFilterSection> found = findReviewerSections(sections, changeData);
     for (ReviewerFilterSection s : found) {
       reviewers.addAll(s.getReviewers());
     }
@@ -212,11 +208,10 @@
 
   private List<ReviewerFilterSection> findReviewerSections(
       List<ReviewerFilterSection> sections, ChangeData changeData)
-          throws OrmException, QueryParseException {
+      throws OrmException, QueryParseException {
     ImmutableList.Builder<ReviewerFilterSection> found = ImmutableList.builder();
     for (ReviewerFilterSection s : sections) {
-      if (Strings.isNullOrEmpty(s.getFilter())
-          || s.getFilter().equals("*")) {
+      if (Strings.isNullOrEmpty(s.getFilter()) || s.getFilter().equals("*")) {
         found.add(s);
       } else if (filterMatch(s.getFilter(), changeData)) {
         found.add(s);
@@ -236,8 +231,8 @@
     return filterPredicate.asMatchable().match(changeData);
   }
 
-  private Set<Account> toAccounts(ReviewDb reviewDb, Set<String> in,
-      Project.NameKey p, String uploaderEMail) {
+  private Set<Account> toAccounts(
+      ReviewDb reviewDb, Set<String> in, Project.NameKey p, String uploaderEMail) {
     Set<Account> reviewers = Sets.newHashSetWithExpectedSize(in.size());
     GroupMembers groupMembers = null;
     for (String r : in) {
@@ -255,18 +250,17 @@
       }
       if (groupMembers == null) {
         groupMembers =
-            groupMembersFactory.create(identifiedUserFactory.create(Iterables
-                .getOnlyElement(byEmailCache.get(uploaderEMail))));
+            groupMembersFactory.create(
+                identifiedUserFactory.create(
+                    Iterables.getOnlyElement(byEmailCache.get(uploaderEMail))));
       }
       try {
-        reviewers.addAll(groupMembers.listAccounts(
-            groupsCollection.get().parse(r).getGroupUUID(), p));
+        reviewers.addAll(
+            groupMembers.listAccounts(groupsCollection.get().parse(r).getGroupUUID(), p));
       } catch (UnprocessableEntityException | NoSuchGroupException e) {
-        log.warn(String.format(
-            "Reviewer %s is neither an account nor a group", r));
+        log.warn(String.format("Reviewer %s is neither an account nor a group", r));
       } catch (NoSuchProjectException e) {
-        log.warn(String.format(
-            "Failed to list accounts for group %s and project %s", r, p));
+        log.warn(String.format("Failed to list accounts for group %s and project %s", r, p));
       } catch (IOException | OrmException e) {
         log.warn(String.format("Failed to list accounts for group %s", r), e);
       }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/DefaultReviewers.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/DefaultReviewers.java
index d721227..a26e6c1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/DefaultReviewers.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/DefaultReviewers.java
@@ -17,22 +17,18 @@
 import com.google.gerrit.extensions.api.GerritApi;
 import com.google.gerrit.extensions.api.changes.AddReviewerInput;
 import com.google.gerrit.extensions.api.changes.ReviewInput;
-import com.google.gerrit.extensions.api.changes.ChangeApi;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
-
+import java.util.ArrayList;
+import java.util.Set;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.Set;
-
 class DefaultReviewers implements Runnable {
-  private static final Logger log = LoggerFactory
-      .getLogger(DefaultReviewers.class);
+  private static final Logger log = LoggerFactory.getLogger(DefaultReviewers.class);
 
   private final GerritApi gApi;
   private final Change change;
@@ -43,10 +39,7 @@
   }
 
   @Inject
-  DefaultReviewers(
-      GerritApi gApi,
-      @Assisted Change change,
-      @Assisted Set<Account> reviewers) {
+  DefaultReviewers(GerritApi gApi, @Assisted Change change, @Assisted Set<Account> reviewers) {
     this.gApi = gApi;
     this.change = change;
     this.reviewers = reviewers;
@@ -74,10 +67,7 @@
         addReviewerInput.reviewer = account.getId().toString();
         in.reviewers.add(addReviewerInput);
       }
-      gApi.changes()
-          .id(change.getId().get())
-          .current()
-          .review(in);
+      gApi.changes().id(change.getId().get()).current().review(in);
     } catch (RestApiException e) {
       log.error("Couldn't add reviewers to the change", e);
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/GetReviewers.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/GetReviewers.java
index 77cd4b8..b0e735f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/GetReviewers.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/GetReviewers.java
@@ -21,7 +21,6 @@
 import com.google.gerrit.server.project.ProjectResource;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
-
 import java.util.List;
 
 @Singleton
@@ -34,8 +33,8 @@
   }
 
   @Override
-  public List<ReviewerFilterSection> apply(ProjectResource resource) throws AuthException,
-      BadRequestException, ResourceConflictException, Exception {
+  public List<ReviewerFilterSection> apply(ProjectResource resource)
+      throws AuthException, BadRequestException, ResourceConflictException, Exception {
     return configFactory.create(resource.getNameKey()).getReviewerFilterSections();
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/HttpModule.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/HttpModule.java
deleted file mode 100644
index 213cdaa..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/HttpModule.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (C) 2014 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.googlesource.gerrit.plugins.reviewers;
-
-import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.gerrit.extensions.webui.GwtPlugin;
-import com.google.gerrit.extensions.webui.WebUiPlugin;
-import com.google.gerrit.httpd.plugins.HttpPluginModule;
-
-public class HttpModule extends HttpPluginModule {
-  @Override
-  protected void configureServlets() {
-    DynamicSet.bind(binder(), WebUiPlugin.class)
-      .toInstance(new GwtPlugin("reviewers"));
-  }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/Module.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/Module.java
index 86b40c4..98dad1b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/Module.java
@@ -16,15 +16,16 @@
 
 import static com.google.gerrit.server.project.ProjectResource.PROJECT_KIND;
 
-import com.google.gerrit.common.EventListener;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.config.FactoryModule;
+import com.google.gerrit.extensions.events.RevisionCreatedListener;
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.extensions.restapi.RestApiModule;
+import com.google.gerrit.extensions.webui.GwtPlugin;
 import com.google.gerrit.extensions.webui.TopMenu;
+import com.google.gerrit.extensions.webui.WebUiPlugin;
 import com.google.gerrit.server.config.PluginConfigFactory;
 import com.google.inject.Inject;
-
 import org.eclipse.jgit.lib.Config;
 
 public class Module extends FactoryModule {
@@ -32,34 +33,38 @@
   private final boolean enableREST;
 
   @Inject
-  public Module(@PluginName String pluginName,
-      PluginConfigFactory pluginCfgFactory) {
+  public Module(@PluginName String pluginName, PluginConfigFactory pluginCfgFactory) {
     Config c = pluginCfgFactory.getGlobalPluginConfig(pluginName);
     this.enableREST = c.getBoolean("reviewers", null, "enableREST", true);
-    this.enableUI = enableREST
-        ? c.getBoolean("reviewers", null, "enableUI", true)
-        : false;
+    this.enableUI = enableREST ? c.getBoolean("reviewers", null, "enableUI", true) : false;
+  }
+
+  public Module(boolean enableUI, boolean enableREST) {
+    this.enableUI = enableUI;
+    this.enableREST = enableREST;
   }
 
   @Override
   protected void configure() {
     if (enableUI) {
-      DynamicSet.bind(binder(), TopMenu.class).to(
-          ReviewersTopMenu.class);
+      DynamicSet.bind(binder(), TopMenu.class).to(ReviewersTopMenu.class);
+      DynamicSet.bind(binder(), WebUiPlugin.class).toInstance(new GwtPlugin("reviewers"));
     }
-    DynamicSet.bind(binder(), EventListener.class).to(
-        ChangeEventListener.class);
+
+    DynamicSet.bind(binder(), RevisionCreatedListener.class).to(ChangeEventListener.class);
     factory(DefaultReviewers.Factory.class);
     factory(ReviewersConfig.Factory.class);
+
     if (enableREST) {
-      install(new RestApiModule() {
-        @Override
-        protected void configure() {
-          get(PROJECT_KIND, "reviewers").to(GetReviewers.class);
-          put(PROJECT_KIND, "reviewers").to(PutReviewers.class);
-          get(PROJECT_KIND, "suggest_reviewers").to(SuggestProjectReviewers.class);
-        }
-      });
+      install(
+          new RestApiModule() {
+            @Override
+            protected void configure() {
+              get(PROJECT_KIND, "reviewers").to(GetReviewers.class);
+              put(PROJECT_KIND, "reviewers").to(PutReviewers.class);
+              get(PROJECT_KIND, "suggest_reviewers").to(SuggestProjectReviewers.class);
+            }
+          });
     }
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/PutReviewers.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/PutReviewers.java
index b83ea10..48c35fb 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/PutReviewers.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/PutReviewers.java
@@ -32,21 +32,17 @@
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
-
 import com.googlesource.gerrit.plugins.reviewers.PutReviewers.Input;
-
+import java.io.IOException;
+import java.util.List;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
-import java.util.List;
-
 @Singleton
 class PutReviewers implements RestModifyView<ProjectResource, Input> {
-  private static final Logger log = LoggerFactory
-      .getLogger(PutReviewers.class);
+  private static final Logger log = LoggerFactory.getLogger(PutReviewers.class);
 
   public static class Input {
     public Action action;
@@ -63,7 +59,8 @@
   private final Provider<ReviewDb> reviewDbProvider;
 
   @Inject
-  PutReviewers(@PluginName String pluginName,
+  PutReviewers(
+      @PluginName String pluginName,
       ReviewersConfig.Factory configFactory,
       Provider<MetaDataUpdate.User> metaDataUpdateFactory,
       ProjectCache projectCache,
@@ -85,8 +82,7 @@
     Project.NameKey projectName = rsrc.getNameKey();
     ReviewersConfig cfg = configFactory.create(projectName);
     if (!rsrc.getControl().isOwner() || cfg == null) {
-      throw new ResourceNotFoundException(
-          "Project" + projectName.get() + " not found");
+      throw new ResourceNotFoundException("Project" + projectName.get() + " not found");
     }
 
     try (MetaDataUpdate md = metaDataUpdateFactory.get().create(projectName)) {
@@ -94,20 +90,21 @@
         validateReviewer(input.reviewer);
       }
       try {
-        StringBuilder message = new StringBuilder(pluginName)
-            .append(" plugin: ");
+        StringBuilder message = new StringBuilder(pluginName).append(" plugin: ");
         cfg.load(md);
         if (input.action == Action.ADD) {
-          message.append("Add reviewer ")
-            .append(input.reviewer)
-            .append(" to filter ")
-            .append(input.filter);
+          message
+              .append("Add reviewer ")
+              .append(input.reviewer)
+              .append(" to filter ")
+              .append(input.filter);
           cfg.addReviewer(input.filter, input.reviewer);
         } else {
-          message.append("Remove reviewer ")
-            .append(input.reviewer)
-            .append(" from filter ")
-            .append(input.filter);
+          message
+              .append("Remove reviewer ")
+              .append(input.reviewer)
+              .append(" from filter ")
+              .append(input.filter);
           cfg.removeReviewer(input.filter, input.reviewer);
         }
         message.append("\n");
@@ -117,17 +114,17 @@
           projectCache.evict(projectName);
         } catch (IOException e) {
           if (e.getCause() instanceof ConfigInvalidException) {
-            throw new ResourceConflictException("Cannot update " + projectName
-                + ": " + e.getCause().getMessage());
+            throw new ResourceConflictException(
+                "Cannot update " + projectName + ": " + e.getCause().getMessage());
           }
           throw new ResourceConflictException("Cannot update " + projectName);
         }
       } catch (ConfigInvalidException err) {
-        throw new ResourceConflictException("Cannot read " + pluginName
-            + " configurations for project " + projectName, err);
+        throw new ResourceConflictException(
+            "Cannot read " + pluginName + " configurations for project " + projectName, err);
       } catch (IOException err) {
-        throw new ResourceConflictException("Cannot update " + pluginName
-            + " configurations for project " + projectName, err);
+        throw new ResourceConflictException(
+            "Cannot update " + pluginName + " configurations for project " + projectName, err);
       }
     } catch (RepositoryNotFoundException err) {
       throw new ResourceNotFoundException(projectName.get());
@@ -144,8 +141,7 @@
         try {
           groupsCollection.get().parse(reviewer);
         } catch (UnprocessableEntityException e) {
-          throw new ResourceNotFoundException(
-              "Account or group " + reviewer + " not found");
+          throw new ResourceNotFoundException("Account or group " + reviewer + " not found");
         }
       }
     } catch (OrmException e) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewerFilterSection.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewerFilterSection.java
index 58e7c89..1112bdd 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewerFilterSection.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewerFilterSection.java
@@ -20,8 +20,7 @@
   private final String filter;
   private final Set<String> reviewers;
 
-  ReviewerFilterSection(String filter,
-      Set<String> reviewers) {
+  ReviewerFilterSection(String filter, Set<String> reviewers) {
     this.filter = filter;
     this.reviewers = reviewers;
   }
@@ -33,4 +32,4 @@
   Set<String> getReviewers() {
     return reviewers;
   }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewersConfig.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewersConfig.java
index 4b8d1ff..6ee15ce 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewersConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewersConfig.java
@@ -25,15 +25,13 @@
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
-
-import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.eclipse.jgit.lib.CommitBuilder;
-import org.eclipse.jgit.lib.Config;
-
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.Config;
 
 class ReviewersConfig extends VersionedMetaData {
   private static final String FILENAME = "reviewers.config";
@@ -46,12 +44,12 @@
   }
 
   @Inject
-  ReviewersConfig(PluginConfigFactory cfgFactory,
+  ReviewersConfig(
+      PluginConfigFactory cfgFactory,
       @PluginName String pluginName,
       @Assisted Project.NameKey projectName)
       throws NoSuchProjectException {
-    cfg = cfgFactory.getProjectPluginConfigWithInheritance(projectName,
-        pluginName);
+    cfg = cfgFactory.getProjectPluginConfigWithInheritance(projectName, pluginName);
   }
 
   List<ReviewerFilterSection> getReviewerFilterSections() {
@@ -64,8 +62,8 @@
 
   void addReviewer(String filter, String reviewer) {
     if (!newReviewerFilterSection(filter).getReviewers().contains(reviewer)) {
-      List<String> values = new ArrayList<>(Arrays.asList(cfg.getStringList(
-          FILTER, filter, REVIEWER)));
+      List<String> values =
+          new ArrayList<>(Arrays.asList(cfg.getStringList(FILTER, filter, REVIEWER)));
       values.add(reviewer);
       cfg.setStringList(FILTER, filter, REVIEWER, values);
     }
@@ -73,8 +71,8 @@
 
   void removeReviewer(String filter, String reviewer) {
     if (newReviewerFilterSection(filter).getReviewers().contains(reviewer)) {
-      List<String> values = new ArrayList<>(Arrays.asList(cfg.getStringList(
-          FILTER, filter, REVIEWER)));
+      List<String> values =
+          new ArrayList<>(Arrays.asList(cfg.getStringList(FILTER, filter, REVIEWER)));
       values.remove(reviewer);
       if (values.isEmpty()) {
         cfg.unsetSection(FILTER, filter);
@@ -103,8 +101,7 @@
   }
 
   @Override
-  protected boolean onSave(CommitBuilder commit) throws IOException,
-      ConfigInvalidException {
+  protected boolean onSave(CommitBuilder commit) throws IOException, ConfigInvalidException {
     if (Strings.isNullOrEmpty(commit.getMessage())) {
       commit.setMessage("Update reviewers configuration\n");
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewersTopMenu.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewersTopMenu.java
index b905858..2c839a0 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewersTopMenu.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ReviewersTopMenu.java
@@ -19,7 +19,6 @@
 import com.google.gerrit.extensions.client.MenuItem;
 import com.google.gerrit.extensions.webui.TopMenu;
 import com.google.inject.Inject;
-
 import java.util.Collections;
 import java.util.List;
 
@@ -29,9 +28,11 @@
   @Inject
   ReviewersTopMenu(@PluginName String pluginName) {
     menuEntries = Lists.newArrayList();
-    menuEntries.add(new MenuEntry("Projects", Collections.singletonList(
-        new MenuItem(
-            "Reviewers", "#/x/" + pluginName + "/p/${projectName}", "_self"))));
+    menuEntries.add(
+        new MenuEntry(
+            "Projects",
+            Collections.singletonList(
+                new MenuItem("Reviewers", "#/x/" + pluginName + "/p/${projectName}", "_self"))));
   }
 
   @Override
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/SuggestProjectReviewers.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/SuggestProjectReviewers.java
index c251941..f71c591 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/SuggestProjectReviewers.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/SuggestProjectReviewers.java
@@ -21,26 +21,24 @@
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.ReviewersUtil;
-import com.google.gerrit.server.IdentifiedUser.GenericFactory;
 import com.google.gerrit.server.ReviewersUtil.VisibilityControl;
 import com.google.gerrit.server.account.AccountVisibility;
-import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.change.SuggestReviewers;
+import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.project.ProjectResource;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
-
-import org.eclipse.jgit.lib.Config;
-
 import java.io.IOException;
 import java.util.List;
+import org.eclipse.jgit.lib.Config;
 
 public class SuggestProjectReviewers extends SuggestReviewers
-      implements RestReadView<ProjectResource> {
+    implements RestReadView<ProjectResource> {
   @Inject
-  SuggestProjectReviewers(AccountVisibility av,
-      GenericFactory identifiedUserFactory,
+  SuggestProjectReviewers(
+      AccountVisibility av,
+      IdentifiedUser.GenericFactory identifiedUserFactory,
       Provider<ReviewDb> dbProvider,
       @GerritServerConfig Config cfg,
       ReviewersUtil reviewersUtil) {
@@ -50,18 +48,16 @@
   @Override
   public List<SuggestedReviewerInfo> apply(ProjectResource rsrc)
       throws BadRequestException, OrmException, IOException {
-    return reviewersUtil.suggestReviewers(this, rsrc.getControl(),
-        getVisibility(rsrc));
+    return reviewersUtil.suggestReviewers(null, this, rsrc.getControl(), getVisibility(rsrc), true);
   }
 
   private VisibilityControl getVisibility(final ProjectResource rsrc) {
     return new VisibilityControl() {
       @Override
       public boolean isVisibleTo(Account.Id account) throws OrmException {
-        IdentifiedUser who =
-            identifiedUserFactory.create(account);
+        IdentifiedUser who = identifiedUserFactory.create(account);
         return rsrc.getControl().forUser(who).isVisible();
       }
     };
   }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/Action.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/Action.java
index 52b7091..96ebd14 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/Action.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/Action.java
@@ -15,5 +15,6 @@
 package com.googlesource.gerrit.plugins.reviewers.client;
 
 public enum Action {
-  ADD, REMOVE
+  ADD,
+  REMOVE
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ChangeReviewersInput.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ChangeReviewersInput.java
index d5f955e..9560feb 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ChangeReviewersInput.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ChangeReviewersInput.java
@@ -21,19 +21,15 @@
     return (ChangeReviewersInput) createObject();
   }
 
-  protected ChangeReviewersInput() {
-  }
+  protected ChangeReviewersInput() {}
 
   final void setAction(Action a) {
     setActionRaw(a.name());
   }
 
-  final native void setActionRaw(String a)
-  /*-{ if(a)this.action=a; }-*/;
+  final native void setActionRaw(String a) /*-{ if(a)this.action=a; }-*/;
 
-  final native void setFilter(String f)
-  /*-{ if(f)this.filter=f; }-*/;
+  final native void setFilter(String f) /*-{ if(f)this.filter=f; }-*/;
 
-  final native void setReviewer(String r)
-  /*-{ if(r)this.reviewer=r; }-*/;
+  final native void setReviewer(String r) /*-{ if(r)this.reviewer=r; }-*/;
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ProjectAccessInfo.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ProjectAccessInfo.java
index 20db766..48010ed 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ProjectAccessInfo.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ProjectAccessInfo.java
@@ -19,6 +19,5 @@
 public class ProjectAccessInfo extends JavaScriptObject {
   public final native boolean isOwner() /*-{ return this.is_owner ? true : false; }-*/;
 
-  protected ProjectAccessInfo() {
-  }
+  protected ProjectAccessInfo() {}
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ReviewerFilterSection.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ReviewerFilterSection.java
index f7088a4..eed5448 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ReviewerFilterSection.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ReviewerFilterSection.java
@@ -19,8 +19,8 @@
 
 public class ReviewerFilterSection extends JavaScriptObject {
   public final native String filter() /*-{ return this.filter; }-*/;
+
   public final native JsArrayString reviewers() /*-{ return this.reviewers; }-*/;
 
-  protected ReviewerFilterSection() {
-  }
+  protected ReviewerFilterSection() {}
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ReviewerSuggestOracle.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ReviewerSuggestOracle.java
index 42d0026..2f601dc 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ReviewerSuggestOracle.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ReviewerSuggestOracle.java
@@ -15,13 +15,12 @@
 package com.googlesource.gerrit.plugins.reviewers.client;
 
 import com.google.gerrit.client.rpc.NativeMap;
+import com.google.gerrit.client.rpc.Natives;
+import com.google.gerrit.client.ui.HighlightSuggestion;
 import com.google.gerrit.plugin.client.rpc.RestApi;
 import com.google.gwt.core.client.JavaScriptObject;
 import com.google.gwt.user.client.rpc.AsyncCallback;
 import com.google.gwt.user.client.ui.SuggestOracle;
-import com.google.gerrit.client.rpc.Natives;
-import com.google.gerrit.client.ui.HighlightSuggestion;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -60,10 +59,8 @@
       this.name = groupName;
     }
 
-    ReviewerSuggestion(String query, String fullname, String email,
-        String accountId) {
-      super(query, fullname
-          + ((!email.isEmpty()) ? " <" + email + ">" : " (" + accountId + ")"));
+    ReviewerSuggestion(String query, String fullname, String email, String accountId) {
+      super(query, fullname + ((!email.isEmpty()) ? " <" + email + ">" : " (" + accountId + ")"));
       this.name = fullname;
     }
 
@@ -84,36 +81,36 @@
     if (req.getLimit() > 0) {
       rest.addParameter("n", req.getLimit());
     }
-    rest.get(new AsyncCallback<NativeMap<JavaScriptObject>>() {
-      @Override
-      public void onSuccess(NativeMap<JavaScriptObject> result) {
-        List<String> keys0 = result.sortedKeys();
-        List<Suggestion> suggestions = new ArrayList<>(keys0.size());
-        for (String key0 : keys0) {
-          Set<String> keys1 = Natives.keys(result.get(key0));
-          NativeMap<JavaScriptObject> map1 = result.get(key0).cast();
-          for (String key1 : keys1) {
-            NativeMap<JavaScriptObject> map2 = map1.get(key1).cast();
-            String name =  map2.get(NAME_KEY).toString();
-            if (ACCOUNT_KEY.equals(key1)) {
-              String email = (map2.containsKey(EMAIL_KEY))
-                  ? map2.get(EMAIL_KEY).toString() : "";
-              String accountId = map2.get(ACCOUNT_ID_KEY).toString();
-              suggestions
-                  .add(new ReviewerSuggestion(req.getQuery(), name, email, accountId));
-            } else if (GROUP_KEY.equals(key1)) {
-              suggestions.add(new ReviewerSuggestion(req.getQuery(), name));
+    rest.get(
+        new AsyncCallback<NativeMap<JavaScriptObject>>() {
+          @Override
+          public void onSuccess(NativeMap<JavaScriptObject> result) {
+            List<String> keys0 = result.sortedKeys();
+            List<Suggestion> suggestions = new ArrayList<>(keys0.size());
+            for (String key0 : keys0) {
+              Set<String> keys1 = Natives.keys(result.get(key0));
+              NativeMap<JavaScriptObject> map1 = result.get(key0).cast();
+              for (String key1 : keys1) {
+                NativeMap<JavaScriptObject> map2 = map1.get(key1).cast();
+                String name = map2.get(NAME_KEY).toString();
+                if (ACCOUNT_KEY.equals(key1)) {
+                  String email =
+                      (map2.containsKey(EMAIL_KEY)) ? map2.get(EMAIL_KEY).toString() : "";
+                  String accountId = map2.get(ACCOUNT_ID_KEY).toString();
+                  suggestions.add(new ReviewerSuggestion(req.getQuery(), name, email, accountId));
+                } else if (GROUP_KEY.equals(key1)) {
+                  suggestions.add(new ReviewerSuggestion(req.getQuery(), name));
+                }
+              }
             }
+            done.onSuggestionsReady(req, new Response(suggestions));
           }
-        }
-        done.onSuggestionsReady(req, new Response(suggestions));
-      }
 
-      @Override
-      public void onFailure(Throwable caught) {
-        responseEmptySuggestion(req, done);
-      }
-    });
+          @Override
+          public void onFailure(Throwable caught) {
+            responseEmptySuggestion(req, done);
+          }
+        });
   }
 
   private static void responseEmptySuggestion(Request req, Callback done) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ReviewersScreen.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ReviewersScreen.java
index ebd1f48..ba601ae 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ReviewersScreen.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/client/ReviewersScreen.java
@@ -32,20 +32,18 @@
 import com.google.gwt.user.client.ui.SuggestBox;
 import com.google.gwt.user.client.ui.VerticalPanel;
 import com.google.gwtexpui.globalkey.client.NpTextBox;
-
 import java.util.HashSet;
 import java.util.Objects;
 import java.util.Set;
 
 public class ReviewersScreen extends HorizontalPanel {
-  private static final String REMOVE_BUTTON_IMG =
-      "plugins/reviewers/static/remove_reviewer.png";
+  private static final String REMOVE_BUTTON_IMG = "plugins/reviewers/static/remove_reviewer.png";
+
   static class Factory implements Screen.EntryPoint {
     @Override
     public void onLoad(Screen screen) {
       screen.setPageTitle("Reviewers");
-      screen.show(
-          new ReviewersScreen(URL.decodeQueryString(screen.getToken(1))));
+      screen.show(new ReviewersScreen(URL.decodeQueryString(screen.getToken(1))));
     }
   }
 
@@ -58,34 +56,37 @@
     this.projectName = projectName;
     this.rEntries = new HashSet<>();
 
-    new RestApi("access/").addParameter("project", projectName).get(
-        new AsyncCallback<NativeMap<ProjectAccessInfo>>() {
+    new RestApi("access/")
+        .addParameter("project", projectName)
+        .get(
+            new AsyncCallback<NativeMap<ProjectAccessInfo>>() {
 
-        @Override
-        public void onSuccess(NativeMap<ProjectAccessInfo> result) {
-          isOwner = result.get(projectName).isOwner();
-          display();
-        }
+              @Override
+              public void onSuccess(NativeMap<ProjectAccessInfo> result) {
+                isOwner = result.get(projectName).isOwner();
+                display();
+              }
 
-        @Override
-        public void onFailure(Throwable caught) {
-        }
-      });
+              @Override
+              public void onFailure(Throwable caught) {}
+            });
   }
 
   void display() {
-    new RestApi("projects").id(projectName).view("reviewers").get(
-        new AsyncCallback<JsArray<ReviewerFilterSection>>() {
+    new RestApi("projects")
+        .id(projectName)
+        .view("reviewers")
+        .get(
+            new AsyncCallback<JsArray<ReviewerFilterSection>>() {
 
-      @Override
-      public void onSuccess(JsArray<ReviewerFilterSection> result) {
-        display(result);
-      }
+              @Override
+              public void onSuccess(JsArray<ReviewerFilterSection> result) {
+                display(result);
+              }
 
-      @Override
-      public void onFailure(Throwable caught) {
-      }
-    });
+              @Override
+              public void onFailure(Throwable caught) {}
+            });
   }
 
   void display(JsArray<ReviewerFilterSection> sections) {
@@ -116,12 +117,13 @@
     Button removeButton = Button.wrap(img.getElement());
     removeButton.setStyleName("reviewers-removeButton");
     removeButton.setTitle("remove reviewer");
-    removeButton.addClickHandler(new ClickHandler() {
-      @Override
-      public void onClick(final ClickEvent event) {
-        doSave(Action.REMOVE, e);
-      }
-    });
+    removeButton.addClickHandler(
+        new ClickHandler() {
+          @Override
+          public void onClick(final ClickEvent event) {
+            doSave(Action.REMOVE, e);
+          }
+        });
     removeButton.setVisible(isOwner);
 
     HorizontalPanel p = new HorizontalPanel();
@@ -130,7 +132,7 @@
     return p;
   }
 
-  Panel createInputPanel(){
+  Panel createInputPanel() {
     Grid inputGrid = new Grid(2, 2);
 
     final NpTextBox filterBox = new NpTextBox();
@@ -147,19 +149,18 @@
 
     Button addButton = new Button("Add");
     addButton.setStyleName("reviewers-addButton");
-    addButton.addClickHandler(new ClickHandler() {
-      @Override
-      public void onClick(final ClickEvent event) {
-        ReviewerEntry e = new ReviewerEntry(filterBox.getValue(),
-            reviewerBox.getValue());
-        if (!rEntries.contains(e) && !e.filter.isEmpty() &&
-            !e.reviewer.isEmpty()) {
-          doSave(Action.ADD, e);
-        }
-        filterBox.setText("");
-        reviewerBox.setText("");
-      }
-    });
+    addButton.addClickHandler(
+        new ClickHandler() {
+          @Override
+          public void onClick(final ClickEvent event) {
+            ReviewerEntry e = new ReviewerEntry(filterBox.getValue(), reviewerBox.getValue());
+            if (!rEntries.contains(e) && !e.filter.isEmpty() && !e.reviewer.isEmpty()) {
+              doSave(Action.ADD, e);
+            }
+            filterBox.setText("");
+            reviewerBox.setText("");
+          }
+        });
     filterBox.setEnabled(isOwner);
     reviewerBox.setEnabled(isOwner);
     addButton.setEnabled(isOwner);
@@ -178,18 +179,21 @@
     in.setReviewer(entry.reviewer);
     reset();
 
-    new RestApi("projects").id(projectName).view("reviewers").put(
-        in, new AsyncCallback<JsArray<ReviewerFilterSection>>() {
+    new RestApi("projects")
+        .id(projectName)
+        .view("reviewers")
+        .put(
+            in,
+            new AsyncCallback<JsArray<ReviewerFilterSection>>() {
 
-      @Override
-      public void onSuccess(JsArray<ReviewerFilterSection> result) {
-        display(result);
-      }
+              @Override
+              public void onSuccess(JsArray<ReviewerFilterSection> result) {
+                display(result);
+              }
 
-      @Override
-      public void onFailure(Throwable caught) {
-      }
-    });
+              @Override
+              public void onFailure(Throwable caught) {}
+            });
   }
 
   void reset() {
@@ -217,8 +221,7 @@
         return false;
       }
       ReviewerEntry other = (ReviewerEntry) o;
-      if (!this.filter.equals(other.filter)
-          || !this.reviewer.equals(other.reviewer)) {
+      if (!this.filter.equals(other.filter) || !this.reviewer.equals(other.reviewer)) {
         return false;
       }
       return true;
diff --git a/src/main/resources/Documentation/build.md b/src/main/resources/Documentation/build.md
index dc33468..770d643 100644
--- a/src/main/resources/Documentation/build.md
+++ b/src/main/resources/Documentation/build.md
@@ -1,71 +1,39 @@
 Build
 =====
 
-This plugin can be built with Buck or Maven.
-
-Buck
-----
+This plugin can be built with Bazel or Maven.
 
 Two build modes are supported: Standalone and in Gerrit tree.
 The standalone build mode is recommended, as this mode doesn't require
 the Gerrit tree to exist locally.
 
-
 ### Build standalone
 
-Clone bucklets library:
-
 ```
-  git clone https://gerrit.googlesource.com/bucklets
-
-```
-and link it to reviewers plugin directory:
-
-```
-  cd reviewers && ln -s ../bucklets .
-```
-
-Add link to the .buckversion file:
-
-```
-  cd reviewers && ln -s bucklets/buckversion .buckversion
-```
-
-Add link to the .watchmanconfig file:
-
-```
-  cd reviewers && ln -s bucklets/watchmanconfig .watchmanconfig
-```
-
-To build the plugin, issue the following command:
-
-
-```
-  buck build plugin
+  bazel build @PLUGIN@
 ```
 
 The output is created in
 
 ```
-  buck-out/gen/reviewers.jar
+  bazel-genfiles/@PLUGIN@.jar
 ```
 
 ### Build in Gerrit tree
 
-Clone or link this plugin to the plugins directory of Gerrit's source
-tree, and issue the command:
-
 ```
-  buck build plugins/reviewers
+  bazel build plugins/@PLUGIN@
 ```
 
 The output is created in
 
 ```
-  buck-out/gen/plugins/reviewers/reviewers.jar
+  bazel-genfiles/plugins/@PLUGIN@/@PLUGIN@.jar
 ```
 
-This project can be imported into the Eclipse IDE:
+This project can be imported into the Eclipse IDE.
+Add the plugin name to the `CUSTOM_PLUGINS` set in
+Gerrit core in `tools/bzl/plugins.bzl`, and execute:
 
 ```
   ./tools/eclipse/project.py
@@ -87,4 +55,4 @@
 When building with Maven, the Gerrit Plugin API must be available.
 
 How to build the Gerrit Plugin API is described in the [Gerrit
-documentation](../../../Documentation/dev-buck.html#_extension_and_plugin_api_jar_files).
+documentation](../../../Documentation/dev-bazel.html#_extension_and_plugin_api_jar_files).
diff --git a/tools/bazel.rc b/tools/bazel.rc
new file mode 100644
index 0000000..4ed16cf
--- /dev/null
+++ b/tools/bazel.rc
@@ -0,0 +1,2 @@
+build --workspace_status_command=./tools/workspace-status.sh
+test --build_tests_only
diff --git a/tools/bzl/BUILD b/tools/bzl/BUILD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/bzl/BUILD
diff --git a/tools/bzl/plugin.bzl b/tools/bzl/plugin.bzl
new file mode 100644
index 0000000..2b1df8c
--- /dev/null
+++ b/tools/bzl/plugin.bzl
@@ -0,0 +1,4 @@
+load(
+    "@com_googlesource_gerrit_bazlets//:gerrit_plugin.bzl",
+    "gerrit_plugin",
+)
diff --git a/tools/workspace-status.sh b/tools/workspace-status.sh
new file mode 100755
index 0000000..674faeb
--- /dev/null
+++ b/tools/workspace-status.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# This script will be run by bazel when the build process starts to
+# generate key-value information that represents the status of the
+# workspace. The output should be like
+#
+# KEY1 VALUE1
+# KEY2 VALUE2
+#
+# If the script exits with non-zero code, it's considered as a failure
+# and the output will be discarded.
+
+function rev() {
+  cd $1; git describe --always --match "v[0-9].*" --dirty
+}
+
+echo STABLE_BUILD_REVIEWERS_LABEL $(rev .)