Merge "Mark ALREADY_MERGED changes as merged in the DB and run hooks" into stable-2.7
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandLink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandLink.java
index c5c68db..7a477fa 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandLink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandLink.java
@@ -86,7 +86,7 @@
       String projectName;
       String ref;
       public RepoCommandLink(String project, String ref) {
-        super(DownloadCommand.REPO_DOWNLOAD, "checkout");
+        super(DownloadCommand.REPO_DOWNLOAD, "repo download");
         this.projectName = project;
         this.ref = ref;
       }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
index 80cdca6..8c8ecfc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
@@ -356,7 +356,13 @@
         continue;
       }
       if (standard) {
-        setRecommendedAndDisliked(cd, type, e.getValue());
+        for (PatchSetApproval psa : cd.currentApprovals(db)) {
+          if (type.matches(psa)) {
+            short val = psa.getValue();
+            Account.Id accountId = psa.getAccountId();
+            setLabelScores(type, e.getValue(), val, accountId);
+          }
+        }
       }
       if (detailed) {
         setLabelValues(type, e.getValue());
@@ -400,36 +406,32 @@
     return labels;
   }
 
-  private void setRecommendedAndDisliked(ChangeData cd, LabelType type,
-      LabelInfo label) throws OrmException {
+  private void setLabelScores(LabelType type,
+      LabelInfo label, short score, Account.Id accountId)
+      throws OrmException {
     if (label.approved != null || label.rejected != null) {
       return;
     }
 
     if (type.getMin() == null || type.getMax() == null) {
-      // Unknown or misconfigured type can't have intermediate scores.
+      // Can't set score for unknown or misconfigured type.
       return;
     }
 
-    short min = type.getMin().getValue();
-    short max = type.getMax().getValue();
-    if (-1 <= min && max <= 1) {
-      // Types with a range of -1..+1 can't have intermediate scores.
-      return;
-    }
-
-    for (PatchSetApproval psa : cd.currentApprovals(db)) {
-      short val = psa.getValue();
-      if (val != 0 && min < val && val < max && type.matches(psa)) {
-        if (0 < val) {
-          label.recommended = accountLoader.get(psa.getAccountId());
-          label.value = val != 1 ? val : null;
-        } else {
-          label.disliked = accountLoader.get(psa.getAccountId());
-          label.value = val != -1 ? val : null;
-        }
+    if (score != 0) {
+      if (score == type.getMax().getValue()) {
+        label.approved = accountLoader.get(accountId);
+      } else if (score == type.getMin().getValue()) {
+        label.rejected = accountLoader.get(accountId);
+      } else if (score > 0) {
+        label.recommended = accountLoader.get(accountId);
+        label.value = score;
+      } else if (score < 0) {
+        label.disliked = accountLoader.get(accountId);
+        label.value = score;
       }
     }
+
     return;
   }
 
@@ -540,22 +542,11 @@
         }
 
         LabelInfo li = labels.get(type.getName());
-        if (!standard || li.approved != null || li.rejected != null) {
+        if (!standard) {
           continue;
         }
-        if (val == type.getMax().getValue()) {
-          li.approved = accountLoader.get(accountId);
-        } else if (val == type.getMin().getValue()
-            // A merged change can't have been rejected.
-            && cd.getChange().getStatus() != Status.MERGED) {
-          li.rejected = accountLoader.get(accountId);
-        } else if (val > 0) {
-          li.recommended = accountLoader.get(accountId);
-          li.value = val;
-        } else if (val < 0) {
-          li.disliked = accountLoader.get(accountId);
-          li.value = val;
-        }
+
+        setLabelScores(type, li, val, accountId);
       }
     }
     return labels;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommandProvider.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommandProvider.java
index e9a31c9..c7594bc 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommandProvider.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommandProvider.java
@@ -53,13 +53,17 @@
   public RegistrationHandle register(final CommandName name,
       final Provider<Command> cmd) {
     final ConcurrentMap<String, CommandProvider> m = getMap();
-    if (m.putIfAbsent(name.value(), new CommandProvider(cmd, null)) != null) {
+    final CommandProvider commandProvider = new CommandProvider(cmd, null);
+    if (m.putIfAbsent(name.value(), commandProvider) != null) {
       throw new IllegalArgumentException(name.value() + " exists");
     }
     return new RegistrationHandle() {
       @Override
       public void remove() {
-        m.remove(name.value(), cmd);
+        if (!m.remove(name.value(), commandProvider)) {
+          throw new IllegalStateException(String.format(
+              "can not unregister command: %s", name.value()));
+        }
       }
     };
   }