Merge branch 'stable-3.0'

* stable-3.0:
  Set version to 3.0.2
  gr-user-header: Construct dashboard url from account id
  Allow to display change-list for inactive users
  run_test.sh: Fix bazelisk location detection
  Set version to 2.16.12-SNAPSHOT
  Set version to 2.16.11.1
  Update git submodules
  Bazel: Adapt docs for custom plugins with external deps
  Update git submodules
  PolyGerrit: Run WCT tests using bazelisk
  dev-intellij.txt: Fix indentation level warning
  link-text-parser.js: Fix indentation
  Fix base url in addHTML to correctly match
  Add base url to addHTML
  Add license to dark-theme

Change-Id: I848d9b3f76a17467a15c8fff6e7b891d148b623b
diff --git a/Documentation/dev-build-plugins.txt b/Documentation/dev-build-plugins.txt
index 47ace5b..8139743 100644
--- a/Documentation/dev-build-plugins.txt
+++ b/Documentation/dev-build-plugins.txt
@@ -128,16 +128,25 @@
 ----
 
 If the plugin(s) being bundled in the release have external dependencies, include them
-in `plugins/external_plugin_deps`. You should alias `external_plugin_deps()` so it
-can be imported for multiple plugins. For example:
+in `plugins/external_plugin_deps`. Create symbolic link from plugin's own
+`external_plugin_deps()` file in plugins directory and prefix the file with
+plugin name, e.g.:
 
 ----
-load(":my-plugin/external_plugin_deps.bzl", my_plugin="external_plugin_deps")
-load(":my-other-plugin/external_plugin_deps.bzl", my_other_plugin="external_plugin_deps")
+  $ cd plugins
+  $ ln -s oauth/external_plugin_deps.bzl oauth_external_plugin_deps.bzl
+  $ ln -s uploadvalidator/external_plugin_deps.bzl uploadvalidator_external_plugin_deps.bzl
+----
+
+Now the plugin specific dependency files can be imported:
+
+----
+load(":oauth_external_plugin_deps.bzl", oauth_deps="external_plugin_deps")
+load(":uploadvalidator_external_plugin_deps.bzl", uploadvalidator_deps="external_plugin_deps")
 
 def external_plugin_deps():
-  my_plugin()
-  my_other_plugin()
+  oauth_deps()
+  uploadvalidator_deps()
 ----
 
 [NOTE]
diff --git a/Documentation/dev-intellij.txt b/Documentation/dev-intellij.txt
index c662e178..5077079 100644
--- a/Documentation/dev-intellij.txt
+++ b/Documentation/dev-intellij.txt
@@ -187,7 +187,8 @@
 or go to *Run -> Edit Configurations*.
 
 [[runconfigurations-daemon]]
-==== Gerrit Daemon
+=== Gerrit Daemon
+
 [WARNING]
 ====
 At the moment running this (local) configuration results in a
diff --git a/plugins/replication b/plugins/replication
index 9b10716..a3ca5f8 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 9b10716f0afaf58e29e591d22859120c4e35a702
+Subproject commit a3ca5f86bb58852b106e3fdb91a79a6cc11bf312
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js
index e72b788..455019f 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js
@@ -245,9 +245,13 @@
       if (!changes || !changes.length) {
         return;
       }
-      if (USER_QUERY_PATTERN.test(this._query) && changes[0].owner.email) {
-        this._userId = changes[0].owner.email;
-        return;
+      if (USER_QUERY_PATTERN.test(this._query)) {
+        const owner = changes[0].owner;
+        const userId = owner._account_id ? owner._account_id : owner.email;
+        if (userId) {
+          this._userId = userId;
+          return;
+        }
       }
       if (REPO_QUERY_PATTERN.test(this._query)) {
         this._repo = changes[0].project;
diff --git a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.js b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.js
index dc945d86..93464b7 100644
--- a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.js
+++ b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.js
@@ -80,8 +80,11 @@
     },
 
     _computeDashboardUrl(accountDetails) {
-      if (!accountDetails || !accountDetails.email) { return null; }
-      return Gerrit.Nav.getUrlForUserDashboard(accountDetails.email);
+      if (!accountDetails) { return null; }
+      const id = accountDetails._account_id;
+      const email = accountDetails.email;
+      if (!id && !email ) { return null; }
+      return Gerrit.Nav.getUrlForUserDashboard(id ? id : email);
     },
 
     _computeDashboardLinkClass(showDashboardLink, loggedIn) {
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html
index 3483d0e..968db93 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html
@@ -69,6 +69,10 @@
           match: 'hash:(.+)',
           html: '<a href="#/awesomesauce">$1</a>',
         },
+        baseurl: {
+          match: 'test (.+)',
+          html: '<a href="/r/awesomesauce">$1</a>',
+        },
         disabledconfig: {
           match: 'foo:(.+)',
           link: 'https://google.com/search?q=$1',
@@ -206,6 +210,15 @@
     test('html with base url', () => {
       window.CANONICAL_PATH = '/r';
 
+      element.content = 'test foo';
+      const linkEl = element.$.output.childNodes[0];
+      assert.isTrue(linkEl.href.endsWith('/r/awesomesauce'));
+      assert.equal(linkEl.textContent, 'foo');
+    });
+
+    test('hash html with base url', () => {
+      window.CANONICAL_PATH = '/r';
+
       element.content = 'hash:foo';
       const linkEl = element.$.output.childNodes[0];
       assert.isTrue(linkEl.href.endsWith('/r/awesomesauce'));
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/link-text-parser.js b/polygerrit-ui/app/elements/shared/gr-linked-text/link-text-parser.js
index c5ac00e..897512b 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/link-text-parser.js
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/link-text-parser.js
@@ -142,7 +142,7 @@
           htmlOutput = a;
         } else if (html) {
           const fragment = document.createDocumentFragment();
-      // Create temporary div to hold the nodes in.
+          // Create temporary div to hold the nodes in.
           const div = document.createElement('div');
           div.innerHTML = html;
           while (div.firstChild) {
@@ -174,7 +174,7 @@
       function(text, href, position, length, outputArray) {
         if (!text || this.hasOverlap(position, length, outputArray)) { return; }
         if (!!this.baseUrl && href.startsWith('/') &&
-              !href.startsWith(this.baseUrl)) {
+             !href.startsWith(this.baseUrl)) {
           href = this.baseUrl + href;
         }
         this.addItem(text, href, null, position, length, outputArray);
diff --git a/polygerrit-ui/app/run_test.sh b/polygerrit-ui/app/run_test.sh
index 3d92e11..e9be18d 100755
--- a/polygerrit-ui/app/run_test.sh
+++ b/polygerrit-ui/app/run_test.sh
@@ -32,9 +32,15 @@
     exit 1
 fi
 
+bazel_bin=$(which bazelisk 2>/dev/null)
+if [[ -z "$bazel_bin" ]]; then
+    echo "Warning: bazelisk is not installed; falling back to bazel."
+    bazel_bin=bazel
+fi
+
 # WCT tests are not hermetic, and need extra environment variables.
 # TODO(hanwen): does $DISPLAY even work on OSX?
-bazel test \
+${bazel_bin} test \
       --test_env="HOME=$HOME" \
       --test_env="WCT=${wct_bin}" \
       --test_env="WCT_ARGS=${WCT_ARGS}" \
diff --git a/polygerrit-ui/app/styles/themes/dark-theme.html b/polygerrit-ui/app/styles/themes/dark-theme.html
index f513f3c..8cf1b13 100644
--- a/polygerrit-ui/app/styles/themes/dark-theme.html
+++ b/polygerrit-ui/app/styles/themes/dark-theme.html
@@ -1,3 +1,19 @@
+<!--
+@license
+Copyright (C) 2019 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
 <dom-module id="dark-theme">
   <custom-style><style is="custom-style">
     html {