Merge branch 'stable-2.12' into stable-2.14

* stable-2.12:
  Change copyright to AOSP

Change-Id: I00c6885ee60769fd1cd530d0e86c10a390738906
diff --git a/.buckconfig b/.buckconfig
deleted file mode 100644
index 48f1c0a..0000000
--- a/.buckconfig
+++ /dev/null
@@ -1,15 +0,0 @@
-[alias]
-  heartbeat = //:heartbeat
-  plugin = //:heartbeat
-  src = //:heartbeat-sources
-
-[java]
-  src_roots = java, resources
-
-[project]
-  ignore = .git, eclipse-out
-
-[cache]
-  mode = dir
-  dir = buck-out/cache
-
diff --git a/.gitignore b/.gitignore
index 4c23cda..72f041f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,6 @@
-/.buckversion
 /.classpath
+/.primary_build_tool
 /.project
 /.settings/
-/.watchmanconfig
-/buck-out/
-/bucklets
-/eclipse-out
+/bazel-*
+/eclipse-out/
diff --git a/BUCK b/BUCK
deleted file mode 100644
index fa50925..0000000
--- a/BUCK
+++ /dev/null
@@ -1,37 +0,0 @@
-include_defs('//bucklets/gerrit_plugin.bucklet')
-include_defs('//bucklets/java_sources.bucklet')
-
-SOURCES = glob(['src/main/java/**/*.java'])
-RESOURCES = glob(['src/main/resources/**/*'])
-TEST_DEPS = GERRIT_PLUGIN_API + [
-  ':heartbeat__plugin',
-  '//lib:junit',
-  '//lib/easymock:easymock',
-]
-
-gerrit_plugin(
-  name = 'heartbeat',
-  srcs = SOURCES,
-  resources = RESOURCES,
-  manifest_entries = [
-    'Gerrit-PluginName: heartbeat',
-    'Gerrit-Module: com.ericsson.gerrit.plugins.heartbeat.HeartbeatModule',
-  ],
-)
-
-java_library(
-  name = 'classpath',
-  deps = TEST_DEPS,
-)
-
-java_test(
-  name = 'heartbeat_tests',
-  labels = ['heartbeat'],
-  srcs = glob(['src/test/java/**/*.java']),
-  deps = TEST_DEPS,
-)
-
-java_sources(
-  name = 'heartbeat-sources',
-  srcs = SOURCES + RESOURCES,
-)
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..de233a2
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,38 @@
+load("//tools/bzl:junit.bzl", "junit_tests")
+load(
+    "//tools/bzl:plugin.bzl",
+    "gerrit_plugin",
+    "PLUGIN_DEPS",
+    "PLUGIN_TEST_DEPS",
+)
+
+gerrit_plugin(
+    name = "heartbeat",
+    srcs = glob(["src/main/java/**/*.java"]),
+    manifest_entries = [
+        "Gerrit-PluginName: heartbeat",
+        "Gerrit-Module: com.ericsson.gerrit.plugins.heartbeat.HeartbeatModule",
+        "Implementation-Title: heartbeat plugin",
+        "Implementation-URL: https://gerrit-review.googlesource.com/#/admin/projects/plugins/heartbeat",
+        "Implementation-Vendor: Ericsson",
+    ],
+    resources = glob(["src/main/resources/**/*"]),
+)
+
+junit_tests(
+    name = "heartbeat_tests",
+    srcs = glob(["src/test/java/**/*.java"]),
+    tags = ["heartbeat"],
+    deps = [
+        ":heartbeat__plugin_test_deps",
+    ],
+)
+
+java_library(
+    name = "heartbeat__plugin_test_deps",
+    testonly = 1,
+    visibility = ["//visibility:public"],
+    exports = PLUGIN_DEPS + PLUGIN_TEST_DEPS + [
+        ":heartbeat__plugin",
+    ],
+)
diff --git a/WORKSPACE b/WORKSPACE
new file mode 100644
index 0000000..dd94def
--- /dev/null
+++ b/WORKSPACE
@@ -0,0 +1,26 @@
+workspace(name = "heartbeat")
+
+load("//:bazlets.bzl", "load_bazlets")
+
+load_bazlets(
+    commit = "11ce7521051ca73598d099aa8a396c9ffe932a74",
+    #    local_path = "/home/<user>/projects/bazlets",
+)
+
+#Snapshot Plugin API
+#load(
+#    "@com_googlesource_gerrit_bazlets//:gerrit_api_maven_local.bzl",
+#    "gerrit_api_maven_local",
+#)
+
+# Load snapshot Plugin API
+#gerrit_api_maven_local()
+
+# Release Plugin API
+load(
+    "@com_googlesource_gerrit_bazlets//:gerrit_api.bzl",
+    "gerrit_api",
+)
+
+# Load release Plugin API
+gerrit_api()
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/BUCK b/lib/BUCK
deleted file mode 100644
index 1d9dd26..0000000
--- a/lib/BUCK
+++ /dev/null
@@ -1,17 +0,0 @@
-include_defs('//bucklets/maven_jar.bucklet')
-
-maven_jar(
-  name = 'junit',
-  id = 'junit:junit:4.10',
-  sha1 = 'e4f1766ce7404a08f45d859fb9c226fc9e41a861',
-  license = 'DO_NOT_DISTRIBUTE',
-  deps = [':hamcrest-core'],
-)
-
-maven_jar(
-  name = 'hamcrest-core',
-  id = 'org.hamcrest:hamcrest-core:1.3',
-  sha1 = '42a25dc3219429f0e5d060061f71acb49bf010a0',
-  license = 'DO_NOT_DISTRIBUTE',
-  visibility = ['//lib:junit'],
-)
diff --git a/lib/easymock/BUCK b/lib/easymock/BUCK
deleted file mode 100644
index 2a774a9..0000000
--- a/lib/easymock/BUCK
+++ /dev/null
@@ -1,29 +0,0 @@
-include_defs('//bucklets/maven_jar.bucklet')
-
-maven_jar(
-  name = 'easymock',
-  id = 'org.easymock:easymock:3.2',
-  sha1 = '00c82f7fa3ef377d8954b1db25123944b5af2ba4',
-  license = 'DO_NOT_DISTRIBUTE',
-  deps = [
-    ':cglib-2_2',
-    ':objenesis',
-  ],
-)
-
-maven_jar(
-  name = 'cglib-2_2',
-  id = 'cglib:cglib-nodep:2.2.2',
-  sha1 = '00d456bb230c70c0b95c76fb28e429d42f275941',
-  license = 'DO_NOT_DISTRIBUTE',
-  attach_source = False,
-)
-
-maven_jar(
-  name = 'objenesis',
-  id = 'org.objenesis:objenesis:1.2',
-  sha1 = 'bfcb0539a071a4c5a30690388903ac48c0667f2a',
-  license = 'DO_NOT_DISTRIBUTE',
-  visibility = ['//lib/powermock:powermock-reflect'],
-  attach_source = False,
-)
diff --git a/lib/gerrit/BUCK b/lib/gerrit/BUCK
deleted file mode 100644
index 488801f..0000000
--- a/lib/gerrit/BUCK
+++ /dev/null
@@ -1,14 +0,0 @@
-include_defs('//bucklets/maven_jar.bucklet')
-
-VER = '2.12'
-REPO = MAVEN_CENTRAL
-
-maven_jar(
-  name = 'plugin-api',
-  id = 'com.google.gerrit:gerrit-plugin-api:' + VER,
-  sha1 ='8ce1f6e65078bbcf03a1758f96b3ebca19b7fe3c',
-  license = 'Apache2.0',
-  attach_source = False,
-  repository = REPO,
-)
-
diff --git a/src/main/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatConfig.java b/src/main/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatConfig.java
index 03cfd27..07f9c43 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatConfig.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatConfig.java
@@ -14,53 +14,38 @@
 
 package com.ericsson.gerrit.plugins.heartbeat;
 
+import com.google.gerrit.server.config.SitePaths;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import java.io.File;
 import java.io.IOException;
-
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.storage.file.FileBasedConfig;
 import org.eclipse.jgit.util.FS;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Strings;
-import com.google.gerrit.reviewdb.client.RefNames;
-import com.google.gerrit.server.config.AllProjectsNameProvider;
-import com.google.gerrit.server.config.SitePaths;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-/**
- * Plugin-specific config file data loader and holder.
- */
+/** Plugin-specific config file data loader and holder. */
 @Singleton
 public class HeartbeatConfig {
   private static final Logger logger = LoggerFactory.getLogger(HeartbeatConfig.class);
 
   public static final int DEFAULT_DELAY = 15000;
-  public static final String DEFAULT_REF = RefNames.REFS_CONFIG;
   public static final String DELAY_KEY = "delay";
   public static final String FILENAME = "heartbeat.config";
   public static final String HEARTBEAT_SECTION = "heartbeat";
-  public static final String PROJECT_KEY = "project";
-  public static final String REF_KEY = "ref";
 
   private int delay = DEFAULT_DELAY;
-  private String project;
-  private String ref = DEFAULT_REF;
 
   /**
    * Constructor that loads the config from the plugin file.
    *
    * @param site the site path
-   * @param allProjects the provided name for All-Projects project
    * @throws ConfigInvalidException If loaded config from plugin file is invalid
    * @throws IOException If there is an issue with loading the config from plugin file
    */
   @Inject
-  public HeartbeatConfig(SitePaths site, AllProjectsNameProvider allProjects)
-      throws ConfigInvalidException, IOException {
-    project = allProjects.get().toString();
+  public HeartbeatConfig(SitePaths site) throws ConfigInvalidException, IOException {
     load(site.etc_dir.resolve(FILENAME).toFile());
   }
 
@@ -74,32 +59,15 @@
     try {
       cfg.load();
     } catch (ConfigInvalidException e) {
-      throw new ConfigInvalidException(String.format(
-          "Config file %s is invalid: %s", cfg.getFile(), e.getMessage()), e);
+      throw new ConfigInvalidException(
+          String.format("Config file %s is invalid: %s", cfg.getFile(), e.getMessage()), e);
     } catch (IOException e) {
-      throw new IOException(String.format(
-          "Cannot read %s: %s", cfg.getFile(),  e.getMessage()), e);
+      throw new IOException(String.format("Cannot read %s: %s", cfg.getFile(), e.getMessage()), e);
     }
     delay = cfg.getInt(HEARTBEAT_SECTION, DELAY_KEY, DEFAULT_DELAY);
-    String configuredProject = cfg.getString(HEARTBEAT_SECTION, null, PROJECT_KEY);
-    if (!Strings.isNullOrEmpty(configuredProject)) {
-      project = configuredProject;
-    }
-    String configuredRef = cfg.getString(HEARTBEAT_SECTION, null, REF_KEY);
-    if (!Strings.isNullOrEmpty(configuredRef)) {
-      ref = configuredRef;
-    }
   }
 
   public int getDelay() {
     return delay;
   }
-
-  public String getProject() {
-    return project;
-  }
-
-  public String getRef() {
-    return ref;
-  }
 }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatDaemon.java b/src/main/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatDaemon.java
index 3408859..8a5b6b8 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatDaemon.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatDaemon.java
@@ -16,29 +16,24 @@
 
 import com.google.gerrit.common.EventDispatcher;
 import com.google.gerrit.extensions.events.LifecycleListener;
-import com.google.gerrit.reviewdb.client.Branch;
-import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.extensions.registration.DynamicItem;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
-
+import java.util.Timer;
+import java.util.TimerTask;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Timer;
-import java.util.TimerTask;
-
-/**
- * Timer-based daemon doing the actual heartbeat task.
- */
+/** Timer-based daemon doing the actual heartbeat task. */
 @Singleton
 public class HeartbeatDaemon implements LifecycleListener {
 
   private static final Logger logger = LoggerFactory.getLogger(HeartbeatDaemon.class);
   private static final String HEARTBEAT_THREAD_NAME = "StreamEventHeartbeat";
-  private final EventDispatcher dispatcher;
+  private final DynamicItem<EventDispatcher> dispatcher;
   private final HeartbeatConfig config;
   private final Timer timer;
-  private final Branch.NameKey branch;
 
   /**
    * Constructor that sets the heartbeat timer.
@@ -47,19 +42,16 @@
    * @param config the plugin config
    */
   @Inject
-  public HeartbeatDaemon(EventDispatcher dispatcher, HeartbeatConfig config) {
+  public HeartbeatDaemon(DynamicItem<EventDispatcher> dispatcher, HeartbeatConfig config) {
     this.dispatcher = dispatcher;
     this.config = config;
-    branch = new Branch.NameKey(Project.NameKey.parse(config.getProject()),
-        config.getRef());
     timer = new Timer(HEARTBEAT_THREAD_NAME, true);
   }
 
   @Override
   public void start() {
     timer.schedule(new HeartbeatTask(), 0, config.getDelay());
-    logger.info("Initialized to send heartbeat event every " + config.getDelay()
-        + " milliseconds");
+    logger.info("Initialized to send heartbeat event every " + config.getDelay() + " milliseconds");
   }
 
   @Override
@@ -71,7 +63,11 @@
   private class HeartbeatTask extends TimerTask {
     @Override
     public void run() {
-      dispatcher.postEvent(branch, new HeartbeatEvent());
+      try {
+        dispatcher.get().postEvent(new HeartbeatEvent());
+      } catch (OrmException e) {
+        logger.error("Failed to post hearbeat event: " + e.getMessage(), e);
+      }
     }
   }
 }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatEvent.java b/src/main/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatEvent.java
index e8103ff..61b39e3 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatEvent.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatEvent.java
@@ -16,14 +16,10 @@
 
 import com.google.gerrit.server.events.Event;
 
-/**
- * Simple event implementation for plugin purposes.
- */
+/** Simple event implementation for plugin purposes. */
 public class HeartbeatEvent extends Event {
 
-  /**
-   * Constructor setting our custom event.
-   */
+  /** Constructor setting our custom event. */
   public HeartbeatEvent() {
     super("heartbeat");
   }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatModule.java b/src/main/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatModule.java
index 5f229a5..ce015bf 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatModule.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatModule.java
@@ -16,9 +16,7 @@
 
 import com.google.gerrit.lifecycle.LifecycleModule;
 
-/**
- * Listener bound to plugin's daemon implementation.
- */
+/** Listener bound to plugin's daemon implementation. */
 public class HeartbeatModule extends LifecycleModule {
 
   @Override
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
index 901bad1..0079c54 100644
--- a/src/main/resources/Documentation/about.md
+++ b/src/main/resources/Documentation/about.md
@@ -1,5 +1,9 @@
 Plugin that sends heartbeat stream event.
 
-Stream events are associated with a project ref for visibility purposes so the heartbeat is no different. The defaut settings will send an event on the refs/meta/config ref of the All-Projects project every 15 seconds.
+Main use case for this plugin is to always keep stream events alive so Jenkins
+Gerrit-Trigger connection watchdog doesn't force reconnection when it detects no
+stream events activity.
+
+By default, send one heartbeat event every 15 seconds.
 
 To configure heartbeat, refer to [config](config.html) documentation.
diff --git a/src/main/resources/Documentation/build.md b/src/main/resources/Documentation/build.md
index e013ce2..fe9c4fd 100644
--- a/src/main/resources/Documentation/build.md
+++ b/src/main/resources/Documentation/build.md
@@ -1,80 +1,70 @@
-Build
-=====
+# Build
 
-This plugin is built with Buck.
+This plugin can be built with Bazel, and two build modes are supported:
 
-Two build modes are supported: Standalone and in Gerrit tree. Standalone
-build mode is recommended, as this mode doesn't require local Gerrit
-tree to exist.
+* Standalone
+* In Gerrit tree
 
-Build standalone
-----------------
+Standalone build mode is recommended, as this mode doesn't require local Gerrit
+tree to exist. Moreover, there are some limitations and additional manual steps
+required when building in Gerrit tree mode (see corresponding sections).
 
-Clone bucklets library:
-
-```
-  git clone https://gerrit.googlesource.com/bucklets
-
-```
-and link it to heartbeat directory:
-
-```
-  cd heartbeat && ln -s ../bucklets .
-```
-
-Add link to the .buckversion file:
-
-```
-  cd heartbeat && ln -s bucklets/buckversion .buckversion
-```
-
-Add link to the .watchmanconfig file:
-
-```
-  cd heartbeat && ln -s bucklets/watchmanconfig .watchmanconfig
-```
+## Build standalone
 
 To build the plugin, issue the following command:
 
 ```
-  buck build plugin
+  bazel build @PLUGIN@
 ```
 
 The output is created in
 
 ```
-  buck-out/gen/heartbeat.jar
+  bazel-genfiles/@PLUGIN@.jar
 ```
 
-This project can be imported into the Eclipse IDE:
+To package the plugin sources run:
 
 ```
-  ./bucklets/tools/eclipse.py
+  bazel build lib@PLUGIN@__plugin-src.jar
+```
+
+The output is created in:
+
+```
+  bazel-bin/lib@PLUGIN@__plugin-src.jar
 ```
 
 To execute the tests run:
 
 ```
-  buck test
+  bazel test //...
 ```
 
-Build in Gerrit tree
---------------------
-
-Clone or link this plugin to the plugins directory of Gerrit's source
-tree, and issue the command:
+This project can be imported into the Eclipse IDE:
 
 ```
-  buck build plugins/heartbeat
+  ./tools/eclipse/project.sh
+```
+
+## Build in Gerrit tree
+
+Clone or link this plugin to the plugins directory of Gerrit's
+source tree. From Gerrit source tree issue the command:
+
+```
+  bazel build plugins/@PLUGIN@
 ```
 
 The output is created in
 
 ```
-  buck-out/gen/plugins/heartbeat/heartbeat.jar
+  bazel-genfiles/plugins/@PLUGIN@/@PLUGIN@.jar
 ```
 
 This project can be imported into the Eclipse IDE:
+Add the plugin name to the `CUSTOM_PLUGINS` in `tools/bzl/plugins.bzl`, and
+execute:
 
 ```
   ./tools/eclipse/project.py
@@ -83,8 +73,10 @@
 To execute the tests run:
 
 ```
-  buck test --include heartbeat
+  bazel test --test_tag_filters=@PLUGIN@ //...
 ```
 
-How to build the Gerrit Plugin API is described in the [Gerrit
-documentation](../../../Documentation/dev-buck.html#_extension_and_plugin_api_jar_files).
+
+[Back to @PLUGIN@ documentation index][index]
+
+[index]: index.html
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index cf24277..9a2296a 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -5,10 +5,6 @@
 
 The optional file `$site_path/etc/heartbeat.config` is a Git-style config file that controls the heartbeat settings for the heartbeat plugin.
 
-The file is composed of one `heartbeat` section with the following optional parameters.
+The file is composed of one `heartbeat` section with the following optional parameter.
 
 delay: time in milliseconds to send heartbeat (defaults to 15000)
-
-project: project on which to send event (default is All-Projets)
-
-ref: ref on which to send event (default is refs/meta/config)
diff --git a/src/test/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatConfigTest.java b/src/test/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatConfigTest.java
index 0f15a21..a656de1 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatConfigTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatConfigTest.java
@@ -14,26 +14,19 @@
 
 package com.ericsson.gerrit.plugins.heartbeat;
 
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
 import static org.junit.Assert.assertEquals;
 
-import com.google.gerrit.server.config.AllProjectsName;
-import com.google.gerrit.server.config.AllProjectsNameProvider;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gwtorm.client.KeyUtil;
 import com.google.gwtorm.server.StandardKeyEncoder;
-
-import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.PrintWriter;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
 
 public class HeartbeatConfigTest {
 
@@ -42,7 +35,6 @@
   }
 
   private SitePaths sitePaths;
-  private AllProjectsNameProvider allProjectsNameProviderMock;
   private HeartbeatConfig heartbeatConfig;
 
   @Before
@@ -51,15 +43,11 @@
     tmpSiteFolder.delete();
     tmpSiteFolder.mkdirs();
     sitePaths = new SitePaths(tmpSiteFolder.toPath());
-    allProjectsNameProviderMock = createMock(AllProjectsNameProvider.class);
-    expect(allProjectsNameProviderMock.get()).andReturn(
-        new AllProjectsName("AllProjectName")).anyTimes();
-    replay(allProjectsNameProviderMock);
   }
 
   @After
   public void tearDown() throws Exception {
-    if(sitePaths != null){
+    if (sitePaths != null) {
       deleteFolder(sitePaths.site_path.toFile());
     }
   }
@@ -67,70 +55,39 @@
   @Test
   public void shouldBeDefaultValuesWhenConfigFileDoesNotExist()
       throws ConfigInvalidException, IOException {
-    heartbeatConfig = new HeartbeatConfig(sitePaths, allProjectsNameProviderMock);
+    heartbeatConfig = new HeartbeatConfig(sitePaths);
     assertEquals(HeartbeatConfig.DEFAULT_DELAY, heartbeatConfig.getDelay());
-    assertEquals(allProjectsNameProviderMock.get().get(), heartbeatConfig.getProject());
-    assertEquals(HeartbeatConfig.DEFAULT_REF, heartbeatConfig.getRef());
   }
 
   @Test
-  public void shouldReturnDelayConfiguredInFile()
-      throws ConfigInvalidException, IOException {
+  public void shouldReturnDelayConfiguredInFile() throws ConfigInvalidException, IOException {
     try (PrintWriter writer = getWriterForConfig()) {
       writer.println("[" + HeartbeatConfig.HEARTBEAT_SECTION + "]");
       writer.println(HeartbeatConfig.DELAY_KEY + " = 1234");
     }
-    heartbeatConfig = new HeartbeatConfig(sitePaths, allProjectsNameProviderMock);
+    heartbeatConfig = new HeartbeatConfig(sitePaths);
     assertEquals(1234, heartbeatConfig.getDelay());
-    assertEquals(allProjectsNameProviderMock.get().get(), heartbeatConfig.getProject());
-    assertEquals(HeartbeatConfig.DEFAULT_REF, heartbeatConfig.getRef());
   }
 
-  @Test
-  public void shouldReturnProjectConfiguredInFile()
-      throws ConfigInvalidException, IOException {
-    try (PrintWriter writer = getWriterForConfig()) {
-      writer.println("[" + HeartbeatConfig.HEARTBEAT_SECTION + "]");
-      writer.println(HeartbeatConfig.PROJECT_KEY + " = someProject");
-    }
-    heartbeatConfig = new HeartbeatConfig(sitePaths, allProjectsNameProviderMock);
-    assertEquals(HeartbeatConfig.DEFAULT_DELAY, heartbeatConfig.getDelay());
-    assertEquals("someProject", heartbeatConfig.getProject());
-    assertEquals(HeartbeatConfig.DEFAULT_REF, heartbeatConfig.getRef());
-  }
-
-  @Test
-  public void shouldReturnRefConfiguredInFile()
-      throws ConfigInvalidException, IOException {
-    try (PrintWriter writer = getWriterForConfig()) {
-      writer.println("["+HeartbeatConfig.HEARTBEAT_SECTION+"]");
-      writer.println(HeartbeatConfig.REF_KEY +  "= someRef");
-    }
-    heartbeatConfig = new HeartbeatConfig(sitePaths, allProjectsNameProviderMock);
-    assertEquals(HeartbeatConfig.DEFAULT_DELAY, heartbeatConfig.getDelay());
-    assertEquals(allProjectsNameProviderMock.get().get(), heartbeatConfig.getProject());
-    assertEquals("someRef", heartbeatConfig.getRef());
-  }
-
-  @Test(expected=ConfigInvalidException.class)
+  @Test(expected = ConfigInvalidException.class)
   public void shouldThrowExceptionWhenFileHasBadFormat()
       throws ConfigInvalidException, IOException {
     try (PrintWriter writer = getWriterForConfig()) {
       writer.println("[" + HeartbeatConfig.HEARTBEAT_SECTION);
     }
-    heartbeatConfig = new HeartbeatConfig(sitePaths, allProjectsNameProviderMock);
+    heartbeatConfig = new HeartbeatConfig(sitePaths);
   }
 
-  private PrintWriter getWriterForConfig() throws FileNotFoundException{
+  private PrintWriter getWriterForConfig() throws FileNotFoundException {
     sitePaths.etc_dir.toFile().mkdirs();
     return new PrintWriter(sitePaths.etc_dir.resolve(HeartbeatConfig.FILENAME).toFile());
   }
 
   private void deleteFolder(File folder) {
     File[] files = folder.listFiles();
-    if(files!=null) { //some JVMs return null for empty dirs
-      for(File f: files) {
-        if(f.isDirectory()) {
+    if (files != null) { //some JVMs return null for empty dirs
+      for (File f : files) {
+        if (f.isDirectory()) {
           deleteFolder(f);
         } else {
           f.delete();
diff --git a/src/test/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatDaemonTest.java b/src/test/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatDaemonTest.java
index 36a4531..3aec912 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatDaemonTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatDaemonTest.java
@@ -16,7 +16,6 @@
 
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.createNiceMock;
-import static org.easymock.EasyMock.eq;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.expectLastCall;
 import static org.easymock.EasyMock.isA;
@@ -24,15 +23,15 @@
 import static org.easymock.EasyMock.reset;
 import static org.easymock.EasyMock.verify;
 
+import com.google.gerrit.common.EventDispatcher;
+import com.google.gerrit.extensions.registration.DynamicItem;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.client.KeyUtil;
+import com.google.gwtorm.server.SchemaFactory;
+import com.google.gwtorm.server.StandardKeyEncoder;
 import org.junit.Before;
 import org.junit.Test;
 
-import com.google.gerrit.common.EventDispatcher;
-import com.google.gerrit.reviewdb.client.Branch;
-import com.google.gerrit.reviewdb.client.Project;
-import com.google.gwtorm.client.KeyUtil;
-import com.google.gwtorm.server.StandardKeyEncoder;
-
 public class HeartbeatDaemonTest {
 
   static {
@@ -40,28 +39,29 @@
   }
 
   private EventDispatcher eventDispatcherMock;
-  private HeartbeatConfig heartbeatConfigMock;
   private HeartbeatDaemon heartbeatDaemon;
 
+  @SuppressWarnings("unchecked")
   @Before
   public void setUp() throws Exception {
     eventDispatcherMock = createNiceMock(EventDispatcher.class);
     replay(eventDispatcherMock);
-    heartbeatConfigMock = createMock(HeartbeatConfig.class);
+    DynamicItem<EventDispatcher> dynamicEventDispatcherMock = createNiceMock(DynamicItem.class);
+    expect(dynamicEventDispatcherMock.get()).andReturn(eventDispatcherMock).anyTimes();
+    replay(dynamicEventDispatcherMock);
+    HeartbeatConfig heartbeatConfigMock = createMock(HeartbeatConfig.class);
     expect(heartbeatConfigMock.getDelay()).andReturn(1).anyTimes();
-    expect(heartbeatConfigMock.getProject()).andReturn("someProject").anyTimes();
-    expect(heartbeatConfigMock.getRef()).andReturn("someRef").anyTimes();
     replay(heartbeatConfigMock);
-    heartbeatDaemon = new HeartbeatDaemon(eventDispatcherMock, heartbeatConfigMock);
+    SchemaFactory<ReviewDb> schemaFactoryMock = createNiceMock(SchemaFactory.class);
+    expect(schemaFactoryMock.open()).andReturn(createNiceMock(ReviewDb.class)).anyTimes();
+    replay(schemaFactoryMock);
+    heartbeatDaemon = new HeartbeatDaemon(dynamicEventDispatcherMock, heartbeatConfigMock);
   }
 
   @Test
-  public void thatDaemonSendsHeartbeatEvents() throws InterruptedException {
+  public void thatDaemonSendsHeartbeatEvents() throws Exception {
     reset(eventDispatcherMock);
-    eventDispatcherMock.postEvent(
-        eq(new Branch.NameKey(Project.NameKey.parse(heartbeatConfigMock
-            .getProject()), heartbeatConfigMock.getRef())),
-        isA(HeartbeatEvent.class));
+    eventDispatcherMock.postEvent(isA(HeartbeatEvent.class));
     expectLastCall().atLeastOnce();
     replay(eventDispatcherMock);
 
diff --git a/src/test/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatIT.java b/src/test/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatIT.java
new file mode 100644
index 0000000..1b53bcd
--- /dev/null
+++ b/src/test/java/com/ericsson/gerrit/plugins/heartbeat/HeartbeatIT.java
@@ -0,0 +1,65 @@
+// Copyright (C) 2018 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.ericsson.gerrit.plugins.heartbeat;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import com.google.gerrit.acceptance.GlobalPluginConfig;
+import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.TestPlugin;
+import com.google.gerrit.acceptance.UseLocalDisk;
+import com.google.gerrit.common.UserScopedEventListener;
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.registration.RegistrationHandle;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.events.Event;
+import com.google.inject.Inject;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import org.junit.Test;
+
+@NoHttpd
+@TestPlugin(name = "heartbeat", sysModule = "com.ericsson.gerrit.plugins.heartbeat.HeartbeatModule")
+public class HeartbeatIT extends LightweightPluginDaemonTest {
+
+  @Inject private DynamicSet<UserScopedEventListener> eventListeners;
+
+  @Test
+  @UseLocalDisk
+  @GlobalPluginConfig(pluginName = "heartbeat", name = "heartbeat.delay", value = "1000")
+  public void heartbeat() throws Exception {
+    CountDownLatch expectedEventLatch = new CountDownLatch(1);
+    RegistrationHandle handle =
+        eventListeners.add(
+            new UserScopedEventListener() {
+              @Override
+              public void onEvent(Event event) {
+                if (event instanceof HeartbeatEvent) {
+                  expectedEventLatch.countDown();
+                }
+              }
+
+              @Override
+              public CurrentUser getUser() {
+                return identifiedUserFactory.create(user.id);
+              }
+            });
+    assertWithMessage("heartbeat event received")
+        .that(expectedEventLatch.await(5, TimeUnit.SECONDS))
+        .isTrue();
+    handle.remove();
+  }
+}
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/classpath.bzl b/tools/bzl/classpath.bzl
new file mode 100644
index 0000000..dfcbe9c
--- /dev/null
+++ b/tools/bzl/classpath.bzl
@@ -0,0 +1,2 @@
+load("@com_googlesource_gerrit_bazlets//tools:classpath.bzl",
+     "classpath_collector")
diff --git a/tools/bzl/junit.bzl b/tools/bzl/junit.bzl
new file mode 100644
index 0000000..3af7e58
--- /dev/null
+++ b/tools/bzl/junit.bzl
@@ -0,0 +1,4 @@
+load(
+    "@com_googlesource_gerrit_bazlets//tools:junit.bzl",
+    "junit_tests",
+)
diff --git a/tools/bzl/plugin.bzl b/tools/bzl/plugin.bzl
new file mode 100644
index 0000000..a2e438f
--- /dev/null
+++ b/tools/bzl/plugin.bzl
@@ -0,0 +1,6 @@
+load(
+    "@com_googlesource_gerrit_bazlets//:gerrit_plugin.bzl",
+    "gerrit_plugin",
+    "PLUGIN_DEPS",
+    "PLUGIN_TEST_DEPS",
+)
diff --git a/tools/eclipse/BUILD b/tools/eclipse/BUILD
new file mode 100644
index 0000000..050ebf3
--- /dev/null
+++ b/tools/eclipse/BUILD
@@ -0,0 +1,9 @@
+load("//tools/bzl:classpath.bzl", "classpath_collector")
+
+classpath_collector(
+    name = "main_classpath_collect",
+    testonly = 1,
+    deps = [
+        "//:heartbeat__plugin_test_deps",
+    ],
+)
diff --git a/tools/eclipse/project.sh b/tools/eclipse/project.sh
new file mode 100755
index 0000000..2801712
--- /dev/null
+++ b/tools/eclipse/project.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+# Copyright (C) 2017 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.
+`bazel query @com_googlesource_gerrit_bazlets//tools/eclipse:project --output location | sed s/BUILD:.*//`project.py -n heartbeat -r .
diff --git a/tools/sonar/sonar.sh b/tools/sonar/sonar.sh
new file mode 100755
index 0000000..39df185
--- /dev/null
+++ b/tools/sonar/sonar.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+# Copyright (C) 2018 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.
+`bazel query @com_googlesource_gerrit_bazlets//tools/sonar:sonar --output location | sed s/BUILD:.*//`sonar.py
diff --git a/tools/workspace-status.sh b/tools/workspace-status.sh
new file mode 100755
index 0000000..16bbc89
--- /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_HEARTBEAT_LABEL $(rev .)