Merge branch 'stable-2.13'

* stable-2.13:
  Batch sending mail when multiple reviewers added

Change-Id: I2bd6fe15ccedf983aee99b34ac35acb19df8000b
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/ChangeEventListener.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/ChangeEventListener.java
index e4c5771..441c605 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,9 @@
 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.RevisionCreatedListener;
 import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Change;
@@ -32,9 +33,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.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;
@@ -62,7 +60,7 @@
 import java.util.Set;
 
 @Singleton
-class ChangeEventListener implements EventListener {
+class ChangeEventListener implements RevisionCreatedListener {
   private static final Logger log = LoggerFactory
       .getLogger(ChangeEventListener.class);
 
@@ -114,12 +112,8 @@
   }
 
   @Override
-  public void onEvent(Event event) {
-    if (!(event instanceof PatchSetCreatedEvent)) {
-      return;
-    }
-    PatchSetCreatedEvent e = (PatchSetCreatedEvent) event;
-    ChangeAttribute c = e.change.get();
+  public void onRevisionCreated(Event event) {
+    ChangeInfo c = event.getChange();
     Project.NameKey projectName = new Project.NameKey(c.project);
     // TODO(davido): we have to cache per project configuration
     ReviewersConfig config = configFactory.create(projectName);
@@ -133,7 +127,7 @@
         RevWalk rw = new RevWalk(git);
         ReviewDb reviewDb = schemaFactory.open()) {
       ChangeData changeData = changeDataFactory.create(
-          reviewDb, projectName, new Change.Id(Integer.parseInt(c.number)));
+          reviewDb, projectName, new Change.Id(c._number));
       Set<String> reviewers = findReviewers(sections, changeData);
       if (reviewers.isEmpty()) {
         return;
@@ -142,7 +136,7 @@
       final Change change = changeData.change();
       final Runnable task = reviewersFactory.create(change,
           toAccounts(reviewDb, reviewers, projectName,
-              e.uploader.get().email));
+              event.getWho().email));
 
       workQueue.getDefaultQueue().submit(new Runnable() {
         ReviewDb db = null;
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..2857105 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/Module.java
@@ -16,12 +16,14 @@
 
 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;
 
@@ -41,16 +43,25 @@
         : 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
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..3e0768e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/SuggestProjectReviewers.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/SuggestProjectReviewers.java
@@ -21,11 +21,10 @@
 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;
@@ -40,7 +39,7 @@
       implements RestReadView<ProjectResource> {
   @Inject
   SuggestProjectReviewers(AccountVisibility av,
-      GenericFactory identifiedUserFactory,
+      IdentifiedUser.GenericFactory identifiedUserFactory,
       Provider<ReviewDb> dbProvider,
       @GerritServerConfig Config cfg,
       ReviewersUtil reviewersUtil) {
@@ -50,8 +49,8 @@
   @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) {
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..b7b86e9 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,12 +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;
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 .)