Merge "Update rules_closure to latest version" 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 c908f99..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,11 +3183,19 @@
[[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.
+[[elasticsearch.maxResultWindow]]elasticsearch.maxResultWindow::
++
+Sets the maximum value of `from + size` for searches to use per index. Refer to the
+link:https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules.html#dynamic-index-settings[
+Elasticsearch documentation] for details.
++
+Defaults to 10000.
+
==== Elasticsearch Security
When security is enabled in Elasticsearch, the username and password must be provided.
@@ -5059,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/java/com/google/gerrit/elasticsearch/ElasticConfiguration.java b/java/com/google/gerrit/elasticsearch/ElasticConfiguration.java
index cbe9bc7..35c33cb 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticConfiguration.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticConfiguration.java
@@ -40,10 +40,13 @@
static final String KEY_SERVER = "server";
static final String KEY_NUMBER_OF_SHARDS = "numberOfShards";
static final String KEY_NUMBER_OF_REPLICAS = "numberOfReplicas";
+ static final String KEY_MAX_RESULT_WINDOW = "maxResultWindow";
+
static final String DEFAULT_PORT = "9200";
static final String DEFAULT_USERNAME = "elastic";
static final int DEFAULT_NUMBER_OF_SHARDS = 0;
static final int DEFAULT_NUMBER_OF_REPLICAS = 1;
+ static final int DEFAULT_MAX_RESULT_WINDOW = 10000;
private final Config cfg;
private final List<HttpHost> hosts;
@@ -52,6 +55,7 @@
final String password;
final int numberOfShards;
final int numberOfReplicas;
+ final int maxResultWindow;
final String prefix;
@Inject
@@ -68,6 +72,8 @@
cfg.getInt(SECTION_ELASTICSEARCH, null, KEY_NUMBER_OF_SHARDS, DEFAULT_NUMBER_OF_SHARDS);
this.numberOfReplicas =
cfg.getInt(SECTION_ELASTICSEARCH, null, KEY_NUMBER_OF_REPLICAS, DEFAULT_NUMBER_OF_REPLICAS);
+ this.maxResultWindow =
+ cfg.getInt(SECTION_ELASTICSEARCH, null, KEY_MAX_RESULT_WINDOW, DEFAULT_MAX_RESULT_WINDOW);
this.hosts = new ArrayList<>();
for (String server : cfg.getStringList(SECTION_ELASTICSEARCH, null, KEY_SERVER)) {
try {
diff --git a/java/com/google/gerrit/elasticsearch/ElasticSetting.java b/java/com/google/gerrit/elasticsearch/ElasticSetting.java
index 14e4623..e016efb 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticSetting.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticSetting.java
@@ -35,6 +35,7 @@
properties.analysis = fields.build();
properties.numberOfShards = config.getNumberOfShards(adapter);
properties.numberOfReplicas = config.numberOfReplicas;
+ properties.maxResultWindow = config.maxResultWindow;
return properties;
}
@@ -75,6 +76,7 @@
Map<String, FieldProperties> analysis;
Integer numberOfShards;
Integer numberOfReplicas;
+ Integer maxResultWindow;
}
static class FieldProperties {
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/server/query/change/ChangeQueryBuilder.java b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index 10b3bc8..61726b8 100644
--- a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -22,6 +22,7 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Enums;
import com.google.common.base.Splitter;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
import com.google.gerrit.common.data.GroupDescription;
@@ -913,12 +914,10 @@
return isVisible();
}
Set<Account.Id> m = args.accountResolver.findAll(who);
- if (!m.isEmpty()) {
- List<Predicate<ChangeData>> p = Lists.newArrayListWithCapacity(m.size());
- for (Account.Id id : m) {
- return visibleto(args.userFactory.create(id));
- }
- return Predicate.or(p);
+ if (m.size() == 1) {
+ return visibleto(args.userFactory.create(Iterables.getOnlyElement(m)));
+ } else if (m.size() > 1) {
+ throw error(String.format("\"%s\" resolves to multiple accounts", who));
}
// If its not an account, maybe its a group?
diff --git a/java/com/google/gerrit/server/schema/Schema_151.java b/java/com/google/gerrit/server/schema/Schema_151.java
index 41d8a32..bab9f41 100644
--- a/java/com/google/gerrit/server/schema/Schema_151.java
+++ b/java/com/google/gerrit/server/schema/Schema_151.java
@@ -14,11 +14,15 @@
package com.google.gerrit.server.schema;
+import com.google.common.annotations.VisibleForTesting;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.jdbc.JdbcSchema;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -26,6 +30,7 @@
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import java.util.Optional;
/** A schema which adds the 'created on' field to groups. */
@@ -37,6 +42,13 @@
@Override
protected void migrateData(ReviewDb db, UpdateUI ui) throws OrmException, SQLException {
+ Connection connection = ((JdbcSchema) db).getConnection();
+ if (!createdOnColumnExists(connection)) {
+ try (Statement stmt = connection.createStatement()) {
+ stmt.execute("ALTER TABLE account_groups ADD COLUMN created_on TIMESTAMP NULL");
+ }
+ }
+
try (PreparedStatement groupUpdate =
prepareStatement(db, "UPDATE account_groups SET created_on = ? WHERE group_id = ?");
PreparedStatement addedOnRetrieval =
@@ -56,6 +68,20 @@
}
}
+ @VisibleForTesting
+ public static boolean createdOnColumnExists(Connection connection) throws SQLException {
+ DatabaseMetaData metaData = connection.getMetaData();
+ boolean toUpper = metaData.storesUpperCaseIdentifiers();
+ return metaData
+ .getColumns(
+ null, null, convertCase(toUpper, "account_groups"), convertCase(toUpper, "created_on"))
+ .next();
+ }
+
+ private static String convertCase(boolean toUpper, String input) {
+ return toUpper ? input.toUpperCase(Locale.US) : input;
+ }
+
private static Optional<Timestamp> getFirstTimeMentioned(
PreparedStatement addedOnRetrieval, AccountGroup.Id groupId) throws SQLException {
addedOnRetrieval.setInt(1, groupId.get());
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/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index 0ebbdc9..bd2b359 100644
--- a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -1710,16 +1710,43 @@
assertQuery(q + " visibleto:self", change2, change1);
// Second user cannot see first user's private change
- Account.Id user2 = createAccount("anotheruser");
+ Account.Id user2 = createAccount("user2");
assertQuery(q + " visibleto:" + user2.get(), change1);
- assertQuery(q + " visibleto:anotheruser", change1);
+ assertQuery(q + " visibleto:user2", change1);
String g1 = createGroup("group1", "Administrators");
- gApi.groups().id(g1).addMembers("anotheruser");
+ gApi.groups().id(g1).addMembers("user2");
assertQuery(q + " visibleto:" + g1, change1);
requestContext.setContext(newRequestContext(user2));
assertQuery("is:visible", change1);
+
+ Account.Id user3 = createAccount("user3");
+
+ // Explicitly authenticate user2 and user3 so that display name gets set
+ AuthRequest authRequest = AuthRequest.forUser("user2");
+ authRequest.setDisplayName("Another User");
+ authRequest.setEmailAddress("user2@example.com");
+ accountManager.authenticate(authRequest);
+ authRequest = AuthRequest.forUser("user3");
+ authRequest.setDisplayName("Another User");
+ authRequest.setEmailAddress("user3@example.com");
+ accountManager.authenticate(authRequest);
+
+ // Switch to user3
+ requestContext.setContext(newRequestContext(user3));
+ Change change3 = insert(repo, newChange(repo), user3);
+ Change change4 = insert(repo, newChangePrivate(repo), user3);
+
+ // User3 can see both their changes and the first user's change
+ assertQuery(q + " visibleto:" + user3.get(), change4, change3, change1);
+
+ // User2 cannot see user3's private change
+ assertQuery(q + " visibleto:" + user2.get(), change3, change1);
+
+ // Query as user3 by display name matching user2 and user3; bad request
+ assertFailingQuery(
+ q + " visibleto:\"Another User\"", "\"Another User\" resolves to multiple accounts");
}
@Test
diff --git a/javatests/com/google/gerrit/server/schema/Schema_150_to_151_Test.java b/javatests/com/google/gerrit/server/schema/Schema_150_to_151_Test.java
index 4d5db6d..2e268ee 100644
--- a/javatests/com/google/gerrit/server/schema/Schema_150_to_151_Test.java
+++ b/javatests/com/google/gerrit/server/schema/Schema_150_to_151_Test.java
@@ -16,6 +16,7 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.TruthJUnit.assume;
+import static com.google.gerrit.server.schema.Schema_151.createdOnColumnExists;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
@@ -151,6 +152,17 @@
assertThat(createdOn).isEqualTo(AccountGroup.auditCreationInstantTs());
}
+ @Test
+ public void createdOnIsAddedWhenItIsMissing() throws Exception {
+ assertThat(createdOnColumnExists(connection)).isTrue();
+ try (Statement deleteColumn = connection.createStatement()) {
+ deleteColumn.execute("ALTER TABLE account_groups DROP COLUMN created_on");
+ }
+ assertThat(createdOnColumnExists(connection)).isFalse();
+ schema151.migrateData(db, new TestUpdateUI());
+ assertThat(createdOnColumnExists(connection)).isTrue();
+ }
+
private AccountGroup.Id createGroupInReviewDb(String name) throws Exception {
AccountGroup group =
new AccountGroup(
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/maven/gerrit-acceptance-framework_pom.xml b/tools/maven/gerrit-acceptance-framework_pom.xml
index 341d5a9..f85dca2 100644
--- a/tools/maven/gerrit-acceptance-framework_pom.xml
+++ b/tools/maven/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.16.17-SNAPSHOT</version>
+ <version>2.16.18-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Gerrit Code Review - Acceptance Test Framework</name>
<description>Framework for Gerrit's acceptance tests</description>
diff --git a/tools/maven/gerrit-extension-api_pom.xml b/tools/maven/gerrit-extension-api_pom.xml
index ffb0158..892f954 100644
--- a/tools/maven/gerrit-extension-api_pom.xml
+++ b/tools/maven/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.16.17-SNAPSHOT</version>
+ <version>2.16.18-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Gerrit Code Review - Extension API</name>
<description>API for Gerrit Extensions</description>
diff --git a/tools/maven/gerrit-plugin-api_pom.xml b/tools/maven/gerrit-plugin-api_pom.xml
index 89a0855..8aef367 100644
--- a/tools/maven/gerrit-plugin-api_pom.xml
+++ b/tools/maven/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.16.17-SNAPSHOT</version>
+ <version>2.16.18-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Gerrit Code Review - Plugin API</name>
<description>API for Gerrit Plugins</description>
diff --git a/tools/maven/gerrit-plugin-gwtui_pom.xml b/tools/maven/gerrit-plugin-gwtui_pom.xml
index 8867410..e4e6adb 100644
--- a/tools/maven/gerrit-plugin-gwtui_pom.xml
+++ b/tools/maven/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.16.17-SNAPSHOT</version>
+ <version>2.16.18-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Gerrit Code Review - Plugin GWT UI</name>
<description>Common Classes for Gerrit GWT UI Plugins</description>
diff --git a/tools/maven/gerrit-war_pom.xml b/tools/maven/gerrit-war_pom.xml
index d21e9e4..0e99675 100644
--- a/tools/maven/gerrit-war_pom.xml
+++ b/tools/maven/gerrit-war_pom.xml
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-war</artifactId>
- <version>2.16.17-SNAPSHOT</version>
+ <version>2.16.18-SNAPSHOT</version>
<packaging>war</packaging>
<name>Gerrit Code Review - WAR</name>
<description>Gerrit WAR</description>
diff --git a/version.bzl b/version.bzl
index df79f83..0c28b2c 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.16.17-SNAPSHOT"
+GERRIT_VERSION = "2.16.18-SNAPSHOT"