Merge "Add reset button to my menu in settings" into stable-2.15
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index aabe87f..78e8512 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -2175,6 +2175,19 @@
 Defaults to GWT (if GWT is enabled) or POLYGERRIT (if POLYGERRIT is
 enabled and GWT is disabled)
 
+[[gerrit.serverId]]gerrit.serverId::
++
+Used by NoteDb to, amongst other things, identify author identities from
+per-server specific account IDs.
++
+If this value is not set on startup it is automatically set to a random UUID.
++
+[NOTE]
+If this value doesn't match the serverId used when creating an already existing
+NoteDb, Gerrit will not be able to use that instance of NoteDb. The serverId
+used to create the NoteDb will show in the resulting exception message in case
+the value differs.
+
 [[gitweb]]
 === Section gitweb
 
diff --git a/gerrit-acceptance-framework/pom.xml b/gerrit-acceptance-framework/pom.xml
index 4c0ca9b..595cc3c 100644
--- a/gerrit-acceptance-framework/pom.xml
+++ b/gerrit-acceptance-framework/pom.xml
@@ -2,7 +2,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.google.gerrit</groupId>
   <artifactId>gerrit-acceptance-framework</artifactId>
-  <version>2.15.1-SNAPSHOT</version>
+  <version>2.15.1</version>
   <packaging>jar</packaging>
   <name>Gerrit Code Review - Acceptance Test Framework</name>
   <description>Framework for Gerrit's acceptance tests</description>
diff --git a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticIndexModule.java b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticIndexModule.java
index 7868443..54e5c38 100644
--- a/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticIndexModule.java
+++ b/gerrit-elasticsearch/src/main/java/com/google/gerrit/elasticsearch/ElasticIndexModule.java
@@ -82,6 +82,7 @@
     } else {
       install(new SingleVersionModule(singleVersions));
     }
+    bind(VersionManager.class).to(ElasticVersionManager.class);
   }
 
   @Provides
@@ -93,7 +94,6 @@
   private class MultiVersionModule extends LifecycleModule {
     @Override
     public void configure() {
-      bind(VersionManager.class).to(ElasticVersionManager.class);
       listener().to(ElasticVersionManager.class);
       if (onlineUpgrade) {
         listener().to(OnlineUpgrader.class);
diff --git a/gerrit-extension-api/pom.xml b/gerrit-extension-api/pom.xml
index b730bd0..795ef9b 100644
--- a/gerrit-extension-api/pom.xml
+++ b/gerrit-extension-api/pom.xml
@@ -2,7 +2,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.google.gerrit</groupId>
   <artifactId>gerrit-extension-api</artifactId>
-  <version>2.15.1-SNAPSHOT</version>
+  <version>2.15.1</version>
   <packaging>jar</packaging>
   <name>Gerrit Code Review - Extension API</name>
   <description>API for Gerrit Extensions</description>
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java
index d738540..0a8f22b 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java
@@ -92,6 +92,7 @@
     } else {
       install(new SingleVersionModule(singleVersions));
     }
+    bind(VersionManager.class).to(LuceneVersionManager.class);
   }
 
   @Provides
@@ -105,7 +106,6 @@
   private class MultiVersionModule extends LifecycleModule {
     @Override
     public void configure() {
-      bind(VersionManager.class).to(LuceneVersionManager.class);
       listener().to(LuceneVersionManager.class);
       if (onlineUpgrade) {
         listener().to(OnlineUpgrader.class);
diff --git a/gerrit-plugin-api/pom.xml b/gerrit-plugin-api/pom.xml
index 5b5a640..a87a456 100644
--- a/gerrit-plugin-api/pom.xml
+++ b/gerrit-plugin-api/pom.xml
@@ -2,7 +2,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.google.gerrit</groupId>
   <artifactId>gerrit-plugin-api</artifactId>
-  <version>2.15.1-SNAPSHOT</version>
+  <version>2.15.1</version>
   <packaging>jar</packaging>
   <name>Gerrit Code Review - Plugin API</name>
   <description>API for Gerrit Plugins</description>
diff --git a/gerrit-plugin-gwtui/pom.xml b/gerrit-plugin-gwtui/pom.xml
index 040569d..f54511b 100644
--- a/gerrit-plugin-gwtui/pom.xml
+++ b/gerrit-plugin-gwtui/pom.xml
@@ -2,7 +2,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.google.gerrit</groupId>
   <artifactId>gerrit-plugin-gwtui</artifactId>
-  <version>2.15.1-SNAPSHOT</version>
+  <version>2.15.1</version>
   <packaging>jar</packaging>
   <name>Gerrit Code Review - Plugin GWT UI</name>
   <description>Common Classes for Gerrit GWT UI Plugins</description>
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerId.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerId.java
index 87dc44a..237f18c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerId.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerId.java
@@ -22,7 +22,8 @@
 /**
  * Marker on a string holding a unique identifier for the server.
  *
- * <p>This value is generated on first use and stored in {@code $site_path/etc/uuid}.
+ * <p>This value is generated on first use and stored in {@code gerrit.serverId} in {@code
+ * gerrit.config}.
  */
 @Retention(RUNTIME)
 @BindingAnnotation
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/VersionManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/VersionManager.java
index 620dd36..8aabb60 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/VersionManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/VersionManager.java
@@ -137,6 +137,16 @@
     return false;
   }
 
+  /**
+   * Tells if an index with this name is currently known or not.
+   *
+   * @param name index name
+   * @return true if index is known and can be used, otherwise false.
+   */
+  public boolean isKnownIndex(String name) {
+    return defs.get(name) != null;
+  }
+
   protected <K, V, I extends Index<K, V>> void initIndex(
       IndexDefinition<K, V, I> def, GerritIndexStatus cfg) {
     TreeMap<Integer, Version<V>> versions = scanVersions(def, cfg);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/IndexActivateCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/IndexActivateCommand.java
index 6b3e6d7..0804d08 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/IndexActivateCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/IndexActivateCommand.java
@@ -16,8 +16,8 @@
 
 import com.google.gerrit.common.data.GlobalCapability;
 import com.google.gerrit.extensions.annotations.RequiresCapability;
-import com.google.gerrit.lucene.LuceneVersionManager;
 import com.google.gerrit.server.index.ReindexerAlreadyRunningException;
+import com.google.gerrit.server.index.VersionManager;
 import com.google.gerrit.sshd.CommandMetaData;
 import com.google.gerrit.sshd.SshCommand;
 import com.google.inject.Inject;
@@ -30,15 +30,19 @@
   @Argument(index = 0, required = true, metaVar = "INDEX", usage = "index name to activate")
   private String name;
 
-  @Inject private LuceneVersionManager luceneVersionManager;
+  @Inject private VersionManager versionManager;
 
   @Override
   protected void run() throws UnloggedFailure {
     try {
-      if (luceneVersionManager.activateLatestIndex(name)) {
-        stdout.println("Activated latest index version");
+      if (versionManager.isKnownIndex(name)) {
+        if (versionManager.activateLatestIndex(name)) {
+          stdout.println("Activated latest index version");
+        } else {
+          stdout.println("Not activating index, already using latest version");
+        }
       } else {
-        stdout.println("Not activating index, already using latest version");
+        stderr.println(String.format("Cannot activate index %s: unknown", name));
       }
     } catch (ReindexerAlreadyRunningException e) {
       throw die("Failed to activate latest index: " + e.getMessage());
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/IndexStartCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/IndexStartCommand.java
index fb9b482..f3d349c 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/IndexStartCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/IndexStartCommand.java
@@ -16,8 +16,8 @@
 
 import com.google.gerrit.common.data.GlobalCapability;
 import com.google.gerrit.extensions.annotations.RequiresCapability;
-import com.google.gerrit.lucene.LuceneVersionManager;
 import com.google.gerrit.server.index.ReindexerAlreadyRunningException;
+import com.google.gerrit.server.index.VersionManager;
 import com.google.gerrit.sshd.CommandMetaData;
 import com.google.gerrit.sshd.SshCommand;
 import com.google.inject.Inject;
@@ -34,15 +34,19 @@
   @Argument(index = 0, required = true, metaVar = "INDEX", usage = "index name to start")
   private String name;
 
-  @Inject private LuceneVersionManager luceneVersionManager;
+  @Inject private VersionManager versionManager;
 
   @Override
   protected void run() throws UnloggedFailure {
     try {
-      if (luceneVersionManager.startReindexer(name, force)) {
-        stdout.println("Reindexer started");
+      if (versionManager.isKnownIndex(name)) {
+        if (versionManager.startReindexer(name, force)) {
+          stdout.println("Reindexer started");
+        } else {
+          stdout.println("Nothing to reindex, index is already the latest version");
+        }
       } else {
-        stdout.println("Nothing to reindex, index is already the latest version");
+        stderr.println(String.format("Cannot reindex %s: unknown", name));
       }
     } catch (ReindexerAlreadyRunningException e) {
       throw die("Failed to start reindexer: " + e.getMessage());
diff --git a/gerrit-war/pom.xml b/gerrit-war/pom.xml
index c24be1e..5fcbd65b 100644
--- a/gerrit-war/pom.xml
+++ b/gerrit-war/pom.xml
@@ -2,7 +2,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.google.gerrit</groupId>
   <artifactId>gerrit-war</artifactId>
-  <version>2.15.1-SNAPSHOT</version>
+  <version>2.15.1</version>
   <packaging>war</packaging>
   <name>Gerrit Code Review - WAR</name>
   <description>Gerrit WAR</description>
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
index d6d8993..bdb437e 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
@@ -510,11 +510,14 @@
         return;
       }
 
-      e.preventDefault();
       if (this._showInlineDiffs) {
+        e.preventDefault();
         this.$.diffCursor.moveDown();
         this._displayLine = true;
       } else {
+        // Down key
+        if (this.getKeyboardEvent(e).keyCode === 40) { return; }
+        e.preventDefault();
         this.$.fileCursor.next();
         this.selectedIndex = this.$.fileCursor.index;
       }
@@ -525,11 +528,14 @@
         return;
       }
 
-      e.preventDefault();
       if (this._showInlineDiffs) {
+        e.preventDefault();
         this.$.diffCursor.moveUp();
         this._displayLine = true;
       } else {
+        // Up key
+        if (this.getKeyboardEvent(e).keyCode === 38) { return; }
+        e.preventDefault();
         this.$.fileCursor.previous();
         this.selectedIndex = this.$.fileCursor.index;
       }
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
index 6b102ba..a5fd521 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
@@ -368,6 +368,10 @@
         // j with a modifier should not move the cursor.
         MockInteractions.pressAndReleaseKeyOn(element, 74, 'shift', 'j');
         assert.equal(element.$.fileCursor.index, 0);
+        // down should not move the cursor.
+        MockInteractions.pressAndReleaseKeyOn(element, 40, null, 'down');
+        assert.equal(element.$.fileCursor.index, 0);
+
         MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
         assert.equal(element.$.fileCursor.index, 1);
         assert.equal(element.selectedIndex, 1);
@@ -381,6 +385,10 @@
         MockInteractions.pressAndReleaseKeyOn(element, 75, 'shift', 'k');
         assert.equal(element.$.fileCursor.index, 2);
 
+        // up should not move the cursor.
+        MockInteractions.pressAndReleaseKeyOn(element, 38, null, 'down');
+        assert.equal(element.$.fileCursor.index, 2);
+
         MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
         assert.equal(element.$.fileCursor.index, 1);
         assert.equal(element.selectedIndex, 1);
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.html b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.html
index bcae0bf..c26ac87 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.html
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.html
@@ -15,9 +15,11 @@
 -->
 
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
-<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
+<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
+<link rel="import" href="../../../behaviors/gr-url-encoding-behavior.html">
 <link rel="import" href="../../../styles/shared-styles.html">
 <link rel="import" href="../../../styles/gr-form-styles.html">
+<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
 
 <dom-module id="gr-group-list">
   <template>
@@ -47,7 +49,11 @@
         <tbody>
           <template is="dom-repeat" items="[[_groups]]">
             <tr>
-              <td class="nameColumn">[[item.name]]</td>
+              <td class="nameColumn">
+                <a href$="[[_computeGroupPath(item)]]">
+                  [[item.name]]
+                </a>
+              </td>
               <td>[[item.description]]</td>
               <td class="visibleCell">[[_computeVisibleToAll(item)]]</td>
             </tr>
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.js b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.js
index d26482d..d294a9b 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.js
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.js
@@ -21,6 +21,11 @@
       _groups: Array,
     },
 
+    behaviors: [
+      Gerrit.BaseUrlBehavior,
+      Gerrit.URLEncodingBehavior,
+    ],
+
     loadData() {
       return this.$.restAPI.getAccountGroups().then(groups => {
         this._groups = groups.sort((a, b) => {
@@ -32,5 +37,13 @@
     _computeVisibleToAll(group) {
       return group.options.visible_to_all ? 'Yes' : 'No';
     },
+
+    _computeGroupPath(group) {
+      if (!group || !group.id) { return; }
+
+      const encodeGroup = this.encodeURL(group.id, true);
+
+      return `${this.getBaseUrl()}/admin/groups/${encodeGroup}`;
+    },
   });
 })();
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html
index 3c4eff2..582ed6c 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html
@@ -33,10 +33,12 @@
 
 <script>
   suite('gr-group-list tests', () => {
+    let sandbox;
     let element;
     let groups;
 
     setup(done => {
+      sandbox = sinon.sandbox.create();
       groups = [{
         url: 'some url',
         options: {},
@@ -65,13 +67,15 @@
       element.loadData().then(() => { flush(done); });
     });
 
+    teardown(() => { sandbox.restore(); });
+
     test('renders', () => {
       const rows = Polymer.dom(element.root).querySelectorAll('tbody tr');
 
       assert.equal(rows.length, 3);
 
       const nameCells = rows.map(row =>
-        row.querySelectorAll('td')[0].textContent
+        row.querySelectorAll('td a')[0].textContent.trim()
       );
 
       assert.equal(nameCells[0], 'Group 1');
@@ -83,5 +87,18 @@
       assert.equal(element._computeVisibleToAll(groups[0]), 'No');
       assert.equal(element._computeVisibleToAll(groups[1]), 'Yes');
     });
+
+    test('_computeGroupPath', () => {
+      let group = {
+        id: 'e2cd66f88a2db4d391ac068a92d987effbe872f5',
+      };
+      assert.equal(element._computeGroupPath(group),
+          '/admin/groups/e2cd66f88a2db4d391ac068a92d987effbe872f5');
+
+      group = {
+        name: 'admin',
+      };
+      assert.isUndefined(element._computeGroupPath(group));
+    });
   });
 </script>
diff --git a/version.bzl b/version.bzl
index e122db3..29fff64 100644
--- a/version.bzl
+++ b/version.bzl
@@ -2,4 +2,4 @@
 # Used by :api_install and :api_deploy targets
 # when talking to the destination repository.
 #
-GERRIT_VERSION = "2.15.1-SNAPSHOT"
+GERRIT_VERSION = "2.15.1"