Merge "Support 'max_result_window' config for Elasticsearch indexes" into stable-2.16
diff --git a/.zuul.yaml b/.zuul.yaml
new file mode 100644
index 0000000..a98975b
--- /dev/null
+++ b/.zuul.yaml
@@ -0,0 +1,32 @@
+- job:
+    name: gerrit-base
+    parent: gerrit-setup
+    description: |
+      Base job for all Gerrit-related builds
+
+      This adds required projects needed for all Gerrit-related builds
+      (i.e., builds of Gerrit itself or plugins) on this branch.
+    # No additional required projects required for this branch.
+
+- job:
+    name: gerrit-build
+    parent: gerrit-build-base
+    description: |
+      Build Gerrit
+
+      This builds Gerrit with the core plugins.
+    required-projects:
+      # This inherits from gerrit-base, so submodules listed above do
+      # not need to be repeated here.
+      - plugins/codemirror-editor
+      - plugins/commit-message-length-validator
+      - plugins/download-commands
+      - plugins/hooks
+      - plugins/replication
+      - plugins/reviewnotes
+      - plugins/singleusergroup
+
+- project:
+    check:
+      jobs:
+        - gerrit-build
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 7af7cb8..8637567 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -3175,7 +3175,7 @@
 [[elasticsearch.numberOfShards]]elasticsearch.numberOfShards::
 +
 Sets the number of shards to use per index. Refer to the
-link:https://www.elastic.co/guide/en/elasticsearch/reference/current/getting-started-concepts.html#getting-started-shards-and-replicas[
+link:https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules.html#_static_index_settings[
 Elasticsearch documentation] for details.
 +
 Defaults to 5 for Elasticsearch versions 5 and 6, and to 1 starting with Elasticsearch 7.
@@ -3183,7 +3183,7 @@
 [[elasticsearch.numberOfReplicas]]elasticsearch.numberOfReplicas::
 +
 Sets the number of replicas to use per index. Refer to the
-link:https://www.elastic.co/guide/en/elasticsearch/reference/current/getting-started-concepts.html#getting-started-shards-and-replicas[
+link:https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules.html#dynamic-index-settings[
 Elasticsearch documentation] for details.
 +
 Defaults to 1.
@@ -5067,6 +5067,10 @@
 The link:#schedule-configuration-interval[interval] for running
 account deactivations.
 
+Note that the task will only be scheduled if the
+link:#autoUpdateAccountActiveStatus[auth.autoUpdateAccountActiveStatus]
+is set to true.
+
 link:#schedule-configuration-examples[Schedule examples] can be found
 in the link:#schedule-configuration[Schedule Configuration] section.
 
diff --git a/Documentation/prolog-change-facts.txt b/Documentation/prolog-change-facts.txt
index 2fb13e9..ac69616 100644
--- a/Documentation/prolog-change-facts.txt
+++ b/Documentation/prolog-change-facts.txt
@@ -48,6 +48,9 @@
 |`commit_message/1`   |`commit_message('Fix bug X').`
     |Commit message as string atom
 
+|`commit_parent_count/1`   |`commit_parent_count(1).`
+    |Number of parent commits of a commit. Can be used to detect merge commits
+
 |`commit_stats/3`   |`commit_stats(5,20,50).`
     |Number of files modified, number of insertions and the number of deletions.
 
diff --git a/java/com/google/gerrit/server/account/AccountDeactivator.java b/java/com/google/gerrit/server/account/AccountDeactivator.java
index b0dc527..ac02322 100644
--- a/java/com/google/gerrit/server/account/AccountDeactivator.java
+++ b/java/com/google/gerrit/server/account/AccountDeactivator.java
@@ -57,10 +57,14 @@
 
     @Override
     public void start() {
-      if (!supportAutomaticAccountActivityUpdate) {
-        return;
+      if (schedule.isPresent()) {
+        if (supportAutomaticAccountActivityUpdate) {
+          queue.scheduleAtFixedRate(deactivator, schedule.get());
+        } else {
+          logger.atWarning().log(
+              "Not scheduling AccountDeactivator because auth.autoUpdateAccountActiveStatus is false");
+        }
       }
-      schedule.ifPresent(s -> queue.scheduleAtFixedRate(deactivator, s));
     }
 
     @Override
diff --git a/java/com/google/gerrit/util/logging/BUILD b/java/com/google/gerrit/util/logging/BUILD
index b8db49bd..ee598a4 100644
--- a/java/com/google/gerrit/util/logging/BUILD
+++ b/java/com/google/gerrit/util/logging/BUILD
@@ -8,6 +8,7 @@
     visibility = ["//visibility:public"],
     deps = [
         "//lib:gson",
+        "//lib/flogger:api",
         "//lib/log:log4j",
     ],
 )
diff --git a/java/com/google/gerrit/util/logging/NamedFluentLogger.java b/java/com/google/gerrit/util/logging/NamedFluentLogger.java
new file mode 100644
index 0000000..04fc18d
--- /dev/null
+++ b/java/com/google/gerrit/util/logging/NamedFluentLogger.java
@@ -0,0 +1,84 @@
+// Copyright (C) 2020 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.google.gerrit.util.logging;
+
+import com.google.common.flogger.AbstractLogger;
+import com.google.common.flogger.LogContext;
+import com.google.common.flogger.LoggingApi;
+import com.google.common.flogger.backend.LoggerBackend;
+import com.google.common.flogger.backend.Platform;
+import com.google.common.flogger.parser.DefaultPrintfMessageParser;
+import com.google.common.flogger.parser.MessageParser;
+import java.util.logging.Level;
+
+/**
+ * FluentLogger.forEnclosingClass() searches for caller class name and passes it as String to
+ * constructor FluentLogger.FluentLogger(LoggerBackend) (which is package protected).
+ *
+ * <p>This allows to create NamedFluentLogger with given name so that dedicated configuration can be
+ * specified by a custom appender in the log4j.properties file. An example of this is the logger
+ * used by the replication queue in the replication plugin, and gerrit's Garbage Collection log.
+ */
+public class NamedFluentLogger extends AbstractLogger<NamedFluentLogger.Api> {
+  /** Copied from FluentLogger */
+  public interface Api extends LoggingApi<Api> {}
+
+  /** Copied from FluentLogger */
+  private static final class NoOp extends LoggingApi.NoOp<Api> implements Api {}
+
+  private static final NoOp NO_OP = new NoOp();
+
+  public static NamedFluentLogger forName(String name) {
+    return new NamedFluentLogger(Platform.getBackend(name));
+  }
+
+  private NamedFluentLogger(LoggerBackend backend) {
+    super(backend);
+  }
+
+  @Override
+  public Api at(Level level) {
+    boolean isLoggable = isLoggable(level);
+    boolean isForced = Platform.shouldForceLogging(getName(), level, isLoggable);
+    return (isLoggable || isForced) ? new Context(level, isForced) : NO_OP;
+  }
+
+  /** Copied from FluentLogger */
+  private final class Context extends LogContext<NamedFluentLogger, Api> implements Api {
+    private Context(Level level, boolean isForced) {
+      super(level, isForced);
+    }
+
+    @Override
+    protected NamedFluentLogger getLogger() {
+      return NamedFluentLogger.this;
+    }
+
+    @Override
+    protected Api api() {
+      return this;
+    }
+
+    @Override
+    protected Api noOp() {
+      return NO_OP;
+    }
+
+    @Override
+    protected MessageParser getMessageParser() {
+      return DefaultPrintfMessageParser.getInstance();
+    }
+  }
+}
diff --git a/java/gerrit/PRED_commit_parent_count_1.java b/java/gerrit/PRED_commit_parent_count_1.java
new file mode 100644
index 0000000..81589dd
--- /dev/null
+++ b/java/gerrit/PRED_commit_parent_count_1.java
@@ -0,0 +1,51 @@
+// Copyright (C) 2020 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 gerrit;
+
+import com.google.gerrit.server.rules.StoredValues;
+import com.googlecode.prolog_cafe.exceptions.PrologException;
+import com.googlecode.prolog_cafe.lang.IntegerTerm;
+import com.googlecode.prolog_cafe.lang.Operation;
+import com.googlecode.prolog_cafe.lang.Predicate;
+import com.googlecode.prolog_cafe.lang.Prolog;
+import com.googlecode.prolog_cafe.lang.Term;
+import org.eclipse.jgit.revwalk.RevCommit;
+
+/**
+ * Prolog fact for the number of parents of a given commit
+ *
+ * <pre>
+ *   'commit_parent_count'(-Count)
+ * </pre>
+ */
+public class PRED_commit_parent_count_1 extends Predicate.P1 {
+  public PRED_commit_parent_count_1(Term a1, Operation n) {
+    arg1 = a1;
+    cont = n;
+  }
+
+  @Override
+  public Operation exec(Prolog engine) throws PrologException {
+    engine.setB0();
+    Term a1 = arg1.dereference();
+
+    RevCommit commit = StoredValues.COMMIT.get(engine);
+
+    if (!a1.unify(new IntegerTerm(commit.getParentCount()), engine.trail)) {
+      return engine.fail();
+    }
+    return cont;
+  }
+}
diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java b/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java
index 96041a1..dd3e364 100644
--- a/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java
+++ b/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java
@@ -53,7 +53,7 @@
       case V6_7:
         return "blacktop/elasticsearch:6.7.2";
       case V6_8:
-        return "blacktop/elasticsearch:6.8.6";
+        return "blacktop/elasticsearch:6.8.7";
       case V7_0:
         return "blacktop/elasticsearch:7.0.1";
       case V7_1:
diff --git a/plugins/BUILD b/plugins/BUILD
index 7d0a2ed..a33ce56 100644
--- a/plugins/BUILD
+++ b/plugins/BUILD
@@ -50,6 +50,7 @@
     "//java/com/google/gerrit/server/util/time",
     "//java/com/google/gerrit/util/cli",
     "//java/com/google/gerrit/util/http",
+    "//java/com/google/gerrit/util/logging",
     "//lib/commons:compress",
     "//lib/commons:dbcp",
     "//lib/commons:lang",
diff --git a/plugins/codemirror-editor b/plugins/codemirror-editor
index 2d3f265..59942b1 160000
--- a/plugins/codemirror-editor
+++ b/plugins/codemirror-editor
@@ -1 +1 @@
-Subproject commit 2d3f265ab1797d4179cbd6855c937989175d5ce5
+Subproject commit 59942b1adf1c949f3633f60ac42f67fae03b3255
diff --git a/plugins/replication b/plugins/replication
index 04bbb43..425f4f2 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 04bbb43e28f14b61412b71ecae19921ab67d62cc
+Subproject commit 425f4f20218986615593da1a9319466743ee12eb
diff --git a/tools/bzl/javadoc.bzl b/tools/bzl/javadoc.bzl
index b5733bd..3add025 100644
--- a/tools/bzl/javadoc.bzl
+++ b/tools/bzl/javadoc.bzl
@@ -32,7 +32,7 @@
         "export TZ",
         "rm -rf %s" % source,
         "mkdir %s" % source,
-        " && ".join(["unzip -qud %s %s" % (source, j.path) for j in source_jars.to_list()]),
+        " && ".join(["unzip -qoud %s %s" % (source, j.path) for j in source_jars.to_list()]),
         "rm -rf %s" % dir,
         "mkdir %s" % dir,
         " ".join([