Merge "Remove everywhere on-tap"
diff --git a/WORKSPACE b/WORKSPACE
index befde25..f18c393 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -776,8 +776,8 @@
 
 maven_jar(
     name = "dropwizard-core",
-    artifact = "io.dropwizard.metrics:metrics-core:4.0.7",
-    sha1 = "673899f605f52ca35836673ccfee97154a496a61",
+    artifact = "io.dropwizard.metrics:metrics-core:4.1.1",
+    sha1 = "ebfafc716d9c3b6151dc7c2c09ce925a163a4f21",
 )
 
 # When updating Bouncy Castle, also update it in bazlets.
diff --git a/java/com/google/gerrit/common/data/PatchScript.java b/java/com/google/gerrit/common/data/PatchScript.java
index c177e35..73e301b 100644
--- a/java/com/google/gerrit/common/data/PatchScript.java
+++ b/java/com/google/gerrit/common/data/PatchScript.java
@@ -37,30 +37,44 @@
     GITLINK
   }
 
+  public static class PatchScriptFileInfo {
+    public final String name;
+    public final FileMode mode;
+    public final SparseFileContent content;
+    public final DisplayMethod displayMethod;
+    public final String mimeType;
+    public final String commitId;
+
+    public PatchScriptFileInfo(
+        String name,
+        FileMode mode,
+        SparseFileContent content,
+        DisplayMethod displayMethod,
+        String mimeType,
+        String commitId) {
+      this.name = name;
+      this.mode = mode;
+      this.content = content;
+      this.displayMethod = displayMethod;
+      this.mimeType = mimeType;
+      this.commitId = commitId;
+    }
+  }
+
   private Change.Key changeId;
   private ChangeType changeType;
-  private String oldName;
-  private String newName;
-  private FileMode oldMode;
-  private FileMode newMode;
   private List<String> header;
   private DiffPreferencesInfo diffPrefs;
-  private SparseFileContent a;
-  private SparseFileContent b;
   private List<Edit> edits;
   private Set<Edit> editsDueToRebase;
-  private DisplayMethod displayMethodA;
-  private DisplayMethod displayMethodB;
-  private transient String mimeTypeA;
-  private transient String mimeTypeB;
   private CommentDetail comments;
   private List<Patch> history;
   private boolean hugeFile;
   private boolean intralineFailure;
   private boolean intralineTimeout;
   private boolean binary;
-  private transient String commitIdA;
-  private transient String commitIdB;
+  private PatchScriptFileInfo fileInfoA;
+  private PatchScriptFileInfo fileInfoB;
 
   public PatchScript(
       Change.Key ck,
@@ -89,50 +103,39 @@
       String cmb) {
     changeId = ck;
     changeType = ct;
-    oldName = on;
-    newName = nn;
-    oldMode = om;
-    newMode = nm;
     header = h;
     diffPrefs = dp;
-    a = ca;
-    b = cb;
     edits = e;
     this.editsDueToRebase = editsDueToRebase;
-    displayMethodA = ma;
-    displayMethodB = mb;
-    mimeTypeA = mta;
-    mimeTypeB = mtb;
     comments = cd;
     history = hist;
     hugeFile = hf;
     intralineFailure = idf;
     intralineTimeout = idt;
     binary = bin;
-    commitIdA = cma;
-    commitIdB = cmb;
-  }
 
-  protected PatchScript() {}
+    fileInfoA = new PatchScriptFileInfo(on, om, ca, ma, mta, cma);
+    fileInfoB = new PatchScriptFileInfo(nn, nm, cb, mb, mtb, cmb);
+  }
 
   public Change.Key getChangeId() {
     return changeId;
   }
 
   public DisplayMethod getDisplayMethodA() {
-    return displayMethodA;
+    return fileInfoA.displayMethod;
   }
 
   public DisplayMethod getDisplayMethodB() {
-    return displayMethodB;
+    return fileInfoB.displayMethod;
   }
 
   public FileMode getFileModeA() {
-    return oldMode;
+    return fileInfoA.mode;
   }
 
   public FileMode getFileModeB() {
-    return newMode;
+    return fileInfoB.mode;
   }
 
   public List<String> getPatchHeader() {
@@ -144,11 +147,11 @@
   }
 
   public String getOldName() {
-    return oldName;
+    return fileInfoA.name;
   }
 
   public String getNewName() {
-    return newName;
+    return fileInfoB.name;
   }
 
   public CommentDetail getCommentDetail() {
@@ -188,19 +191,19 @@
   }
 
   public SparseFileContent getA() {
-    return a;
+    return fileInfoA.content;
   }
 
   public SparseFileContent getB() {
-    return b;
+    return fileInfoB.content;
   }
 
   public String getMimeTypeA() {
-    return mimeTypeA;
+    return fileInfoA.mimeType;
   }
 
   public String getMimeTypeB() {
-    return mimeTypeB;
+    return fileInfoB.mimeType;
   }
 
   public List<Edit> getEdits() {
@@ -216,10 +219,18 @@
   }
 
   public String getCommitIdA() {
-    return commitIdA;
+    return fileInfoA.commitId;
   }
 
   public String getCommitIdB() {
-    return commitIdB;
+    return fileInfoB.commitId;
+  }
+
+  public PatchScriptFileInfo getFileInfoA() {
+    return fileInfoA;
+  }
+
+  public PatchScriptFileInfo getFileInfoB() {
+    return fileInfoB;
   }
 }
diff --git a/java/com/google/gerrit/elasticsearch/builders/XContentBuilder.java b/java/com/google/gerrit/elasticsearch/builders/XContentBuilder.java
index 06427f1..061a373 100644
--- a/java/com/google/gerrit/elasticsearch/builders/XContentBuilder.java
+++ b/java/com/google/gerrit/elasticsearch/builders/XContentBuilder.java
@@ -19,7 +19,8 @@
 import com.fasterxml.jackson.core.JsonEncoding;
 import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.json.JsonReadFeature;
+import com.fasterxml.jackson.core.json.JsonWriteFeature;
 import com.google.common.base.Charsets;
 import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
@@ -38,14 +39,14 @@
    * Inspired from org.elasticsearch.common.xcontent.json.JsonXContent static block.
    */
   public XContentBuilder() throws IOException {
-    JsonFactory jsonFactory = new JsonFactory();
-    jsonFactory.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
-    jsonFactory.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, true);
-    jsonFactory.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
-    jsonFactory.configure(
-        JsonFactory.Feature.FAIL_ON_SYMBOL_HASH_OVERFLOW,
-        false); // this trips on many mappings now...
-    this.generator = jsonFactory.createGenerator(bos, JsonEncoding.UTF8);
+    this.generator =
+        JsonFactory.builder()
+            .configure(JsonReadFeature.ALLOW_UNQUOTED_FIELD_NAMES, true)
+            .configure(JsonWriteFeature.QUOTE_FIELD_NAMES, true)
+            .configure(JsonReadFeature.ALLOW_JAVA_COMMENTS, true)
+            .configure(JsonFactory.Feature.FAIL_ON_SYMBOL_HASH_OVERFLOW, false)
+            .build()
+            .createGenerator(bos, JsonEncoding.UTF8);
   }
 
   public XContentBuilder startObject(String name) throws IOException {
diff --git a/java/com/google/gerrit/extensions/restapi/Response.java b/java/com/google/gerrit/extensions/restapi/Response.java
index 5504cfd..bec7fc3 100644
--- a/java/com/google/gerrit/extensions/restapi/Response.java
+++ b/java/com/google/gerrit/extensions/restapi/Response.java
@@ -30,6 +30,12 @@
     return new Impl<>(200, value);
   }
 
+  /** HTTP 200 OK: with empty value. */
+  public static Response<String> ok() {
+    return ok("");
+  }
+
+  /** HTTP 200 OK: with forced revalidation of cache. */
   public static <T> Response<T> withMustRevalidate(T value) {
     return ok(value).caching(CacheControl.PRIVATE(0, TimeUnit.SECONDS).setMustRevalidate());
   }
@@ -39,6 +45,11 @@
     return new Impl<>(201, value);
   }
 
+  /** HTTP 201 Created: with empty value. */
+  public static Response<String> created() {
+    return created("");
+  }
+
   /** HTTP 202 Accepted: accepted as background task. */
   public static Accepted accepted(String location) {
     return new Accepted(location);
diff --git a/java/com/google/gerrit/gpg/server/DeleteGpgKey.java b/java/com/google/gerrit/gpg/server/DeleteGpgKey.java
index 24bfd4f..6233605 100644
--- a/java/com/google/gerrit/gpg/server/DeleteGpgKey.java
+++ b/java/com/google/gerrit/gpg/server/DeleteGpgKey.java
@@ -21,8 +21,8 @@
 import com.google.common.flogger.FluentLogger;
 import com.google.common.io.BaseEncoding;
 import com.google.gerrit.exceptions.EmailException;
+import com.google.gerrit.exceptions.StorageException;
 import com.google.gerrit.extensions.common.Input;
-import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestApiException;
@@ -108,9 +108,10 @@
                 rsrc.getUser().getAccount().preferredEmail());
           }
           break;
+        case LOCK_FAILURE:
+          // should not happen since this case is already handled by PublicKeyStore#save
         case FORCED:
         case IO_FAILURE:
-        case LOCK_FAILURE:
         case NEW:
         case NOT_ATTEMPTED:
         case REJECTED:
@@ -119,7 +120,7 @@
         case REJECTED_MISSING_OBJECT:
         case REJECTED_OTHER_REASON:
         default:
-          throw new ResourceConflictException("Failed to delete public key: " + saveResult);
+          throw new StorageException(String.format("Failed to delete public key: %s", saveResult));
       }
     }
     return Response.none();
diff --git a/java/com/google/gerrit/gpg/server/PostGpgKeys.java b/java/com/google/gerrit/gpg/server/PostGpgKeys.java
index ac5209e..f4a1655 100644
--- a/java/com/google/gerrit/gpg/server/PostGpgKeys.java
+++ b/java/com/google/gerrit/gpg/server/PostGpgKeys.java
@@ -274,8 +274,9 @@
           break;
         case NO_CHANGE:
           break;
-        case IO_FAILURE:
         case LOCK_FAILURE:
+          // should not happen since this case is already handled by PublicKeyStore#save
+        case IO_FAILURE:
         case NOT_ATTEMPTED:
         case REJECTED:
         case REJECTED_CURRENT_BRANCH:
@@ -283,7 +284,7 @@
         case REJECTED_MISSING_OBJECT:
         case REJECTED_OTHER_REASON:
         default:
-          throw new ResourceConflictException("Failed to save public keys: " + saveResult);
+          throw new StorageException(String.format("Failed to save public keys: %s", saveResult));
       }
     }
     return null;
diff --git a/java/com/google/gerrit/pgm/init/BaseInit.java b/java/com/google/gerrit/pgm/init/BaseInit.java
index 008969e..7fbf2d7 100644
--- a/java/com/google/gerrit/pgm/init/BaseInit.java
+++ b/java/com/google/gerrit/pgm/init/BaseInit.java
@@ -123,7 +123,7 @@
         } catch (StorageException e) {
           String msg = "Couldn't upgrade schema. Expected if slave and read-only database";
           System.err.println(msg);
-          logger.atWarning().withCause(e).log(msg);
+          logger.atSevere().withCause(e).log(msg);
         }
 
         init.initializer.postRun(sysInjector);
diff --git a/java/com/google/gerrit/server/account/SetInactiveFlag.java b/java/com/google/gerrit/server/account/SetInactiveFlag.java
index fb3d4ea..a6c5d5c 100644
--- a/java/com/google/gerrit/server/account/SetInactiveFlag.java
+++ b/java/com/google/gerrit/server/account/SetInactiveFlag.java
@@ -106,6 +106,6 @@
     if (exception.get().isPresent()) {
       throw exception.get().get();
     }
-    return alreadyActive.get() ? Response.ok("") : Response.created("");
+    return alreadyActive.get() ? Response.ok() : Response.created();
   }
 }
diff --git a/java/com/google/gerrit/server/patch/PatchScriptBuilder.java b/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
index 71b35d1..0f228fe 100644
--- a/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
+++ b/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
@@ -522,69 +522,67 @@
                 MimeUtil2.UNKNOWN_MIME_TYPE,
                 DisplayMethod.NONE,
                 false);
+          }
+          Text src =
+              isCommitMsg
+                  ? Text.forCommit(reader, within)
+                  : Text.forMergeList(comparisonType, reader, within);
+          byte[] srcContent = src.getContent();
+          DisplayMethod displayMethod;
+          FileMode mode;
+          if (src == Text.EMPTY) {
+            mode = FileMode.MISSING;
+            displayMethod = DisplayMethod.NONE;
           } else {
-            Text src =
-                isCommitMsg
-                    ? Text.forCommit(reader, within)
-                    : Text.forMergeList(comparisonType, reader, within);
-            byte[] srcContent = src.getContent();
-            DisplayMethod displayMethod;
-            FileMode mode;
-            if (src == Text.EMPTY) {
-              mode = FileMode.MISSING;
-              displayMethod = DisplayMethod.NONE;
-            } else {
-              mode = FileMode.REGULAR_FILE;
-              displayMethod = DisplayMethod.DIFF;
-            }
-            return createSide(
-                path,
-                within,
-                mode,
-                srcContent,
-                src,
-                MimeUtil2.UNKNOWN_MIME_TYPE,
-                displayMethod,
-                false);
+            mode = FileMode.REGULAR_FILE;
+            displayMethod = DisplayMethod.DIFF;
           }
-        } else {
-          final TreeWalk tw = find(path, within);
-          ObjectId id = tw != null ? tw.getObjectId(0) : ObjectId.zeroId();
-          FileMode mode = tw != null ? tw.getFileMode(0) : FileMode.MISSING;
-          boolean reuse =
-              other != null
-                  && other.id.equals(id)
-                  && (other.mode == mode || isBothFile(other.mode, mode));
-          Text src = null;
-          byte[] srcContent;
-          if (reuse) {
-            srcContent = other.srcContent;
-
-          } else if (mode.getObjectType() == Constants.OBJ_BLOB) {
-            srcContent = Text.asByteArray(db.open(id, Constants.OBJ_BLOB));
-
-          } else if (mode.getObjectType() == Constants.OBJ_COMMIT) {
-            String strContent = "Subproject commit " + ObjectId.toString(id);
-            srcContent = strContent.getBytes(UTF_8);
-
-          } else {
-            srcContent = Text.NO_BYTES;
-          }
-          MimeType mimeType = MimeUtil2.UNKNOWN_MIME_TYPE;
-          DisplayMethod displayMethod = DisplayMethod.DIFF;
-          if (reuse) {
-            mimeType = other.mimeType;
-            displayMethod = other.displayMethod;
-            src = other.src;
-
-          } else if (srcContent.length > 0 && FileMode.SYMLINK != mode) {
-            mimeType = registry.getMimeType(path, srcContent);
-            if ("image".equals(mimeType.getMediaType()) && registry.isSafeInline(mimeType)) {
-              displayMethod = DisplayMethod.IMG;
-            }
-          }
-          return createSide(path, id, mode, srcContent, src, mimeType, displayMethod, reuse);
+          return createSide(
+              path,
+              within,
+              mode,
+              srcContent,
+              src,
+              MimeUtil2.UNKNOWN_MIME_TYPE,
+              displayMethod,
+              false);
         }
+        final TreeWalk tw = find(path, within);
+        ObjectId id = tw != null ? tw.getObjectId(0) : ObjectId.zeroId();
+        FileMode mode = tw != null ? tw.getFileMode(0) : FileMode.MISSING;
+        boolean reuse =
+            other != null
+                && other.id.equals(id)
+                && (other.mode == mode || isBothFile(other.mode, mode));
+        Text src = null;
+        byte[] srcContent;
+        if (reuse) {
+          srcContent = other.srcContent;
+
+        } else if (mode.getObjectType() == Constants.OBJ_BLOB) {
+          srcContent = Text.asByteArray(db.open(id, Constants.OBJ_BLOB));
+
+        } else if (mode.getObjectType() == Constants.OBJ_COMMIT) {
+          String strContent = "Subproject commit " + ObjectId.toString(id);
+          srcContent = strContent.getBytes(UTF_8);
+
+        } else {
+          srcContent = Text.NO_BYTES;
+        }
+        MimeType mimeType = MimeUtil2.UNKNOWN_MIME_TYPE;
+        DisplayMethod displayMethod = DisplayMethod.DIFF;
+        if (reuse) {
+          mimeType = other.mimeType;
+          displayMethod = other.displayMethod;
+          src = other.src;
+
+        } else if (srcContent.length > 0 && FileMode.SYMLINK != mode) {
+          mimeType = registry.getMimeType(path, srcContent);
+          if ("image".equals(mimeType.getMediaType()) && registry.isSafeInline(mimeType)) {
+            displayMethod = DisplayMethod.IMG;
+          }
+        }
+        return createSide(path, id, mode, srcContent, src, mimeType, displayMethod, reuse);
       } catch (IOException err) {
         throw new IOException("Cannot read " + within.name() + ":" + path, err);
       }
diff --git a/java/com/google/gerrit/server/restapi/account/PutPreferred.java b/java/com/google/gerrit/server/restapi/account/PutPreferred.java
index 2ddea2f..c781246 100644
--- a/java/com/google/gerrit/server/restapi/account/PutPreferred.java
+++ b/java/com/google/gerrit/server/restapi/account/PutPreferred.java
@@ -145,6 +145,6 @@
     if (exception.get().isPresent()) {
       throw exception.get().get();
     }
-    return alreadyPreferred.get() ? Response.ok("") : Response.created("");
+    return alreadyPreferred.get() ? Response.ok() : Response.created();
   }
 }
diff --git a/java/com/google/gerrit/server/restapi/change/GetDiff.java b/java/com/google/gerrit/server/restapi/change/GetDiff.java
index 857205a..74562c2 100644
--- a/java/com/google/gerrit/server/restapi/change/GetDiff.java
+++ b/java/com/google/gerrit/server/restapi/change/GetDiff.java
@@ -155,23 +155,23 @@
       psf.setLoadHistory(false);
       psf.setLoadComments(context != DiffPreferencesInfo.WHOLE_FILE_CONTEXT);
       PatchScript ps = psf.call();
-      Content content = new Content(ps);
+      ContentCollector contentCollector = new ContentCollector(ps);
       Set<Edit> editsDueToRebase = ps.getEditsDueToRebase();
       for (Edit edit : ps.getEdits()) {
         if (edit.getType() == Edit.Type.EMPTY) {
           continue;
         }
-        content.addCommon(edit.getBeginA());
+        contentCollector.addCommon(edit.getBeginA());
 
         checkState(
-            content.nextA == edit.getBeginA(),
+            contentCollector.nextA == edit.getBeginA(),
             "nextA = %s; want %s",
-            content.nextA,
+            contentCollector.nextA,
             edit.getBeginA());
         checkState(
-            content.nextB == edit.getBeginB(),
+            contentCollector.nextB == edit.getBeginB(),
             "nextB = %s; want %s",
-            content.nextB,
+            contentCollector.nextB,
             edit.getBeginB());
         switch (edit.getType()) {
           case DELETE:
@@ -180,19 +180,19 @@
             List<Edit> internalEdit =
                 edit instanceof ReplaceEdit ? ((ReplaceEdit) edit).getInternalEdits() : null;
             boolean dueToRebase = editsDueToRebase.contains(edit);
-            content.addDiff(edit.getEndA(), edit.getEndB(), internalEdit, dueToRebase);
+            contentCollector.addDiff(edit.getEndA(), edit.getEndB(), internalEdit, dueToRebase);
             break;
           case EMPTY:
           default:
             throw new IllegalStateException();
         }
       }
-      content.addCommon(ps.getA().size());
+      contentCollector.addCommon(ps.getA().size());
 
       ProjectState state = projectCache.get(resource.getRevision().getChange().getProject());
 
       DiffInfo result = new DiffInfo();
-      String revA = basePatchSet != null ? basePatchSet.refName() : content.commitIdA;
+      String revA = basePatchSet != null ? basePatchSet.refName() : ps.getFileInfoA().commitId;
       String revB =
           resource.getRevision().getEdit().isPresent()
               ? resource.getRevision().getEdit().get().getRefName()
@@ -221,7 +221,7 @@
                 state, result.metaA.name, ps.getFileModeA(), ps.getMimeTypeA());
         result.metaA.lines = ps.getA().size();
         result.metaA.webLinks = getFileWebLinks(state.getProject(), revA, result.metaA.name);
-        result.metaA.commitId = content.commitIdA;
+        result.metaA.commitId = ps.getFileInfoA().commitId;
       }
 
       if (ps.getDisplayMethodB() != DisplayMethod.NONE) {
@@ -232,7 +232,7 @@
                 state, result.metaB.name, ps.getFileModeB(), ps.getMimeTypeB());
         result.metaB.lines = ps.getB().size();
         result.metaB.webLinks = getFileWebLinks(state.getProject(), revB, result.metaB.name);
-        result.metaB.commitId = content.commitIdB;
+        result.metaB.commitId = ps.getFileInfoB().commitId;
       }
 
       if (intraline) {
@@ -253,7 +253,7 @@
       if (ps.getPatchHeader().size() > 0) {
         result.diffHeader = ps.getPatchHeader();
       }
-      result.content = content.lines;
+      result.content = contentCollector.lines;
 
       Response<DiffInfo> r = Response.ok(result);
       if (resource.isCacheable()) {
@@ -297,24 +297,20 @@
     return this;
   }
 
-  private static class Content {
+  private static class ContentCollector {
     final List<ContentEntry> lines;
     final SparseFileContent fileA;
     final SparseFileContent fileB;
     final boolean ignoreWS;
-    final String commitIdA;
-    final String commitIdB;
 
     int nextA;
     int nextB;
 
-    Content(PatchScript ps) {
+    ContentCollector(PatchScript ps) {
       lines = Lists.newArrayListWithExpectedSize(ps.getEdits().size() + 2);
       fileA = ps.getA();
       fileB = ps.getB();
       ignoreWS = ps.isIgnoreWhitespace();
-      commitIdA = ps.getCommitIdA();
-      commitIdB = ps.getCommitIdB();
     }
 
     void addCommon(int end) {
diff --git a/java/com/google/gerrit/server/restapi/change/Ignore.java b/java/com/google/gerrit/server/restapi/change/Ignore.java
index 25cf311..a049e54 100644
--- a/java/com/google/gerrit/server/restapi/change/Ignore.java
+++ b/java/com/google/gerrit/server/restapi/change/Ignore.java
@@ -60,7 +60,7 @@
       if (!isIgnored(rsrc)) {
         stars.ignore(rsrc);
       }
-      return Response.ok("");
+      return Response.ok();
     } catch (MutuallyExclusiveLabelsException e) {
       throw new ResourceConflictException(e.getMessage());
     }
diff --git a/java/com/google/gerrit/server/restapi/change/MarkAsReviewed.java b/java/com/google/gerrit/server/restapi/change/MarkAsReviewed.java
index 4c942d2..fa4555b 100644
--- a/java/com/google/gerrit/server/restapi/change/MarkAsReviewed.java
+++ b/java/com/google/gerrit/server/restapi/change/MarkAsReviewed.java
@@ -54,7 +54,7 @@
   public Response<String> apply(ChangeResource rsrc, Input input)
       throws RestApiException, IllegalLabelException {
     stars.markAsReviewed(rsrc);
-    return Response.ok("");
+    return Response.ok();
   }
 
   private boolean isReviewed(ChangeResource rsrc) {
diff --git a/java/com/google/gerrit/server/restapi/change/MarkAsUnreviewed.java b/java/com/google/gerrit/server/restapi/change/MarkAsUnreviewed.java
index 5945b14..601fc4a 100644
--- a/java/com/google/gerrit/server/restapi/change/MarkAsUnreviewed.java
+++ b/java/com/google/gerrit/server/restapi/change/MarkAsUnreviewed.java
@@ -52,7 +52,7 @@
   @Override
   public Response<String> apply(ChangeResource rsrc, Input input) throws IllegalLabelException {
     stars.markAsUnreviewed(rsrc);
-    return Response.ok("");
+    return Response.ok();
   }
 
   private boolean isReviewed(ChangeResource rsrc) {
diff --git a/java/com/google/gerrit/server/restapi/change/PostPrivate.java b/java/com/google/gerrit/server/restapi/change/PostPrivate.java
index 7ccdfff..c9ad049 100644
--- a/java/com/google/gerrit/server/restapi/change/PostPrivate.java
+++ b/java/com/google/gerrit/server/restapi/change/PostPrivate.java
@@ -71,7 +71,7 @@
     }
 
     if (rsrc.getChange().isPrivate()) {
-      return Response.ok("");
+      return Response.ok();
     }
 
     SetPrivateOp op = setPrivateOpFactory.create(true, input);
@@ -80,7 +80,7 @@
       u.addOp(rsrc.getId(), op).execute();
     }
 
-    return Response.created("");
+    return Response.created();
   }
 
   @Override
diff --git a/java/com/google/gerrit/server/restapi/change/Reviewed.java b/java/com/google/gerrit/server/restapi/change/Reviewed.java
index 7152799..2793059 100644
--- a/java/com/google/gerrit/server/restapi/change/Reviewed.java
+++ b/java/com/google/gerrit/server/restapi/change/Reviewed.java
@@ -43,7 +43,7 @@
                       resource.getPatchKey().patchSetId(),
                       resource.getAccountId(),
                       resource.getPatchKey().fileName()));
-      return reviewFlagUpdated ? Response.created("") : Response.ok("");
+      return reviewFlagUpdated ? Response.created() : Response.ok();
     }
   }
 
diff --git a/java/com/google/gerrit/server/restapi/change/SetReadyForReview.java b/java/com/google/gerrit/server/restapi/change/SetReadyForReview.java
index 288806c..8470742 100644
--- a/java/com/google/gerrit/server/restapi/change/SetReadyForReview.java
+++ b/java/com/google/gerrit/server/restapi/change/SetReadyForReview.java
@@ -69,7 +69,7 @@
       bu.setNotify(NotifyResolver.Result.create(firstNonNull(input.notify, NotifyHandling.ALL)));
       bu.addOp(rsrc.getChange().getId(), opFactory.create(false, input));
       bu.execute();
-      return Response.ok("");
+      return Response.ok();
     }
   }
 
diff --git a/java/com/google/gerrit/server/restapi/change/SetWorkInProgress.java b/java/com/google/gerrit/server/restapi/change/SetWorkInProgress.java
index 3fb0295..60884c9 100644
--- a/java/com/google/gerrit/server/restapi/change/SetWorkInProgress.java
+++ b/java/com/google/gerrit/server/restapi/change/SetWorkInProgress.java
@@ -69,7 +69,7 @@
       bu.setNotify(NotifyResolver.Result.create(firstNonNull(input.notify, NotifyHandling.NONE)));
       bu.addOp(rsrc.getChange().getId(), opFactory.create(true, input));
       bu.execute();
-      return Response.ok("");
+      return Response.ok();
     }
   }
 
diff --git a/java/com/google/gerrit/server/restapi/change/Unignore.java b/java/com/google/gerrit/server/restapi/change/Unignore.java
index 26d3233..999e736 100644
--- a/java/com/google/gerrit/server/restapi/change/Unignore.java
+++ b/java/com/google/gerrit/server/restapi/change/Unignore.java
@@ -50,7 +50,7 @@
     if (isIgnored(rsrc)) {
       stars.unignore(rsrc);
     }
-    return Response.ok("");
+    return Response.ok();
   }
 
   private boolean isIgnored(ChangeResource rsrc) {
diff --git a/java/com/google/gerrit/server/restapi/config/FlushCache.java b/java/com/google/gerrit/server/restapi/config/FlushCache.java
index 9ea9e33..f10ed8d 100644
--- a/java/com/google/gerrit/server/restapi/config/FlushCache.java
+++ b/java/com/google/gerrit/server/restapi/config/FlushCache.java
@@ -50,6 +50,6 @@
     }
 
     rsrc.getCache().invalidateAll();
-    return Response.ok("");
+    return Response.ok();
   }
 }
diff --git a/java/com/google/gerrit/server/restapi/config/PostCaches.java b/java/com/google/gerrit/server/restapi/config/PostCaches.java
index c633af0..c9480c5 100644
--- a/java/com/google/gerrit/server/restapi/config/PostCaches.java
+++ b/java/com/google/gerrit/server/restapi/config/PostCaches.java
@@ -84,13 +84,13 @@
               "specifying caches is not allowed for operation 'FLUSH_ALL'");
         }
         flushAll();
-        return Response.ok("");
+        return Response.ok();
       case FLUSH:
         if (input.caches == null || input.caches.isEmpty()) {
           throw new BadRequestException("caches must be specified for operation 'FLUSH'");
         }
         flush(input.caches);
-        return Response.ok("");
+        return Response.ok();
       default:
         throw new BadRequestException("unsupported operation: " + input.operation);
     }
diff --git a/java/com/google/gerrit/server/restapi/project/DeleteRef.java b/java/com/google/gerrit/server/restapi/project/DeleteRef.java
index 805a4d7..1979d61 100644
--- a/java/com/google/gerrit/server/restapi/project/DeleteRef.java
+++ b/java/com/google/gerrit/server/restapi/project/DeleteRef.java
@@ -27,6 +27,7 @@
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.entities.BranchNameKey;
 import com.google.gerrit.entities.Project;
+import com.google.gerrit.exceptions.StorageException;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.server.IdentifiedUser;
@@ -156,7 +157,7 @@
           break;
 
         case REJECTED_CURRENT_BRANCH:
-          logger.atSevere().log("Cannot delete %s: %s", ref, result.name());
+          logger.atFine().log("Cannot delete current branch %s: %s", ref, result.name());
           throw new ResourceConflictException("cannot delete current branch");
 
         case IO_FAILURE:
@@ -167,8 +168,7 @@
         case REJECTED_MISSING_OBJECT:
         case REJECTED_OTHER_REASON:
         default:
-          logger.atSevere().log("Cannot delete %s: %s", ref, result.name());
-          throw new ResourceConflictException("cannot delete: " + result.name());
+          throw new StorageException(String.format("Cannot delete %s: %s", ref, result.name()));
       }
     }
   }
diff --git a/javatests/com/google/gerrit/acceptance/pgm/ElasticReindexIT.java b/javatests/com/google/gerrit/acceptance/pgm/ElasticReindexIT.java
index c0f27bd..dcdca86 100644
--- a/javatests/com/google/gerrit/acceptance/pgm/ElasticReindexIT.java
+++ b/javatests/com/google/gerrit/acceptance/pgm/ElasticReindexIT.java
@@ -41,7 +41,7 @@
   }
 
   @Override
-  public void configureIndex(Injector injector) throws Exception {
+  public void configureIndex(Injector injector) {
     createAllIndexes(injector);
   }
 
diff --git a/javatests/com/google/gerrit/acceptance/ssh/AbstractIndexTests.java b/javatests/com/google/gerrit/acceptance/ssh/AbstractIndexTests.java
index c841559..4fe0df4 100644
--- a/javatests/com/google/gerrit/acceptance/ssh/AbstractIndexTests.java
+++ b/javatests/com/google/gerrit/acceptance/ssh/AbstractIndexTests.java
@@ -57,7 +57,7 @@
       disableChangeIndexWrites();
       amendChange(changeId, "second test", "test2.txt", "test2");
 
-      assertChangeQuery("message:second", change.getChange(), false);
+      assertChangeQuery(change.getChange(), false);
       enableChangeIndexWrites();
 
       changeIndexedCounter.clear();
@@ -67,7 +67,7 @@
 
       changeIndexedCounter.assertReindexOf(changeInfo, 1);
 
-      assertChangeQuery("message:second", change.getChange(), true);
+      assertChangeQuery(change.getChange(), true);
     }
   }
 
@@ -86,7 +86,7 @@
       disableChangeIndexWrites();
       amendChange(changeId, "second test", "test2.txt", "test2");
 
-      assertChangeQuery("message:second", change.getChange(), false);
+      assertChangeQuery(change.getChange(), false);
       enableChangeIndexWrites();
 
       changeIndexedCounter.clear();
@@ -103,13 +103,12 @@
 
       changeIndexedCounter.assertReindexOf(changeInfo, 1);
 
-      assertChangeQuery("message:second", change.getChange(), true);
+      assertChangeQuery(change.getChange(), true);
     }
   }
 
-  protected void assertChangeQuery(String q, ChangeData change, boolean assertTrue)
-      throws Exception {
-    List<Integer> ids = query(q).stream().map(c -> c._number).collect(toList());
+  private void assertChangeQuery(ChangeData change, boolean assertTrue) throws Exception {
+    List<Integer> ids = query("message:second").stream().map(c -> c._number).collect(toList());
     if (assertTrue) {
       assertThat(ids).contains(change.getId().get());
     } else {
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.js b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.js
index 261ddda..ed1e3db 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.js
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.js
@@ -232,9 +232,13 @@
         e.detail.value[this.$.textarea.selectionStart - 1] : '';
       if (charAtCursor !== ':' && this._colonIndex == null) { return; }
 
-      // When a colon is detected, set a colon index.
+      // When a colon is detected, set a colon index. We are interested only on
+      // colons after space or in beginning of textarea
       if (charAtCursor === ':') {
-        this._colonIndex = this.$.textarea.selectionStart - 1;
+        if (this.$.textarea.selectionStart < 2 ||
+            e.detail.value[this.$.textarea.selectionStart - 2] === ' ') {
+          this._colonIndex = this.$.textarea.selectionStart - 1;
+        }
       }
 
       this._currentSearchString = e.detail.value.substr(this._colonIndex + 1,
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
index 4c59f50..ae1de02 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
@@ -98,6 +98,34 @@
           assert.equal(element._currentSearchString, '');
         });
 
+    test('emoji selector opens when a colon is typed after space',
+        () => {
+          MockInteractions.focus(element.$.textarea);
+          // Needed for Safari tests. selectionStart is not updated when text is
+          // updated.
+          element.$.textarea.selectionStart = 2;
+          element.$.textarea.selectionEnd = 2;
+          element.text = ' :';
+          flushAsynchronousOperations();
+          assert.isFalse(element.$.emojiSuggestions.isHidden);
+          assert.equal(element._colonIndex, 1);
+          assert.isFalse(element._hideAutocomplete);
+          assert.equal(element._currentSearchString, '');
+        });
+
+    test('emoji selector doesn\`t open when a colon is typed after character',
+        () => {
+          MockInteractions.focus(element.$.textarea);
+          // Needed for Safari tests. selectionStart is not updated when text is
+          // updated.
+          element.$.textarea.selectionStart = 5;
+          element.$.textarea.selectionEnd = 5;
+          element.text = 'test:';
+          flushAsynchronousOperations();
+          assert.isTrue(element.$.emojiSuggestions.isHidden);
+          assert.isTrue(element._hideAutocomplete);
+        });
+
     test('emoji selector opens when a colon is typed and some substring',
         () => {
           MockInteractions.focus(element.$.textarea);
diff --git a/tools/bzl/genrule2.bzl b/tools/bzl/genrule2.bzl
index 3113022..d0b0969 100644
--- a/tools/bzl/genrule2.bzl
+++ b/tools/bzl/genrule2.bzl
@@ -21,6 +21,7 @@
         "ROOT=$$PWD",
         "TMP=$$(mktemp -d || mktemp -d -t bazel-tmp)",
         "(" + cmd + ")",
+        "rm -rf $$TMP",
     ])
     native.genrule(
         cmd = cmd,