Merge "Fix `_selectedRevision` for edit patchset"
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 95d78de..0e77e20 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -1696,6 +1696,21 @@
+
Common unit suffixes of 'k', 'm', or 'g' are supported.
+[[core.packedGitUseStrongRefs]]core.packedGitUseStrongRefs::
++
+Set to `true` in order to use strong references to reference packfile
+pages cached in the WindowCache. Otherwise SoftReferences are used.
+If this option is set to `false`, the Java garbage collector will
+flush the WindowCache to free memory if the used heap comes close to
+the maximum heap size. This has the advantage that it can quickly
+reclaim memory which was used by the WindowCache but comes at the
+price that the previously cached pack file content needs to be again
+copied from the file system cache to the Gerrit process.
+Setting this option to `true` prevents flushing the WindowCache
+which provides more predictable performance.
++
+Default is `false`.
+
[[core.deltaBaseCaseLimit]]core.deltaBaseCacheLimit::
+
Maximum number of bytes to reserve for caching base objects
@@ -3571,7 +3586,8 @@
[[log.jsonLogging]]log.jsonLogging::
+
-If set to true, enables error logging in JSON format (file name: "logs/error_log.json").
+If set to true, enables error, ssh and http logging in JSON format (file name:
+"logs/{error|sshd|httpd}_log.json").
+
Defaults to false.
diff --git a/Documentation/dev-bazel.txt b/Documentation/dev-bazel.txt
index 103ae0a..af5bfd3 100644
--- a/Documentation/dev-bazel.txt
+++ b/Documentation/dev-bazel.txt
@@ -293,7 +293,7 @@
Debugging tests:
----
- bazel test --test_output=streamed --test_filter=com.gerrit.TestClass.testMethod testTarget
+ bazel test --test_output=streamed --test_filter=com.gerrit.TestClass.testMethod testTarget
----
Debug test example:
@@ -376,21 +376,25 @@
Note that Bazel currently does not show
link:https://github.com/bazelbuild/bazel/issues/3476[the skipped tests,role=external,window=_blank].
-[[debug]]
-=== Index Query Tests
+[[logging]]
+=== Controlling logging level
-The `DEBUG` log level can optionally be enabled for the index query tests. That log level applies to
-both Elasticsearch and Lucene tests.
+Per default, logging level is set to `INFO` level for all tests. The `DEBUG`
+log level can be enabled for the tests.
-In Eclipse, set `-Ddebug=true` as a VM argument under the Run Configuration's `Arguments` tab.
-
-With `bazel`, here is an example for the Lucene `account` test:
+In IDE, set `-Dgerrit.logLevel=debug` as a VM argument. With `bazel`, pass
+`GERRIT_LOG_LEVEL=debug` environment variable:
----
-bazel test --jvmopt='-Ddebug=true' \
-javatests/com/google/gerrit/server/query/account:lucene_query_test
+ bazel test --test_filter=com.gerrit.server.notedb.ChangeNotesTest \
+ --test_env=GERRIT_LOG_LEVEL=debug \
+ javatests/com/google/gerrit/server:server_tests
----
+The log results can be found in:
+`bazel-testlogs/javatests/com/google/gerrit/server/server_tests/test.log`.
+
+
== Dependencies
Dependency JARs are normally downloaded as needed, but you can
@@ -596,7 +600,6 @@
link:https://classic.yarnpkg.com/en/docs/cli/upgrade/[yarn upgrade doc,role=external,window=_blank].
-
[[RBE]]
== Google Remote Build Support
@@ -631,8 +634,6 @@
```
-
-
GERRIT
------
Part of link:index.html[Gerrit Code Review]
diff --git a/Documentation/intro-project-owner.txt b/Documentation/intro-project-owner.txt
index 7f1e82b..7f932da 100644
--- a/Documentation/intro-project-owner.txt
+++ b/Documentation/intro-project-owner.txt
@@ -587,13 +587,6 @@
Gerrit administrators may configure which of the commands are shown on
the change screen.
-- link:https://gerrit-review.googlesource.com/admin/repos/plugins/egit[
- egit,role=external,window=_blank] plugin:
-+
-The `egit` plugin provides the change ref as a download command, which is
-needed for downloading a change from within
-link:https://www.eclipse.org/egit/[EGit].
-
- link:https://gerrit-review.googlesource.com/admin/repos/plugins/project-download-commands[
project-download-commands,role=external,window=_blank] plugin:
+
@@ -760,7 +753,16 @@
Gerrit core does not support the renaming of projects.
-As workaround you can perform the following steps:
+If the link:https://gerrit-review.googlesource.com/admin/repos/plugins/rename-project[rename-project]
+plugin is installed, projects can be renamed using the
+link:https://gerrit.googlesource.com/plugins/rename-project/+/refs/heads/master/src/main/resources/Documentation/cmd-rename.md[rename-project]
+ssh command.
+
+Find details about prerequisites in the
+link:https://gerrit.googlesource.com/plugins/rename-project/+/refs/heads/master/src/main/resources/Documentation/about.md[plugin documentation].
+
+If you don't want to use the rename-project plugin you can perform the following steps as
+a workaround:
. link:#project-creation[Create a new project] with the new name.
. link:#import-history[Import the history of the old project].
@@ -769,11 +771,6 @@
Please note that a drawback of this workaround is that the whole review
history (changes, review comments) is lost.
-Alternatively, you can use the
-link:https://gerrit.googlesource.com/plugins/importer/[importer,role=external,window=_blank] plugin
-to copy the project _including the review history_, and then
-link:#project-deletion[delete the old project].
-
GERRIT
------
Part of link:index.html[Gerrit Code Review]
diff --git a/Documentation/metrics.txt b/Documentation/metrics.txt
index 41c241f..075de2b 100644
--- a/Documentation/metrics.txt
+++ b/Documentation/metrics.txt
@@ -67,6 +67,15 @@
==== Jetty
+* `http/server/jetty/connections/connections`: The current number of open connections
+* `http/server/jetty/connections/connections_total`: The total number of connections opened
+* `http/server/jetty/connections/connections_duration_max`: The max duration of a connection in ms
+* `http/server/jetty/connections/connections_duration_mean`: The mean duration of a connection in ms
+* `http/server/jetty/connections/connections_duration_stdev`: The standard deviation of the duration of a connection in ms
+* `http/server/jetty/connections/received_messages`: The total number of messages received
+* `http/server/jetty/connections/sent_messages`: The total number of messages sent
+* `http/server/jetty/connections/received_bytes`: Total number of bytes received by tracked connections
+* `http/server/jetty/connections/sent_bytes`: Total number of bytes sent by tracked connections"
* `http/server/jetty/threadpool/active_threads`: Active threads
* `http/server/jetty/threadpool/idle_threads`: Idle threads
* `http/server/jetty/threadpool/reserved_threads`: Reserved threads
@@ -137,6 +146,18 @@
* `jgit/block_cache/cache_used`: Bytes of memory retained in JGit block cache.
* `jgit/block_cache/open_files`: File handles held open by JGit block cache.
+* `avg_load_time` Average time to load a cache entry for JGit block cache.
+* `eviction_count` : Cache evictions for JGit block cache.
+* `eviction_ratio` : Cache eviction ratio for JGit block cache.
+* `hit_count` : Cache hits for JGit block cache.
+* `hit_ratio` : Cache hit ratio for JGit block cache.
+* `load_failure_count` : Failed cache loads for JGit block cache.
+* `load_failure_ratio` : Failed cache load ratio for JGit block cache.
+* `load_success_count` : Successful cache loads for JGit block cache.
+* `miss_count` : Cache misses for JGit block cache.
+* `miss_ratio` : Cache miss ratio for JGit block cache.
+* `cache_used_per_repository` : Bytes of memory retained per repository for the top N repositories
+having most data in the cache. The number N of reported repositories is limited to 1000.
=== Git
diff --git a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index ca105f6..cfee970 100644
--- a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -1282,7 +1282,7 @@
}
protected void assertNotifyCc(TestAccount expected) {
- assertNotifyCc(expected.getEmailAddress());
+ assertNotifyCc(expected.getNameEmail());
}
protected void assertNotifyCc(String expectedEmail, String expectedFullname) {
@@ -1302,7 +1302,7 @@
protected void assertNotifyBcc(TestAccount expected) {
assertThat(sender.getMessages()).hasSize(1);
Message m = sender.getMessages().get(0);
- assertThat(m.rcpt()).containsExactly(expected.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(expected.getNameEmail());
assertThat(m.headers().get("To").isEmpty()).isTrue();
assertThat(m.headers().get("Cc").isEmpty()).isTrue();
}
diff --git a/java/com/google/gerrit/acceptance/AbstractNotificationTest.java b/java/com/google/gerrit/acceptance/AbstractNotificationTest.java
index 088de23..a372089 100644
--- a/java/com/google/gerrit/acceptance/AbstractNotificationTest.java
+++ b/java/com/google/gerrit/acceptance/AbstractNotificationTest.java
@@ -319,6 +319,9 @@
}
protected class StagedUsers {
+ public static final String REVIEWER_BY_EMAIL = "reviewerByEmail@example.com";
+ public static final String CC_BY_EMAIL = "ccByEmail@example.com";
+
public final TestAccount owner;
public final TestAccount author;
public final TestAccount uploader;
@@ -327,8 +330,6 @@
public final TestAccount starrer;
public final TestAccount assignee;
public final TestAccount watchingProjectOwner;
- public final String reviewerByEmail = "reviewerByEmail@example.com";
- public final String ccerByEmail = "ccByEmail@example.com";
private final Map<NotifyType, TestAccount> watchers = new HashMap<>();
private final Map<String, TestAccount> accountsByEmail = new HashMap<>();
@@ -429,9 +430,9 @@
ReviewInput in =
ReviewInput.noScore()
.reviewer(reviewer.email())
- .reviewer(reviewerByEmail)
+ .reviewer(REVIEWER_BY_EMAIL)
.reviewer(ccer.email(), ReviewerState.CC, false)
- .reviewer(ccerByEmail, ReviewerState.CC, false);
+ .reviewer(CC_BY_EMAIL, ReviewerState.CC, false);
ReviewResult result = gApi.changes().id(r.getChangeId()).current().review(in);
supportReviewersByEmail = true;
if (result.reviewers.values().stream().anyMatch(v -> v.error != null)) {
diff --git a/java/com/google/gerrit/acceptance/BUILD b/java/com/google/gerrit/acceptance/BUILD
index 89d1f3d..541e479 100644
--- a/java/com/google/gerrit/acceptance/BUILD
+++ b/java/com/google/gerrit/acceptance/BUILD
@@ -48,8 +48,6 @@
"//lib/guice:guice-servlet",
"//lib/mail",
"//lib/mina:sshd",
- "//lib/log:impl-log4j",
- "//lib/log:log4j",
"//lib:guava",
"//lib/bouncycastle:bcpg",
"//lib/bouncycastle:bcprov",
diff --git a/java/com/google/gerrit/acceptance/GerritServer.java b/java/com/google/gerrit/acceptance/GerritServer.java
index 95afad7..b25dcc3 100644
--- a/java/com/google/gerrit/acceptance/GerritServer.java
+++ b/java/com/google/gerrit/acceptance/GerritServer.java
@@ -18,13 +18,11 @@
import static com.google.common.base.Preconditions.checkState;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static java.util.Objects.requireNonNull;
-import static org.apache.log4j.Logger.getLogger;
import com.google.auto.value.AutoValue;
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.gerrit.acceptance.config.ConfigAnnotationParser;
import com.google.gerrit.acceptance.config.GerritConfig;
import com.google.gerrit.acceptance.config.GerritConfigs;
@@ -55,6 +53,7 @@
import com.google.gerrit.testing.FakeEmailSender;
import com.google.gerrit.testing.InMemoryRepositoryManager;
import com.google.gerrit.testing.SshMode;
+import com.google.gerrit.testing.TestLoggingActivator;
import com.google.inject.AbstractModule;
import com.google.inject.BindingAnnotation;
import com.google.inject.Injector;
@@ -80,11 +79,6 @@
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
-import org.apache.log4j.ConsoleAppender;
-import org.apache.log4j.Level;
-import org.apache.log4j.LogManager;
-import org.apache.log4j.Logger;
-import org.apache.log4j.PatternLayout;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.RepositoryCache;
import org.eclipse.jgit.util.FS;
@@ -122,8 +116,7 @@
null, // @GerritConfig is only valid on methods.
null, // @GerritConfigs is only valid on methods.
null, // @GlobalPluginConfig is only valid on methods.
- null, // @GlobalPluginConfigs is only valid on methods.
- getLogLevelThresholdAnnotation(testDesc));
+ null); // @GlobalPluginConfigs is only valid on methods.
}
public static Description forTestMethod(
@@ -159,8 +152,7 @@
testDesc.getAnnotation(GerritConfig.class),
testDesc.getAnnotation(GerritConfigs.class),
testDesc.getAnnotation(GlobalPluginConfig.class),
- testDesc.getAnnotation(GlobalPluginConfigs.class),
- getLogLevelThresholdAnnotation(testDesc));
+ testDesc.getAnnotation(GlobalPluginConfigs.class));
}
private static boolean has(Class<? extends Annotation> annotation, Class<?> clazz) {
@@ -182,14 +174,6 @@
return null;
}
- private static Level getLogLevelThresholdAnnotation(org.junit.runner.Description testDesc) {
- LogThreshold logLevelThreshold = testDesc.getTestClass().getAnnotation(LogThreshold.class);
- if (logLevelThreshold == null) {
- return Level.DEBUG;
- }
- return Level.toLevel(logLevelThreshold.level());
- }
-
abstract org.junit.runner.Description testDescription();
@Nullable
@@ -229,8 +213,6 @@
@Nullable
abstract GlobalPluginConfigs pluginConfigs();
- abstract Level logLevelThreshold();
-
private void checkValidAnnotations() {
if (useClockStep() != null && useSystemTime()) {
throw new IllegalStateException("Use either @UseClockStep or @UseSystemTime, not both");
@@ -267,54 +249,6 @@
}
}
- private static final ImmutableMap<String, Level> LOG_LEVELS =
- ImmutableMap.<String, Level>builder()
- .put("com.google.gerrit", getGerritLogLevel())
-
- // Silence non-critical messages from MINA SSHD.
- .put("org.apache.mina", Level.WARN)
- .put("org.apache.sshd.common", Level.WARN)
- .put("org.apache.sshd.server", Level.WARN)
- .put("org.apache.sshd.common.keyprovider.FileKeyPairProvider", Level.INFO)
- .put("com.google.gerrit.sshd.GerritServerSession", Level.WARN)
-
- // Silence non-critical messages from mime-util.
- .put("eu.medsea.mimeutil", Level.WARN)
-
- // Silence non-critical messages from openid4java.
- .put("org.apache.xml", Level.WARN)
- .put("org.openid4java", Level.WARN)
- .put("org.openid4java.consumer.ConsumerManager", Level.FATAL)
- .put("org.openid4java.discovery.Discovery", Level.ERROR)
- .put("org.openid4java.server.RealmVerifier", Level.ERROR)
- .put("org.openid4java.message.AuthSuccess", Level.ERROR)
-
- // Silence non-critical messages from c3p0 (if used).
- .put("com.mchange.v2.c3p0", Level.WARN)
- .put("com.mchange.v2.resourcepool", Level.WARN)
- .put("com.mchange.v2.sql", Level.WARN)
-
- // Silence non-critical messages from apache.http.
- .put("org.apache.http", Level.WARN)
-
- // Silence non-critical messages from Jetty.
- .put("org.eclipse.jetty", Level.WARN)
-
- // Silence non-critical messages from JGit.
- .put("org.eclipse.jgit.transport.PacketLineIn", Level.WARN)
- .put("org.eclipse.jgit.transport.PacketLineOut", Level.WARN)
- .put("org.eclipse.jgit.internal.storage.file.FileSnapshot", Level.WARN)
- .put("org.eclipse.jgit.util.FS", Level.WARN)
- .build();
-
- private static Level getGerritLogLevel() {
- String value = Strings.nullToEmpty(System.getenv("GERRIT_LOG_LEVEL"));
- if (value.isEmpty()) {
- value = Strings.nullToEmpty(System.getProperty("gerrit.logLevel"));
- }
- return Level.toLevel(value, Level.INFO);
- }
-
private static boolean forceLocalDisk() {
String value = Strings.nullToEmpty(System.getenv("GERRIT_FORCE_LOCAL_DISK"));
if (value.isEmpty()) {
@@ -430,7 +364,7 @@
throws Exception {
checkArgument(site != null, "site is required (even for in-memory server");
desc.checkValidAnnotations();
- configureLogging(desc.logLevelThreshold());
+ TestLoggingActivator.configureLogging();
CyclicBarrier serverStarted = new CyclicBarrier(2);
Daemon daemon =
new Daemon(
@@ -531,25 +465,6 @@
return new GerritServer(desc, site, createTestInjector(daemon), daemon, daemonService);
}
- private static void configureLogging(Level threshold) {
- LogManager.resetConfiguration();
-
- PatternLayout layout = new PatternLayout();
- layout.setConversionPattern("%-5p %c %x: %m%n");
-
- ConsoleAppender dst = new ConsoleAppender();
- dst.setLayout(layout);
- dst.setTarget("System.err");
- dst.setThreshold(threshold);
- dst.activateOptions();
-
- Logger root = LogManager.getRootLogger();
- root.removeAllAppenders();
- root.addAppender(dst);
-
- LOG_LEVELS.entrySet().stream().forEach(e -> getLogger(e.getKey()).setLevel(e.getValue()));
- }
-
private static void mergeTestConfig(Config cfg) {
String forceEphemeralPort = String.format("%s:0", getLocalHost().getHostName());
String url = "http://" + forceEphemeralPort + "/";
diff --git a/java/com/google/gerrit/acceptance/LogThreshold.java b/java/com/google/gerrit/acceptance/LogThreshold.java
deleted file mode 100644
index 36831f3..0000000
--- a/java/com/google/gerrit/acceptance/LogThreshold.java
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (C) 2019 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.acceptance;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-@Target({TYPE, METHOD})
-@Retention(RUNTIME)
-@Inherited
-public @interface LogThreshold {
- String level() default "DEBUG";
-}
diff --git a/java/com/google/gerrit/acceptance/TestAccount.java b/java/com/google/gerrit/acceptance/TestAccount.java
index 07bb739..8b39c9e 100644
--- a/java/com/google/gerrit/acceptance/TestAccount.java
+++ b/java/com/google/gerrit/acceptance/TestAccount.java
@@ -79,7 +79,7 @@
.toString();
}
- public Address getEmailAddress() {
+ public Address getNameEmail() {
// Address is weird enough that it's safer and clearer to create a new instance in a
// non-abstract method rather than, say, having an abstract emailAddress() as part of this
// AutoValue class. Specifically:
diff --git a/java/com/google/gerrit/common/PageLinks.java b/java/com/google/gerrit/common/PageLinks.java
index 9f06364..38de5b1 100644
--- a/java/com/google/gerrit/common/PageLinks.java
+++ b/java/com/google/gerrit/common/PageLinks.java
@@ -90,16 +90,16 @@
return ADMIN_PROJECTS + p.get();
}
- public static String toProjectAcceess(Project.NameKey p) {
- return "/admin/projects/" + p.get() + ",access";
+ public static String toProjectAccess(Project.NameKey p) {
+ return ADMIN_PROJECTS + p.get() + ",access";
}
public static String toProjectBranches(Project.NameKey p) {
- return "/admin/projects/" + p.get() + ",branches";
+ return ADMIN_PROJECTS + p.get() + ",branches";
}
public static String toProjectTags(Project.NameKey p) {
- return "/admin/projects/" + p.get() + ",tags";
+ return ADMIN_PROJECTS + p.get() + ",tags";
}
public static String toAccountQuery(String fullname, Status status) {
diff --git a/java/com/google/gerrit/common/data/LabelType.java b/java/com/google/gerrit/common/data/LabelType.java
index 964cf67..3a68414 100644
--- a/java/com/google/gerrit/common/data/LabelType.java
+++ b/java/com/google/gerrit/common/data/LabelType.java
@@ -133,7 +133,7 @@
maxNegative = Short.MIN_VALUE;
maxPositive = Short.MAX_VALUE;
- if (values.size() > 0) {
+ if (!values.isEmpty()) {
if (values.get(0).getValue() < 0) {
maxNegative = values.get(0).getValue();
}
diff --git a/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java b/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
index 5f412ce..730af90 100644
--- a/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
+++ b/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
@@ -392,7 +392,7 @@
@Override
public ResultSet<V> read() {
- return readImpl((doc) -> AbstractElasticIndex.this.fromDocument(doc, opts.fields()));
+ return readImpl(doc -> AbstractElasticIndex.this.fromDocument(doc, opts.fields()));
}
@Override
diff --git a/java/com/google/gerrit/elasticsearch/builders/XContentBuilder.java b/java/com/google/gerrit/elasticsearch/builders/XContentBuilder.java
index 061a373..9c44583 100644
--- a/java/com/google/gerrit/elasticsearch/builders/XContentBuilder.java
+++ b/java/com/google/gerrit/elasticsearch/builders/XContentBuilder.java
@@ -14,6 +14,7 @@
package com.google.gerrit.elasticsearch.builders;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static java.time.format.DateTimeFormatter.ISO_INSTANT;
import com.fasterxml.jackson.core.JsonEncoding;
@@ -21,7 +22,6 @@
import com.fasterxml.jackson.core.JsonGenerator;
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;
import java.io.IOException;
@@ -139,7 +139,7 @@
public String string() {
close();
byte[] bytesArray = bos.toByteArray();
- return new String(bytesArray, Charsets.UTF_8);
+ return new String(bytesArray, UTF_8);
}
private void writeValue(Object value) throws IOException {
diff --git a/java/com/google/gerrit/entities/AttentionStatus.java b/java/com/google/gerrit/entities/AttentionStatus.java
new file mode 100644
index 0000000..c488ccd
--- /dev/null
+++ b/java/com/google/gerrit/entities/AttentionStatus.java
@@ -0,0 +1,72 @@
+// 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.entities;
+
+import com.google.auto.value.AutoValue;
+import com.google.gerrit.common.Nullable;
+import java.time.Instant;
+
+/**
+ * A single update to the attention set. To reconstruct the attention set these instances are parsed
+ * in reverse chronological order. Since each update contains all required information and
+ * invalidates all previous state (hence the name -Status rather than -Update), only the most recent
+ * record is relevant for each user.
+ *
+ * <p>See <a href="https://www.gerritcodereview.com/design-docs/attention-set.html">here</a> for
+ * details.
+ */
+@AutoValue
+public abstract class AttentionStatus {
+
+ /** Users can be added to or removed from the attention set. */
+ public enum Operation {
+ ADD,
+ REMOVE
+ }
+
+ /**
+ * The time at which this status was set. This is null for instances to be written because the
+ * timestamp in the commit message will be used.
+ */
+ @Nullable
+ public abstract Instant timestamp();
+
+ /** The user included in or excluded from the attention set. */
+ public abstract Account.Id account();
+
+ /** Indicates whether the user is added to or removed from the attention set. */
+ public abstract Operation operation();
+
+ /** A short human readable reason that explains this status (e.g. "manual"). */
+ public abstract String reason();
+
+ /**
+ * Create an instance from data read from NoteDB. This includes the timestamp taken from the
+ * commit.
+ */
+ public static AttentionStatus createFromRead(
+ Instant timestamp, Account.Id account, Operation operation, String reason) {
+ return new AutoValue_AttentionStatus(timestamp, account, operation, reason);
+ }
+
+ /**
+ * Create an instance to be written to NoteDB. This has no timestamp because the timestamp of the
+ * commit will be used.
+ */
+ public static AttentionStatus createForWrite(
+ Account.Id account, Operation operation, String reason) {
+ return new AutoValue_AttentionStatus(null, account, operation, reason);
+ }
+}
diff --git a/java/com/google/gerrit/extensions/api/accounts/Accounts.java b/java/com/google/gerrit/extensions/api/accounts/Accounts.java
index db7f506..15fca9a 100644
--- a/java/com/google/gerrit/extensions/api/accounts/Accounts.java
+++ b/java/com/google/gerrit/extensions/api/accounts/Accounts.java
@@ -21,6 +21,7 @@
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
+import java.util.Set;
public interface Accounts {
/**
@@ -138,7 +139,7 @@
private int limit;
private int start;
private boolean suggest;
- private EnumSet<ListAccountsOption> options = EnumSet.noneOf(ListAccountsOption.class);
+ private Set<ListAccountsOption> options = EnumSet.noneOf(ListAccountsOption.class);
/** Execute query and return a list of accounts. */
public abstract List<AccountInfo> get() throws RestApiException;
@@ -185,7 +186,7 @@
}
/** Set options on the request, replacing existing options. */
- public QueryRequest withOptions(EnumSet<ListAccountsOption> options) {
+ public QueryRequest withOptions(Set<ListAccountsOption> options) {
this.options = options;
return this;
}
@@ -206,7 +207,7 @@
return suggest;
}
- public EnumSet<ListAccountsOption> getOptions() {
+ public Set<ListAccountsOption> getOptions() {
return options;
}
}
diff --git a/java/com/google/gerrit/extensions/api/changes/ChangeEditApi.java b/java/com/google/gerrit/extensions/api/changes/ChangeEditApi.java
index 6bd4b73..a26068a 100644
--- a/java/com/google/gerrit/extensions/api/changes/ChangeEditApi.java
+++ b/java/com/google/gerrit/extensions/api/changes/ChangeEditApi.java
@@ -22,6 +22,7 @@
import com.google.gerrit.extensions.restapi.RestApiException;
import java.util.EnumSet;
import java.util.Optional;
+import java.util.Set;
/**
* An API for the change edit of a change. A change edit is similar to a patch set and will become
@@ -51,7 +52,7 @@
return base;
}
- public EnumSet<ChangeEditDetailOption> options() {
+ public Set<ChangeEditDetailOption> options() {
return options;
}
}
diff --git a/java/com/google/gerrit/extensions/api/changes/Changes.java b/java/com/google/gerrit/extensions/api/changes/Changes.java
index 8609207..d8741f5 100644
--- a/java/com/google/gerrit/extensions/api/changes/Changes.java
+++ b/java/com/google/gerrit/extensions/api/changes/Changes.java
@@ -24,6 +24,7 @@
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
+import java.util.Set;
public interface Changes {
/**
@@ -80,7 +81,7 @@
private int limit;
private int start;
private boolean isNoLimit;
- private EnumSet<ListChangesOption> options = EnumSet.noneOf(ListChangesOption.class);
+ private Set<ListChangesOption> options = EnumSet.noneOf(ListChangesOption.class);
private ListMultimap<String, String> pluginOptions = ArrayListMultimap.create();
public abstract List<ChangeInfo> get() throws RestApiException;
@@ -118,7 +119,7 @@
}
/** Set options on the request, replacing existing options. */
- public QueryRequest withOptions(EnumSet<ListChangesOption> options) {
+ public QueryRequest withOptions(Set<ListChangesOption> options) {
this.options = options;
return this;
}
@@ -151,7 +152,7 @@
return start;
}
- public EnumSet<ListChangesOption> getOptions() {
+ public Set<ListChangesOption> getOptions() {
return options;
}
diff --git a/java/com/google/gerrit/extensions/api/groups/Groups.java b/java/com/google/gerrit/extensions/api/groups/Groups.java
index 86c2d77..81b5f47 100644
--- a/java/com/google/gerrit/extensions/api/groups/Groups.java
+++ b/java/com/google/gerrit/extensions/api/groups/Groups.java
@@ -24,6 +24,7 @@
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
public interface Groups {
/**
@@ -166,7 +167,7 @@
return this;
}
- public EnumSet<ListGroupsOption> getOptions() {
+ public Set<ListGroupsOption> getOptions() {
return options;
}
@@ -224,7 +225,7 @@
private String query;
private int limit;
private int start;
- private EnumSet<ListGroupsOption> options = EnumSet.noneOf(ListGroupsOption.class);
+ private Set<ListGroupsOption> options = EnumSet.noneOf(ListGroupsOption.class);
/** Execute query and returns the matched groups as list. */
public abstract List<GroupInfo> get() throws RestApiException;
@@ -266,7 +267,7 @@
}
/** Set options on the request, replacing existing options. */
- public QueryRequest withOptions(EnumSet<ListGroupsOption> options) {
+ public QueryRequest withOptions(Set<ListGroupsOption> options) {
this.options = options;
return this;
}
@@ -283,7 +284,7 @@
return start;
}
- public EnumSet<ListGroupsOption> getOptions() {
+ public Set<ListGroupsOption> getOptions() {
return options;
}
}
diff --git a/java/com/google/gerrit/extensions/common/TestSubmitRuleInfo.java b/java/com/google/gerrit/extensions/common/TestSubmitRuleInfo.java
index bd7ebcb..4170797 100644
--- a/java/com/google/gerrit/extensions/common/TestSubmitRuleInfo.java
+++ b/java/com/google/gerrit/extensions/common/TestSubmitRuleInfo.java
@@ -32,7 +32,7 @@
public static class None {
private None() {}
- public static None INSTANCE = new None();
+ public static final None INSTANCE = new None();
}
@Override
diff --git a/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java b/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java
index b09dad0..dcfb614 100644
--- a/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java
+++ b/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java
@@ -192,7 +192,7 @@
// We might already have this account on file. Look for it.
//
try {
- return accountManager.lookup(aReq.getIdentity()) == null;
+ return !accountManager.lookup(aReq.getIdentity()).isPresent();
} catch (AccountException e) {
logger.atWarning().withCause(e).log("Cannot determine if user account exists");
return true;
@@ -333,7 +333,7 @@
areq.setEmailAddress(fetchRsp.getAttributeValue("Email"));
}
- if (openIdDomains != null && openIdDomains.size() > 0) {
+ if (openIdDomains != null && !openIdDomains.isEmpty()) {
// Administrator limited email domains, which can be used for OpenID.
// Login process will only work if the passed email matches one
// of these domains.
diff --git a/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java b/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java
index 2507163..4fabb18 100644
--- a/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java
+++ b/java/com/google/gerrit/httpd/gitweb/GitwebServlet.java
@@ -96,9 +96,9 @@
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final String PROJECT_LIST_ACTION = "project_list";
+ private static final int BUFFER_SIZE = 8192;
private final Set<String> deniedActions;
- private final int bufferSize = 8192;
private final Path gitwebCgi;
private final URI gitwebUrl;
private final LocalDiskRepositoryManager repoManager;
@@ -504,11 +504,11 @@
proc.getOutputStream().close();
}
- try (InputStream in = new BufferedInputStream(proc.getInputStream(), bufferSize)) {
+ try (InputStream in = new BufferedInputStream(proc.getInputStream(), BUFFER_SIZE)) {
readCgiHeaders(rsp, in);
try (OutputStream out = rsp.getOutputStream()) {
- final byte[] buf = new byte[bufferSize];
+ final byte[] buf = new byte[BUFFER_SIZE];
int n;
while ((n = in.read(buf)) > 0) {
out.write(buf, 0, n);
@@ -643,7 +643,7 @@
() -> {
try {
try {
- final byte[] buf = new byte[bufferSize];
+ final byte[] buf = new byte[BUFFER_SIZE];
int remaining = contentLength;
while (0 < remaining) {
final int max = Math.max(buf.length, remaining);
diff --git a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
index 4af7872..b32da89 100644
--- a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
+++ b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -1616,7 +1616,7 @@
for (String p : Splitter.on('/').split(path)) {
out.add(IdString.fromUrl(p));
}
- if (out.size() > 0 && out.get(out.size() - 1).isEmpty()) {
+ if (!out.isEmpty() && out.get(out.size() - 1).isEmpty()) {
out.remove(out.size() - 1);
}
return out;
diff --git a/java/com/google/gerrit/lucene/LuceneChangeIndex.java b/java/com/google/gerrit/lucene/LuceneChangeIndex.java
index 375967b..495c7e5 100644
--- a/java/com/google/gerrit/lucene/LuceneChangeIndex.java
+++ b/java/com/google/gerrit/lucene/LuceneChangeIndex.java
@@ -606,7 +606,7 @@
private void decodeReviewedBy(ListMultimap<String, IndexableField> doc, ChangeData cd) {
Collection<IndexableField> reviewedBy = doc.get(REVIEWEDBY_FIELD);
- if (reviewedBy.size() > 0) {
+ if (!reviewedBy.isEmpty()) {
Set<Account.Id> accounts = Sets.newHashSetWithExpectedSize(reviewedBy.size());
for (IndexableField r : reviewedBy) {
int id = r.numericValue().intValue();
diff --git a/java/com/google/gerrit/mail/Address.java b/java/com/google/gerrit/mail/Address.java
index 24ab353..455cc90 100644
--- a/java/com/google/gerrit/mail/Address.java
+++ b/java/com/google/gerrit/mail/Address.java
@@ -16,6 +16,7 @@
import com.google.gerrit.common.Nullable;
+/** Represents an address (name + email) in an email message. */
public class Address {
public static Address parse(String in) {
final int lt = in.indexOf('<');
diff --git a/java/com/google/gerrit/mail/RawMailParser.java b/java/com/google/gerrit/mail/RawMailParser.java
index b7e2030..9c89d19 100644
--- a/java/com/google/gerrit/mail/RawMailParser.java
+++ b/java/com/google/gerrit/mail/RawMailParser.java
@@ -69,7 +69,7 @@
}
// Add From, To and Cc
- if (mimeMessage.getFrom() != null && mimeMessage.getFrom().size() > 0) {
+ if (mimeMessage.getFrom() != null && !mimeMessage.getFrom().isEmpty()) {
Mailbox from = mimeMessage.getFrom().get(0);
messageBuilder.from(new Address(from.getName(), from.getAddress()));
}
diff --git a/java/com/google/gerrit/metrics/dropwizard/BUILD b/java/com/google/gerrit/metrics/dropwizard/BUILD
index 3079809..4b3859f 100644
--- a/java/com/google/gerrit/metrics/dropwizard/BUILD
+++ b/java/com/google/gerrit/metrics/dropwizard/BUILD
@@ -8,7 +8,6 @@
"//java/com/google/gerrit/common:annotations",
"//java/com/google/gerrit/extensions:api",
"//java/com/google/gerrit/metrics",
- "//java/com/google/gerrit/pgm/http/jetty",
"//java/com/google/gerrit/server",
"//lib:args4j",
"//lib:guava",
diff --git a/java/com/google/gerrit/metrics/dropwizard/BucketedCallback.java b/java/com/google/gerrit/metrics/dropwizard/BucketedCallback.java
index e33c242..68f8021 100644
--- a/java/com/google/gerrit/metrics/dropwizard/BucketedCallback.java
+++ b/java/com/google/gerrit/metrics/dropwizard/BucketedCallback.java
@@ -22,6 +22,7 @@
import com.google.gerrit.metrics.Description;
import com.google.gerrit.metrics.Field;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/** Abstract callback metric broken down into buckets. */
@@ -66,7 +67,13 @@
}
void doPrune() {
- cells.entrySet().removeIf(objectValueGaugeEntry -> !objectValueGaugeEntry.getValue().set);
+ Set<Map.Entry<Object, BucketedCallback<V>.ValueGauge>> entries = cells.entrySet();
+ for (Map.Entry<Object, ValueGauge> e : entries) {
+ if (!e.getValue().set) {
+ entries.remove(e);
+ registry.remove(submetric(e.getKey()));
+ }
+ }
}
void doEndSet() {
diff --git a/java/com/google/gerrit/metrics/proc/JGitMetricModule.java b/java/com/google/gerrit/metrics/proc/JGitMetricModule.java
index 3819786..62b2497 100644
--- a/java/com/google/gerrit/metrics/proc/JGitMetricModule.java
+++ b/java/com/google/gerrit/metrics/proc/JGitMetricModule.java
@@ -14,12 +14,18 @@
package com.google.gerrit.metrics.proc;
+import com.google.gerrit.metrics.CallbackMetric1;
import com.google.gerrit.metrics.Description;
import com.google.gerrit.metrics.Description.Units;
+import com.google.gerrit.metrics.Field;
import com.google.gerrit.metrics.MetricMaker;
+import com.google.gerrit.server.logging.Metadata;
+import java.util.Map;
import org.eclipse.jgit.storage.file.WindowCacheStats;
public class JGitMetricModule extends MetricModule {
+ private static final long MAX_REPO_COUNT = 1000;
+
@Override
protected void configure(MetricMaker metrics) {
metrics.newCallbackMetric(
@@ -28,12 +34,99 @@
new Description("Bytes of memory retained in JGit block cache.")
.setGauge()
.setUnit(Units.BYTES),
- () -> WindowCacheStats.getStats().getOpenByteCount());
+ WindowCacheStats.getStats()::getOpenByteCount);
metrics.newCallbackMetric(
"jgit/block_cache/open_files",
Long.class,
new Description("File handles held open by JGit block cache.").setGauge().setUnit("fds"),
- () -> WindowCacheStats.getStats().getOpenFileCount());
+ WindowCacheStats.getStats()::getOpenFileCount);
+
+ metrics.newCallbackMetric(
+ "jgit/block_cache/avg_load_time",
+ Double.class,
+ new Description("Average time to load a cache entry for JGit block cache.")
+ .setGauge()
+ .setUnit(Units.NANOSECONDS),
+ WindowCacheStats.getStats()::getAverageLoadTime);
+
+ metrics.newCallbackMetric(
+ "jgit/block_cache/eviction_count",
+ Long.class,
+ new Description("Cache evictions for JGit block cache.").setGauge(),
+ WindowCacheStats.getStats()::getEvictionCount);
+
+ metrics.newCallbackMetric(
+ "jgit/block_cache/eviction_ratio",
+ Double.class,
+ new Description("Cache eviction ratio for JGit block cache.").setGauge(),
+ WindowCacheStats.getStats()::getEvictionRatio);
+
+ metrics.newCallbackMetric(
+ "jgit/block_cache/hit_count",
+ Long.class,
+ new Description("Cache hits for JGit block cache.").setGauge(),
+ WindowCacheStats.getStats()::getHitCount);
+
+ metrics.newCallbackMetric(
+ "jgit/block_cache/hit_ratio",
+ Double.class,
+ new Description("Cache hit ratio for JGit block cache.").setGauge(),
+ WindowCacheStats.getStats()::getHitRatio);
+
+ metrics.newCallbackMetric(
+ "jgit/block_cache/load_failure_count",
+ Long.class,
+ new Description("Failed cache loads for JGit block cache.").setGauge(),
+ WindowCacheStats.getStats()::getLoadFailureCount);
+
+ metrics.newCallbackMetric(
+ "jgit/block_cache/load_failure_ratio",
+ Double.class,
+ new Description("Failed cache load ratio for JGit block cache.").setGauge(),
+ WindowCacheStats.getStats()::getLoadFailureRatio);
+
+ metrics.newCallbackMetric(
+ "jgit/block_cache/load_success_count",
+ Long.class,
+ new Description("Successfull cache loads for JGit block cache.").setGauge(),
+ WindowCacheStats.getStats()::getLoadSuccessCount);
+
+ metrics.newCallbackMetric(
+ "jgit/block_cache/miss_count",
+ Long.class,
+ new Description("Cache misses for JGit block cache.").setGauge(),
+ WindowCacheStats.getStats()::getMissCount);
+
+ metrics.newCallbackMetric(
+ "jgit/block_cache/miss_ratio",
+ Double.class,
+ new Description("Cache miss ratio for JGit block cache.").setGauge(),
+ WindowCacheStats.getStats()::getMissRatio);
+
+ CallbackMetric1<String, Long> repoEnt =
+ metrics.newCallbackMetric(
+ "jgit/block_cache/cache_used_per_repository",
+ Long.class,
+ new Description(
+ "Bytes of memory retained per repository for the top repositories "
+ + "having most data in the cache.")
+ .setGauge()
+ .setUnit("byte"),
+ Field.ofString("repository_name", Metadata.Builder::projectName).build());
+ metrics.newTrigger(
+ repoEnt,
+ () -> {
+ Map<String, Long> cacheMap = WindowCacheStats.getStats().getOpenByteCountPerRepository();
+ if (cacheMap.isEmpty()) {
+ repoEnt.forceCreate("");
+ } else {
+ cacheMap.entrySet().stream()
+ .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
+ .limit(MAX_REPO_COUNT)
+ .forEach(e -> repoEnt.set(e.getKey(), e.getValue()));
+ repoEnt.prune();
+ }
+ });
}
}
diff --git a/java/com/google/gerrit/pgm/BUILD b/java/com/google/gerrit/pgm/BUILD
index aa4df82..8b8f13c 100644
--- a/java/com/google/gerrit/pgm/BUILD
+++ b/java/com/google/gerrit/pgm/BUILD
@@ -22,6 +22,7 @@
"//java/com/google/gerrit/launcher",
"//java/com/google/gerrit/lifecycle",
"//java/com/google/gerrit/lucene",
+ "//java/com/google/gerrit/metrics",
"//java/com/google/gerrit/metrics/dropwizard",
"//java/com/google/gerrit/pgm/http/jetty",
"//java/com/google/gerrit/pgm/init",
diff --git a/java/com/google/gerrit/pgm/DeleteZombieDrafts.java b/java/com/google/gerrit/pgm/DeleteZombieDrafts.java
index 90a60c1..c08e999 100644
--- a/java/com/google/gerrit/pgm/DeleteZombieDrafts.java
+++ b/java/com/google/gerrit/pgm/DeleteZombieDrafts.java
@@ -14,6 +14,8 @@
package com.google.gerrit.pgm;
+import com.google.gerrit.metrics.DisabledMetricMaker;
+import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.pgm.init.api.ConsoleUI;
import com.google.gerrit.pgm.util.SiteProgram;
import com.google.gerrit.server.config.GerritServerConfigModule;
@@ -68,6 +70,7 @@
bind(String.class)
.annotatedWith(SecureStoreClassName.class)
.toProvider(Providers.of(getConfiguredSecureStoreClass()));
+ bind(MetricMaker.class).to(DisabledMetricMaker.class);
install(new FactoryModuleBuilder().build(DeleteZombieCommentsRefs.Factory.class));
}
});
diff --git a/java/com/google/gerrit/pgm/http/jetty/BUILD b/java/com/google/gerrit/pgm/http/jetty/BUILD
index 32247fb..cd188f5 100644
--- a/java/com/google/gerrit/pgm/http/jetty/BUILD
+++ b/java/com/google/gerrit/pgm/http/jetty/BUILD
@@ -13,6 +13,8 @@
"//java/com/google/gerrit/server/util/time",
"//java/com/google/gerrit/sshd",
"//java/com/google/gerrit/util/http",
+ "//java/com/google/gerrit/util/logging",
+ "//lib:gson",
"//lib:guava",
"//lib:jgit",
"//lib:servlet-api",
diff --git a/java/com/google/gerrit/pgm/http/jetty/HttpLog.java b/java/com/google/gerrit/pgm/http/jetty/HttpLog.java
index 809f7bc..4e4c93b 100644
--- a/java/com/google/gerrit/pgm/http/jetty/HttpLog.java
+++ b/java/com/google/gerrit/pgm/http/jetty/HttpLog.java
@@ -17,6 +17,7 @@
import com.google.common.base.Strings;
import com.google.gerrit.httpd.GetUserFilter;
import com.google.gerrit.httpd.restapi.LogRedactUtil;
+import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.util.SystemLog;
import com.google.gerrit.server.util.time.TimeUtil;
import com.google.inject.Inject;
@@ -28,11 +29,13 @@
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.eclipse.jgit.lib.Config;
/** Writes the {@code httpd_log} file with per-request data. */
class HttpLog extends AbstractLifeCycle implements RequestLog {
private static final Logger log = Logger.getLogger(HttpLog.class);
private static final String LOG_NAME = "httpd_log";
+ private static final String JSON_SUFFIX = ".json";
interface HttpLogFactory {
HttpLog get();
@@ -52,8 +55,20 @@
private final AsyncAppender async;
@Inject
- HttpLog(SystemLog systemLog) {
- async = systemLog.createAsyncAppender(LOG_NAME, new HttpLogLayout());
+ HttpLog(SystemLog systemLog, @GerritServerConfig Config config) {
+ boolean json = config.getBoolean("log", "jsonLogging", false);
+ boolean text = config.getBoolean("log", "textLogging", true) || !json;
+
+ async = new AsyncAppender();
+
+ if (text) {
+ async.addAppender(systemLog.createAsyncAppender(LOG_NAME, new HttpLogLayout()));
+ }
+
+ if (json) {
+ async.addAppender(
+ systemLog.createAsyncAppender(LOG_NAME + JSON_SUFFIX, new HttpLogJsonLayout()));
+ }
}
@Override
diff --git a/java/com/google/gerrit/pgm/http/jetty/HttpLogJsonLayout.java b/java/com/google/gerrit/pgm/http/jetty/HttpLogJsonLayout.java
new file mode 100644
index 0000000..73d9ee4
--- /dev/null
+++ b/java/com/google/gerrit/pgm/http/jetty/HttpLogJsonLayout.java
@@ -0,0 +1,72 @@
+// 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.pgm.http.jetty;
+
+import static com.google.gerrit.pgm.http.jetty.HttpLog.P_CONTENT_LENGTH;
+import static com.google.gerrit.pgm.http.jetty.HttpLog.P_HOST;
+import static com.google.gerrit.pgm.http.jetty.HttpLog.P_METHOD;
+import static com.google.gerrit.pgm.http.jetty.HttpLog.P_PROTOCOL;
+import static com.google.gerrit.pgm.http.jetty.HttpLog.P_REFERER;
+import static com.google.gerrit.pgm.http.jetty.HttpLog.P_RESOURCE;
+import static com.google.gerrit.pgm.http.jetty.HttpLog.P_STATUS;
+import static com.google.gerrit.pgm.http.jetty.HttpLog.P_USER;
+import static com.google.gerrit.pgm.http.jetty.HttpLog.P_USER_AGENT;
+
+import com.google.gerrit.util.logging.JsonLayout;
+import com.google.gerrit.util.logging.JsonLogEntry;
+import java.time.format.DateTimeFormatter;
+import org.apache.log4j.spi.LoggingEvent;
+
+public class HttpLogJsonLayout extends JsonLayout {
+
+ @Override
+ public DateTimeFormatter createDateTimeFormatter() {
+ return DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ss,SSS Z");
+ }
+
+ @Override
+ public JsonLogEntry toJsonLogEntry(LoggingEvent event) {
+ return new HttpJsonLogEntry(event);
+ }
+
+ @SuppressWarnings("unused")
+ private class HttpJsonLogEntry extends JsonLogEntry {
+ public String host;
+ public String thread;
+ public String user;
+ public String timestamp;
+ public String method;
+ public String resource;
+ public String protocol;
+ public String status;
+ public String contentLength;
+ public String referer;
+ public String userAgent;
+
+ public HttpJsonLogEntry(LoggingEvent event) {
+ this.host = getMdcString(event, P_HOST);
+ this.thread = event.getThreadName();
+ this.user = getMdcString(event, P_USER);
+ this.timestamp = formatDate(event.getTimeStamp());
+ this.method = getMdcString(event, P_METHOD);
+ this.resource = getMdcString(event, P_RESOURCE);
+ this.protocol = getMdcString(event, P_PROTOCOL);
+ this.status = getMdcString(event, P_STATUS);
+ this.contentLength = getMdcString(event, P_CONTENT_LENGTH);
+ this.referer = getMdcString(event, P_REFERER);
+ this.userAgent = getMdcString(event, P_USER_AGENT);
+ }
+ }
+}
diff --git a/java/com/google/gerrit/pgm/http/jetty/JettyMetrics.java b/java/com/google/gerrit/pgm/http/jetty/JettyMetrics.java
index b6a2d38..80edd45 100644
--- a/java/com/google/gerrit/pgm/http/jetty/JettyMetrics.java
+++ b/java/com/google/gerrit/pgm/http/jetty/JettyMetrics.java
@@ -17,6 +17,7 @@
import com.google.gerrit.metrics.CallbackMetric;
import com.google.gerrit.metrics.CallbackMetric0;
import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.Description.Units;
import com.google.gerrit.metrics.MetricMaker;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -45,27 +46,83 @@
metrics.newCallbackMetric(
"http/server/jetty/threadpool/idle_threads",
Integer.class,
- new Description("Idle threads").setGauge().setUnit("threads"));
+ new Description("Idle threads").setGauge());
CallbackMetric0<Integer> busyThreads =
metrics.newCallbackMetric(
"http/server/jetty/threadpool/active_threads",
Integer.class,
- new Description("Active threads").setGauge().setUnit("threads"));
+ new Description("Active threads").setGauge());
CallbackMetric0<Integer> reservedThreads =
metrics.newCallbackMetric(
"http/server/jetty/threadpool/reserved_threads",
Integer.class,
- new Description("Reserved threads").setGauge().setUnit("threads"));
+ new Description("Reserved threads").setGauge());
CallbackMetric0<Integer> queueSize =
metrics.newCallbackMetric(
"http/server/jetty/threadpool/queue_size",
Integer.class,
- new Description("Queued requests waiting for a thread").setGauge().setUnit("requests"));
+ new Description("Queued requests waiting for a thread").setGauge());
CallbackMetric0<Boolean> lowOnThreads =
metrics.newCallbackMetric(
"http/server/jetty/threadpool/is_low_on_threads",
Boolean.class,
new Description("Whether thread pool is low on threads").setGauge());
+ CallbackMetric0<Long> connections =
+ metrics.newCallbackMetric(
+ "http/server/jetty/connections/connections",
+ Long.class,
+ new Description("The current number of open connections").setGauge());
+ CallbackMetric0<Long> connectionsTotal =
+ metrics.newCallbackMetric(
+ "http/server/jetty/connections/connections_total",
+ Long.class,
+ new Description("The total number of connections opened").setGauge());
+ CallbackMetric0<Long> connectionDurationMax =
+ metrics.newCallbackMetric(
+ "http/server/jetty/connections/connections_duration_max",
+ Long.class,
+ new Description("The max duration of a connection")
+ .setGauge()
+ .setUnit(Units.MILLISECONDS));
+ CallbackMetric0<Double> connectionDurationMean =
+ metrics.newCallbackMetric(
+ "http/server/jetty/connections/connections_duration_mean",
+ Double.class,
+ new Description("The mean duration of a connection")
+ .setGauge()
+ .setUnit(Units.MILLISECONDS));
+ CallbackMetric0<Double> connectionDurationStDev =
+ metrics.newCallbackMetric(
+ "http/server/jetty/connections/connections_duration_stdev",
+ Double.class,
+ new Description("The standard deviation of the duration of a connection")
+ .setGauge()
+ .setUnit(Units.MILLISECONDS));
+ CallbackMetric0<Long> receivedMessages =
+ metrics.newCallbackMetric(
+ "http/server/jetty/connections/received_messages",
+ Long.class,
+ new Description("The total number of messages received").setGauge());
+ CallbackMetric0<Long> sentMessages =
+ metrics.newCallbackMetric(
+ "http/server/jetty/connections/sent_messages",
+ Long.class,
+ new Description("The total number of messages sent").setGauge());
+ CallbackMetric0<Long> receivedBytes =
+ metrics.newCallbackMetric(
+ "http/server/jetty/connections/received_bytes",
+ Long.class,
+ new Description("Total number of bytes received by tracked connections")
+ .setGauge()
+ .setUnit(Units.BYTES));
+ CallbackMetric0<Long> sentBytes =
+ metrics.newCallbackMetric(
+ "http/server/jetty/connections/sent_bytes",
+ Long.class,
+ new Description("Total number of bytes sent by tracked connections")
+ .setGauge()
+ .setUnit(Units.BYTES));
+
JettyServer.Metrics jettyMetrics = jetty.getMetrics();
metrics.newTrigger(
ImmutableSet.<CallbackMetric<?>>of(
@@ -76,7 +133,16 @@
maxPoolSize,
poolSize,
queueSize,
- lowOnThreads),
+ lowOnThreads,
+ connections,
+ connectionsTotal,
+ connectionDurationMax,
+ connectionDurationMean,
+ connectionDurationStDev,
+ receivedMessages,
+ sentMessages,
+ receivedBytes,
+ sentBytes),
() -> {
minPoolSize.set(jettyMetrics.getMinThreads());
maxPoolSize.set(jettyMetrics.getMaxThreads());
@@ -86,6 +152,15 @@
reservedThreads.set(jettyMetrics.getReservedThreads());
queueSize.set(jettyMetrics.getQueueSize());
lowOnThreads.set(jettyMetrics.isLowOnThreads());
+ connections.set(jettyMetrics.getConnections());
+ connectionsTotal.set(jettyMetrics.getConnectionsTotal());
+ connectionDurationMax.set(jettyMetrics.getConnectionDurationMax());
+ connectionDurationMean.set(jettyMetrics.getConnectionDurationMean());
+ connectionDurationStDev.set(jettyMetrics.getConnectionDurationStdDev());
+ receivedMessages.set(jettyMetrics.getReceivedMessages());
+ sentMessages.set(jettyMetrics.getSentMessages());
+ receivedBytes.set(jettyMetrics.getReceivedBytes());
+ sentBytes.set(jettyMetrics.getSentBytes());
});
}
}
diff --git a/java/com/google/gerrit/pgm/http/jetty/JettyServer.java b/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
index 5851fd0..b59dfc9 100644
--- a/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
+++ b/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
@@ -45,6 +45,7 @@
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.io.ConnectionStatistics;
import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.ForwardedRequestCustomizer;
@@ -118,9 +119,11 @@
static class Metrics {
private final QueuedThreadPool threadPool;
+ private ConnectionStatistics connStats;
- Metrics(QueuedThreadPool threadPool) {
+ Metrics(QueuedThreadPool threadPool, ConnectionStatistics connStats) {
this.threadPool = threadPool;
+ this.connStats = connStats;
}
public int getIdleThreads() {
@@ -154,12 +157,49 @@
public boolean isLowOnThreads() {
return threadPool.isLowOnThreads();
}
+
+ public long getConnections() {
+ return connStats.getConnections();
+ }
+
+ public long getConnectionsTotal() {
+ return connStats.getConnectionsTotal();
+ }
+
+ public long getConnectionDurationMax() {
+ return connStats.getConnectionDurationMax();
+ }
+
+ public double getConnectionDurationMean() {
+ return connStats.getConnectionDurationMean();
+ }
+
+ public double getConnectionDurationStdDev() {
+ return connStats.getConnectionDurationStdDev();
+ }
+
+ public long getReceivedMessages() {
+ return connStats.getReceivedMessages();
+ }
+
+ public long getSentMessages() {
+ return connStats.getSentMessages();
+ }
+
+ public long getReceivedBytes() {
+ return connStats.getReceivedBytes();
+ }
+
+ public long getSentBytes() {
+ return connStats.getSentBytes();
+ }
}
private final SitePaths site;
private final Server httpd;
private final Metrics metrics;
private boolean reverseProxy;
+ private ConnectionStatistics connStats;
@Inject
JettyServer(
@@ -173,7 +213,11 @@
QueuedThreadPool pool = threadPool(cfg, threadSettingsConfig);
httpd = new Server(pool);
httpd.setConnectors(listen(httpd, cfg));
- metrics = new Metrics(pool);
+ connStats = new ConnectionStatistics();
+ for (Connector connector : httpd.getConnectors()) {
+ connector.addBean(connStats);
+ }
+ metrics = new Metrics(pool, connStats);
Handler app = makeContext(env, cfg);
if (cfg.getBoolean("httpd", "requestLog", !reverseProxy)) {
diff --git a/java/com/google/gerrit/pgm/init/api/Section.java b/java/com/google/gerrit/pgm/init/api/Section.java
index cbf32a1..b5d35f4 100644
--- a/java/com/google/gerrit/pgm/init/api/Section.java
+++ b/java/com/google/gerrit/pgm/init/api/Section.java
@@ -69,7 +69,7 @@
all.addAll(Arrays.asList(flags.cfg.getStringList(section, subsection, name)));
if (value != null) {
- if (all.size() == 0 || all.size() == 1) {
+ if (all.isEmpty() || all.size() == 1) {
flags.cfg.setString(section, subsection, name, value);
} else {
all.set(0, value);
@@ -78,7 +78,7 @@
} else if (all.size() == 1) {
flags.cfg.unset(section, subsection, name);
- } else if (all.size() != 0) {
+ } else if (!all.isEmpty()) {
all.remove(0);
flags.cfg.setStringList(section, subsection, name, all);
}
diff --git a/java/com/google/gerrit/server/account/AccountManager.java b/java/com/google/gerrit/server/account/AccountManager.java
index 6a16a53..4fe9daa 100644
--- a/java/com/google/gerrit/server/account/AccountManager.java
+++ b/java/com/google/gerrit/server/account/AccountManager.java
@@ -462,8 +462,8 @@
}
if (filteredExtIdsByScheme.size() > 1
- || !filteredExtIdsByScheme.stream()
- .anyMatch(e -> e.key().equals(who.getExternalIdKey()))) {
+ || filteredExtIdsByScheme.stream()
+ .noneMatch(e -> e.key().equals(who.getExternalIdKey()))) {
u.deleteExternalIds(filteredExtIdsByScheme);
}
});
diff --git a/java/com/google/gerrit/server/account/AccountsConsistencyChecker.java b/java/com/google/gerrit/server/account/AccountsConsistencyChecker.java
index 19582da..db350c6 100644
--- a/java/com/google/gerrit/server/account/AccountsConsistencyChecker.java
+++ b/java/com/google/gerrit/server/account/AccountsConsistencyChecker.java
@@ -37,8 +37,8 @@
for (AccountState accountState : accounts.all()) {
Account account = accountState.account();
if (account.preferredEmail() != null) {
- if (!accountState.externalIds().stream()
- .anyMatch(e -> account.preferredEmail().equals(e.email()))) {
+ if (accountState.externalIds().stream()
+ .noneMatch(e -> account.preferredEmail().equals(e.email()))) {
addError(
String.format(
"Account '%s' has no external ID for its preferred email '%s'",
diff --git a/java/com/google/gerrit/server/args4j/ChangeIdHandler.java b/java/com/google/gerrit/server/args4j/ChangeIdHandler.java
index ddcd4db..448c654 100644
--- a/java/com/google/gerrit/server/args4j/ChangeIdHandler.java
+++ b/java/com/google/gerrit/server/args4j/ChangeIdHandler.java
@@ -17,6 +17,7 @@
import static com.google.gerrit.util.cli.Localizable.localizable;
import com.google.common.base.Splitter;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.Project;
@@ -35,34 +36,42 @@
import org.kohsuke.args4j.spi.Setter;
public class ChangeIdHandler extends OptionHandler<Change.Id> {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
private final Provider<InternalChangeQuery> queryProvider;
@Inject
public ChangeIdHandler(
// TODO(dborowitz): Not sure whether this is injectable here.
Provider<InternalChangeQuery> queryProvider,
- @Assisted final CmdLineParser parser,
- @Assisted final OptionDef option,
- @Assisted final Setter<Change.Id> setter) {
+ @Assisted CmdLineParser parser,
+ @Assisted OptionDef option,
+ @Assisted Setter<Change.Id> setter) {
super(parser, option, setter);
this.queryProvider = queryProvider;
}
@Override
public final int parseArguments(Parameters params) throws CmdLineException {
- final String token = params.getParameter(0);
- final List<String> tokens = Splitter.on(',').splitToList(token);
+ String token = params.getParameter(0);
+ List<String> tokens = Splitter.on(',').splitToList(token);
if (tokens.size() != 3) {
throw new CmdLineException(
owner, localizable("change should be specified as <project>,<branch>,<change-id>"));
}
try {
- final Change.Key key = Change.Key.parse(tokens.get(2));
- final Project.NameKey project = Project.nameKey(tokens.get(0));
- final BranchNameKey branch = BranchNameKey.create(project, tokens.get(1));
- for (ChangeData cd : queryProvider.get().byBranchKey(branch, key)) {
- setter.addValue(cd.getId());
+ Change.Key key = Change.Key.parse(tokens.get(2));
+ Project.NameKey project = Project.nameKey(tokens.get(0));
+ BranchNameKey branch = BranchNameKey.create(project, tokens.get(1));
+ List<ChangeData> changes = queryProvider.get().byBranchKey(branch, key);
+ if (!changes.isEmpty()) {
+ if (changes.size() > 1) {
+ String msg = "\"%s\": resolves to multiple changes";
+ logger.atSevere().log(msg, token);
+ throw new CmdLineException(owner, localizable(msg), token);
+ }
+ setter.addValue(changes.get(0).getId());
return 1;
}
} catch (IllegalArgumentException e) {
diff --git a/java/com/google/gerrit/server/cache/CacheMetrics.java b/java/com/google/gerrit/server/cache/CacheMetrics.java
index 1ef5a3b..5d30952 100644
--- a/java/com/google/gerrit/server/cache/CacheMetrics.java
+++ b/java/com/google/gerrit/server/cache/CacheMetrics.java
@@ -32,10 +32,11 @@
@Singleton
public class CacheMetrics {
+ private static final Field<String> F_NAME =
+ Field.ofString("cache_name", Metadata.Builder::cacheName).build();
+
@Inject
public CacheMetrics(MetricMaker metrics, DynamicMap<Cache<?, ?>> cacheMap) {
- Field<String> F_NAME = Field.ofString("cache_name", Metadata.Builder::cacheName).build();
-
CallbackMetric1<String, Long> memEnt =
metrics.newCallbackMetric(
"caches/memory_cached",
diff --git a/java/com/google/gerrit/server/config/ChangeCleanupConfig.java b/java/com/google/gerrit/server/config/ChangeCleanupConfig.java
index bd51fc7..cb4bff8 100644
--- a/java/com/google/gerrit/server/config/ChangeCleanupConfig.java
+++ b/java/com/google/gerrit/server/config/ChangeCleanupConfig.java
@@ -29,12 +29,12 @@
public class ChangeCleanupConfig {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private static String SECTION = "changeCleanup";
- private static String KEY_ABANDON_AFTER = "abandonAfter";
- private static String KEY_ABANDON_IF_MERGEABLE = "abandonIfMergeable";
- private static String KEY_ABANDON_MESSAGE = "abandonMessage";
- private static String KEY_CLEANUP_ACCOUNT_PATCH_REVIEW = "cleanupAccountPatchReview";
- private static String DEFAULT_ABANDON_MESSAGE =
+ private static final String SECTION = "changeCleanup";
+ private static final String KEY_ABANDON_AFTER = "abandonAfter";
+ private static final String KEY_ABANDON_IF_MERGEABLE = "abandonIfMergeable";
+ private static final String KEY_ABANDON_MESSAGE = "abandonMessage";
+ private static final String KEY_CLEANUP_ACCOUNT_PATCH_REVIEW = "cleanupAccountPatchReview";
+ private static final String DEFAULT_ABANDON_MESSAGE =
"Auto-Abandoned due to inactivity, see "
+ "${URL}\n"
+ "\n"
diff --git a/java/com/google/gerrit/server/config/TrackingFootersProvider.java b/java/com/google/gerrit/server/config/TrackingFootersProvider.java
index 2114b1a..1611da9 100644
--- a/java/com/google/gerrit/server/config/TrackingFootersProvider.java
+++ b/java/com/google/gerrit/server/config/TrackingFootersProvider.java
@@ -34,10 +34,10 @@
private static final int MAX_LENGTH = 10;
- private static String TRACKING_ID_TAG = "trackingid";
- private static String FOOTER_TAG = "footer";
- private static String SYSTEM_TAG = "system";
- private static String REGEX_TAG = "match";
+ private static final String TRACKING_ID_TAG = "trackingid";
+ private static final String FOOTER_TAG = "footer";
+ private static final String SYSTEM_TAG = "system";
+ private static final String REGEX_TAG = "match";
private final List<TrackingFooter> trackingFooters = new ArrayList<>();
@Inject
diff --git a/java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java b/java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java
index a15b429..59ae6f8 100644
--- a/java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java
+++ b/java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java
@@ -22,7 +22,6 @@
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
@@ -42,7 +41,7 @@
public class QueryDocumentationExecutor {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private static Map<String, Float> WEIGHTS =
+ private static final ImmutableMap<String, Float> WEIGHTS =
ImmutableMap.of(
Constants.TITLE_FIELD, 2.0f,
Constants.DOC_FIELD, 1.0f);
diff --git a/java/com/google/gerrit/server/events/StreamEventsApiListener.java b/java/com/google/gerrit/server/events/StreamEventsApiListener.java
index b040f38..18b6a5e 100644
--- a/java/com/google/gerrit/server/events/StreamEventsApiListener.java
+++ b/java/com/google/gerrit/server/events/StreamEventsApiListener.java
@@ -230,7 +230,7 @@
}
String[] hashtagArray(Collection<String> hashtags) {
- if (hashtags != null && hashtags.size() > 0) {
+ if (hashtags != null && !hashtags.isEmpty()) {
return Sets.newHashSet(hashtags).toArray(new String[hashtags.size()]);
}
return null;
diff --git a/java/com/google/gerrit/server/git/GroupCollector.java b/java/com/google/gerrit/server/git/GroupCollector.java
index 1f0dcd4..9e0f2ee 100644
--- a/java/com/google/gerrit/server/git/GroupCollector.java
+++ b/java/com/google/gerrit/server/git/GroupCollector.java
@@ -149,7 +149,7 @@
checkState(!done, "visit() called after getGroups()");
Set<RevCommit> interestingParents = getInterestingParents(c);
- if (interestingParents.size() == 0) {
+ if (interestingParents.isEmpty()) {
// All parents are uninteresting: treat this commit as the root of a new
// group of related changes.
groups.put(c, c.name());
diff --git a/java/com/google/gerrit/server/git/MergeUtil.java b/java/com/google/gerrit/server/git/MergeUtil.java
index 39fd103..89a2036 100644
--- a/java/com/google/gerrit/server/git/MergeUtil.java
+++ b/java/com/google/gerrit/server/git/MergeUtil.java
@@ -21,7 +21,6 @@
import static com.google.gerrit.git.ObjectIds.abbreviateName;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Comparator.naturalOrder;
-import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.joining;
import com.google.common.base.Strings;
@@ -44,8 +43,6 @@
import com.google.gerrit.exceptions.MergeWithConflictsNotSupportedException;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.registration.DynamicItem;
-import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.MergeConflictException;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
@@ -62,7 +59,6 @@
import com.google.gerrit.server.submit.IntegrationException;
import com.google.gerrit.server.submit.MergeIdenticalTreeException;
import com.google.gerrit.server.submit.MergeSorter;
-import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import java.io.IOException;
@@ -128,44 +124,6 @@
*/
private static final int NAME_ABBREV_LEN = 6;
- static class PluggableCommitMessageGenerator {
- private final DynamicSet<ChangeMessageModifier> changeMessageModifiers;
-
- @Inject
- PluggableCommitMessageGenerator(DynamicSet<ChangeMessageModifier> changeMessageModifiers) {
- this.changeMessageModifiers = changeMessageModifiers;
- }
-
- public String generate(
- RevCommit original, RevCommit mergeTip, BranchNameKey dest, String originalMessage) {
- requireNonNull(original.getRawBuffer());
- if (mergeTip != null) {
- requireNonNull(mergeTip.getRawBuffer());
- }
-
- int count = 0;
- String current = originalMessage;
- for (Extension<ChangeMessageModifier> ext : changeMessageModifiers.entries()) {
- ChangeMessageModifier changeMessageModifier = ext.get();
- String className = changeMessageModifier.getClass().getName();
- current = changeMessageModifier.onSubmit(current, original, mergeTip, dest);
- checkState(
- current != null,
- "%s.onSubmit from plugin %s returned null instead of new commit message",
- className,
- ext.getPluginName());
- count++;
- logger.atFine().log(
- "Invoked %s from plugin %s, message length now %d",
- className, ext.getPluginName(), current.length());
- }
- logger.atFine().log(
- "Invoked %d ChangeMessageModifiers on message with original length %d",
- count, originalMessage.length());
- return current;
- }
- }
-
private static final String R_HEADS_MASTER = Constants.R_HEADS + Constants.MASTER;
public static boolean useRecursiveMerge(Config cfg) {
@@ -432,7 +390,33 @@
RevCommit originalCommit,
String mergeStrategy,
boolean allowConflicts,
- PersonIdent committerIndent,
+ PersonIdent committerIdent,
+ String commitMsg,
+ CodeReviewRevWalk rw)
+ throws IOException, MergeIdenticalTreeException, MergeConflictException,
+ InvalidMergeStrategyException {
+ return createMergeCommit(
+ inserter,
+ repoConfig,
+ mergeTip,
+ originalCommit,
+ mergeStrategy,
+ allowConflicts,
+ committerIdent,
+ committerIdent,
+ commitMsg,
+ rw);
+ }
+
+ public static CodeReviewCommit createMergeCommit(
+ ObjectInserter inserter,
+ Config repoConfig,
+ RevCommit mergeTip,
+ RevCommit originalCommit,
+ String mergeStrategy,
+ boolean allowConflicts,
+ PersonIdent authorIdent,
+ PersonIdent committerIdent,
String commitMsg,
CodeReviewRevWalk rw)
throws IOException, MergeIdenticalTreeException, MergeConflictException,
@@ -496,8 +480,8 @@
CommitBuilder mergeCommit = new CommitBuilder();
mergeCommit.setTreeId(tree);
mergeCommit.setParentIds(mergeTip, originalCommit);
- mergeCommit.setAuthor(committerIndent);
- mergeCommit.setCommitter(committerIndent);
+ mergeCommit.setAuthor(authorIdent);
+ mergeCommit.setCommitter(committerIdent);
mergeCommit.setMessage(commitMsg);
CodeReviewCommit commit = rw.parseCommit(inserter.insert(mergeCommit));
commit.setFilesWithGitConflicts(filesWithGitConflicts);
diff --git a/java/com/google/gerrit/server/git/NotifyConfig.java b/java/com/google/gerrit/server/git/NotifyConfig.java
index 2ca2744a..429f15a 100644
--- a/java/com/google/gerrit/server/git/NotifyConfig.java
+++ b/java/com/google/gerrit/server/git/NotifyConfig.java
@@ -50,11 +50,11 @@
return types.contains(type) || types.contains(NotifyType.ALL);
}
- public EnumSet<NotifyType> getNotify() {
+ public Set<NotifyType> getNotify() {
return types;
}
- public void setTypes(EnumSet<NotifyType> newTypes) {
+ public void setTypes(Set<NotifyType> newTypes) {
types = EnumSet.copyOf(newTypes);
}
diff --git a/java/com/google/gerrit/server/git/PluggableCommitMessageGenerator.java b/java/com/google/gerrit/server/git/PluggableCommitMessageGenerator.java
new file mode 100644
index 0000000..804a218
--- /dev/null
+++ b/java/com/google/gerrit/server/git/PluggableCommitMessageGenerator.java
@@ -0,0 +1,71 @@
+// 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.server.git;
+
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.entities.BranchNameKey;
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.registration.Extension;
+import com.google.inject.Inject;
+import org.eclipse.jgit.revwalk.RevCommit;
+
+/** Helper to call plugins that want to change the commit message before a change is merged. */
+public class PluggableCommitMessageGenerator {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ private final DynamicSet<ChangeMessageModifier> changeMessageModifiers;
+
+ @Inject
+ PluggableCommitMessageGenerator(DynamicSet<ChangeMessageModifier> changeMessageModifiers) {
+ this.changeMessageModifiers = changeMessageModifiers;
+ }
+
+ /**
+ * Returns the commit message as modified by plugins. The returned message can be equal to {@code
+ * originalMessage} in case no plugins are registered or the registered plugins decided not to
+ * modify the message.
+ */
+ public String generate(
+ RevCommit original, RevCommit mergeTip, BranchNameKey dest, String originalMessage) {
+ requireNonNull(original.getRawBuffer());
+ if (mergeTip != null) {
+ requireNonNull(mergeTip.getRawBuffer());
+ }
+
+ int count = 0;
+ String current = originalMessage;
+ for (Extension<ChangeMessageModifier> ext : changeMessageModifiers.entries()) {
+ ChangeMessageModifier changeMessageModifier = ext.get();
+ String className = changeMessageModifier.getClass().getName();
+ current = changeMessageModifier.onSubmit(current, original, mergeTip, dest);
+ checkState(
+ current != null,
+ "%s.onSubmit from plugin %s returned null instead of new commit message",
+ className,
+ ext.getPluginName());
+ count++;
+ logger.atFine().log(
+ "Invoked %s from plugin %s, message length now %d",
+ className, ext.getPluginName(), current.length());
+ }
+ logger.atFine().log(
+ "Invoked %d ChangeMessageModifiers on message with original length %d",
+ count, originalMessage.length());
+ return current;
+ }
+}
diff --git a/java/com/google/gerrit/server/git/meta/TabFile.java b/java/com/google/gerrit/server/git/meta/TabFile.java
index f5d7037..c9a8e77 100644
--- a/java/com/google/gerrit/server/git/meta/TabFile.java
+++ b/java/com/google/gerrit/server/git/meta/TabFile.java
@@ -34,7 +34,7 @@
String parse(String str);
}
- public static Parser TRIM = String::trim;
+ public static final Parser TRIM = String::trim;
protected static class Row {
public String left;
diff --git a/java/com/google/gerrit/server/git/meta/VersionedMetaData.java b/java/com/google/gerrit/server/git/meta/VersionedMetaData.java
index 38c8d7d..8ab2779 100644
--- a/java/com/google/gerrit/server/git/meta/VersionedMetaData.java
+++ b/java/com/google/gerrit/server/git/meta/VersionedMetaData.java
@@ -412,7 +412,7 @@
// read the subject line and use it as reflog message
ru.setRefLogMessage("commit: " + reader.readLine(), true);
}
- logger.atFine().log("Saving commit: " + message);
+ logger.atFine().log("Saving commit '%s' on project '%s'", message.trim(), projectName);
inserter.flush();
RefUpdate.Result result = ru.update();
switch (result) {
@@ -420,6 +420,9 @@
case FAST_FORWARD:
revision = rw.parseCommit(ru.getNewObjectId());
update.fireGitRefUpdatedEvent(ru);
+ logger.atFine().log(
+ "Saved commit '%s' as revision '%s' on project '%s'",
+ message.trim(), revision.name(), projectName);
return revision;
case LOCK_FAILURE:
throw new LockFailureException(errorMsg(ru, db.getDirectory()), ru);
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index 4b6a4cd..3013b02 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -2267,7 +2267,7 @@
return Collections.emptyList();
}
- if (changes.size() == 0) {
+ if (changes.isEmpty()) {
if (!isValidChangeId(p.changeKey.get())) {
reject(magicBranch.cmd, "invalid Change-Id");
return Collections.emptyList();
diff --git a/java/com/google/gerrit/server/index/change/ChangeIndexRewriter.java b/java/com/google/gerrit/server/index/change/ChangeIndexRewriter.java
index 7e1353c..63c5297 100644
--- a/java/com/google/gerrit/server/index/change/ChangeIndexRewriter.java
+++ b/java/com/google/gerrit/server/index/change/ChangeIndexRewriter.java
@@ -78,7 +78,7 @@
* @return the maximal set of statuses that any changes matching the input predicates may have,
* based on examining boolean and {@link ChangeStatusPredicate}s.
*/
- public static EnumSet<Change.Status> getPossibleStatus(Predicate<ChangeData> in) {
+ public static Set<Change.Status> getPossibleStatus(Predicate<ChangeData> in) {
EnumSet<Change.Status> s = extractStatus(in);
return s != null ? s : EnumSet.allOf(Change.Status.class);
}
diff --git a/java/com/google/gerrit/server/logging/BUILD b/java/com/google/gerrit/server/logging/BUILD
index 2c2341f..7af34f7 100644
--- a/java/com/google/gerrit/server/logging/BUILD
+++ b/java/com/google/gerrit/server/logging/BUILD
@@ -10,11 +10,13 @@
"//java/com/google/gerrit/common:annotations",
"//java/com/google/gerrit/extensions:api",
"//java/com/google/gerrit/server/util/time",
+ "//lib:gson",
"//lib:guava",
"//lib:jgit",
"//lib/auto:auto-value",
"//lib/auto:auto-value-annotations",
"//lib/flogger:api",
"//lib/guice",
+ "//lib/log:log4j",
],
)
diff --git a/java/com/google/gerrit/server/mail/send/ProjectWatch.java b/java/com/google/gerrit/server/mail/send/ProjectWatch.java
index be36f55..d2fa69c 100644
--- a/java/com/google/gerrit/server/mail/send/ProjectWatch.java
+++ b/java/com/google/gerrit/server/mail/send/ProjectWatch.java
@@ -244,7 +244,7 @@
qb = args.queryBuilder.get().asUser(args.anonymousUser.get());
} else {
qb = args.queryBuilder.get().asUser(user);
- p = qb.is_visible();
+ p = qb.isVisible();
}
if (filter != null) {
diff --git a/java/com/google/gerrit/server/notedb/AbstractChangeUpdate.java b/java/com/google/gerrit/server/notedb/AbstractChangeUpdate.java
index d301d34..7136d2b 100644
--- a/java/com/google/gerrit/server/notedb/AbstractChangeUpdate.java
+++ b/java/com/google/gerrit/server/notedb/AbstractChangeUpdate.java
@@ -110,7 +110,7 @@
ChangeNoteUtil noteUtil, PersonIdent serverIdent, CurrentUser u, Date when) {
checkUserType(u);
if (u instanceof IdentifiedUser) {
- return noteUtil.newIdent(u.asIdentifiedUser().getAccount(), when, serverIdent);
+ return noteUtil.newIdent(u.asIdentifiedUser().getAccount().id(), when, serverIdent);
} else if (u instanceof InternalUser) {
return serverIdent;
}
@@ -164,10 +164,6 @@
return accountId;
}
- protected PersonIdent newIdent(Account.Id authorId, Date when) {
- return noteUtil.newIdent(authorId, when, serverIdent);
- }
-
/** Whether no updates have been done. */
public abstract boolean isEmpty();
@@ -184,6 +180,14 @@
protected abstract String getRefName();
+ protected void setParentCommit(CommitBuilder cb, ObjectId parentCommitId) {
+ if (!parentCommitId.equals(ObjectId.zeroId())) {
+ cb.setParentId(parentCommitId);
+ } else {
+ cb.setParentIds(); // Ref is currently nonexistent, commit has no parents.
+ }
+ }
+
/**
* Whether to allow bypassing the check that an update does not exceed the max update count on an
* object.
@@ -224,11 +228,7 @@
}
cb.setAuthor(authorIdent);
cb.setCommitter(new PersonIdent(serverIdent, when));
- if (!curr.equals(z)) {
- cb.setParentId(curr);
- } else {
- cb.setParentIds(); // Ref is currently nonexistent, commit has no parents.
- }
+ setParentCommit(cb, curr);
if (cb.getTreeId() == null) {
if (curr.equals(z)) {
cb.setTreeId(emptyTree(ins)); // No parent, assume empty tree.
diff --git a/java/com/google/gerrit/server/notedb/ChangeDraftUpdate.java b/java/com/google/gerrit/server/notedb/ChangeDraftUpdate.java
index 72a460c..4b538f3 100644
--- a/java/com/google/gerrit/server/notedb/ChangeDraftUpdate.java
+++ b/java/com/google/gerrit/server/notedb/ChangeDraftUpdate.java
@@ -289,6 +289,11 @@
}
@Override
+ protected void setParentCommit(CommitBuilder cb, ObjectId parentCommitId) {
+ cb.setParentIds(); // Draft updates should not keep history of parent commits
+ }
+
+ @Override
public boolean isEmpty() {
return delete.isEmpty() && put.isEmpty();
}
diff --git a/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java b/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java
index cebb67d..287f3e7 100644
--- a/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java
+++ b/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java
@@ -15,10 +15,13 @@
package com.google.gerrit.server.notedb;
import com.google.auto.value.AutoValue;
-import com.google.common.annotations.VisibleForTesting;
import com.google.gerrit.entities.Account;
+import com.google.gerrit.entities.AttentionStatus;
+import com.google.gerrit.json.OutputFormat;
import com.google.gerrit.server.config.GerritServerId;
+import com.google.gson.Gson;
import com.google.inject.Inject;
+import java.time.Instant;
import java.util.Date;
import java.util.Optional;
import org.eclipse.jgit.lib.PersonIdent;
@@ -27,42 +30,31 @@
import org.eclipse.jgit.util.RawParseUtils;
public class ChangeNoteUtil {
- public static final FooterKey FOOTER_ASSIGNEE = new FooterKey("Assignee");
- public static final FooterKey FOOTER_BRANCH = new FooterKey("Branch");
- public static final FooterKey FOOTER_CHANGE_ID = new FooterKey("Change-id");
- public static final FooterKey FOOTER_COMMIT = new FooterKey("Commit");
- public static final FooterKey FOOTER_CURRENT = new FooterKey("Current");
- public static final FooterKey FOOTER_GROUPS = new FooterKey("Groups");
- public static final FooterKey FOOTER_HASHTAGS = new FooterKey("Hashtags");
- public static final FooterKey FOOTER_LABEL = new FooterKey("Label");
- public static final FooterKey FOOTER_PATCH_SET = new FooterKey("Patch-set");
- public static final FooterKey FOOTER_PATCH_SET_DESCRIPTION =
- new FooterKey("Patch-set-description");
- public static final FooterKey FOOTER_PRIVATE = new FooterKey("Private");
- public static final FooterKey FOOTER_REAL_USER = new FooterKey("Real-user");
- public static final FooterKey FOOTER_STATUS = new FooterKey("Status");
- public static final FooterKey FOOTER_SUBJECT = new FooterKey("Subject");
- public static final FooterKey FOOTER_SUBMISSION_ID = new FooterKey("Submission-id");
- public static final FooterKey FOOTER_SUBMITTED_WITH = new FooterKey("Submitted-with");
- public static final FooterKey FOOTER_TOPIC = new FooterKey("Topic");
- public static final FooterKey FOOTER_TAG = new FooterKey("Tag");
- public static final FooterKey FOOTER_WORK_IN_PROGRESS = new FooterKey("Work-in-progress");
- public static final FooterKey FOOTER_REVERT_OF = new FooterKey("Revert-of");
- public static final FooterKey FOOTER_CHERRY_PICK_OF = new FooterKey("Cherry-pick-of");
- static final String AUTHOR = "Author";
- static final String BASE_PATCH_SET = "Base-for-patch-set";
- static final String COMMENT_RANGE = "Comment-range";
- static final String FILE = "File";
- static final String LENGTH = "Bytes";
- static final String PARENT = "Parent";
- static final String PARENT_NUMBER = "Parent-number";
- static final String PATCH_SET = "Patch-set";
- static final String REAL_AUTHOR = "Real-author";
- static final String REVISION = "Revision";
- static final String UUID = "UUID";
- static final String UNRESOLVED = "Unresolved";
- static final String TAG = FOOTER_TAG.getName();
+ static final FooterKey FOOTER_ATTENTION = new FooterKey("Attention");
+ static final FooterKey FOOTER_ASSIGNEE = new FooterKey("Assignee");
+ static final FooterKey FOOTER_BRANCH = new FooterKey("Branch");
+ static final FooterKey FOOTER_CHANGE_ID = new FooterKey("Change-id");
+ static final FooterKey FOOTER_COMMIT = new FooterKey("Commit");
+ static final FooterKey FOOTER_CURRENT = new FooterKey("Current");
+ static final FooterKey FOOTER_GROUPS = new FooterKey("Groups");
+ static final FooterKey FOOTER_HASHTAGS = new FooterKey("Hashtags");
+ static final FooterKey FOOTER_LABEL = new FooterKey("Label");
+ static final FooterKey FOOTER_PATCH_SET = new FooterKey("Patch-set");
+ static final FooterKey FOOTER_PATCH_SET_DESCRIPTION = new FooterKey("Patch-set-description");
+ static final FooterKey FOOTER_PRIVATE = new FooterKey("Private");
+ static final FooterKey FOOTER_REAL_USER = new FooterKey("Real-user");
+ static final FooterKey FOOTER_STATUS = new FooterKey("Status");
+ static final FooterKey FOOTER_SUBJECT = new FooterKey("Subject");
+ static final FooterKey FOOTER_SUBMISSION_ID = new FooterKey("Submission-id");
+ static final FooterKey FOOTER_SUBMITTED_WITH = new FooterKey("Submitted-with");
+ static final FooterKey FOOTER_TOPIC = new FooterKey("Topic");
+ static final FooterKey FOOTER_TAG = new FooterKey("Tag");
+ static final FooterKey FOOTER_WORK_IN_PROGRESS = new FooterKey("Work-in-progress");
+ static final FooterKey FOOTER_REVERT_OF = new FooterKey("Revert-of");
+ static final FooterKey FOOTER_CHERRY_PICK_OF = new FooterKey("Cherry-pick-of");
+
+ private static final Gson gson = OutputFormat.JSON_COMPACT.newGson();
private final ChangeNoteJson changeNoteJson;
private final String serverId;
@@ -77,21 +69,17 @@
return changeNoteJson;
}
- public PersonIdent newIdent(Account.Id authorId, Date when, PersonIdent serverIdent) {
+ public PersonIdent newIdent(Account.Id accountId, Date when, PersonIdent serverIdent) {
return new PersonIdent(
- "Gerrit User " + authorId.toString(),
- authorId.get() + "@" + serverId,
- when,
- serverIdent.getTimeZone());
+ getUsername(accountId), getEmailAddress(accountId), when, serverIdent.getTimeZone());
}
- @VisibleForTesting
- public PersonIdent newIdent(Account author, Date when, PersonIdent serverIdent) {
- return new PersonIdent(
- "Gerrit User " + author.id(),
- author.id().get() + "@" + serverId,
- when,
- serverIdent.getTimeZone());
+ private static String getUsername(Account.Id accountId) {
+ return "Gerrit User " + accountId.toString();
+ }
+
+ private String getEmailAddress(Account.Id accountId) {
+ return accountId.get() + "@" + serverId;
}
public static Optional<CommitMessageRange> parseCommitMessageRange(RevCommit commit) {
@@ -151,6 +139,7 @@
@AutoValue
public abstract static class CommitMessageRange {
+
public abstract int subjectStart();
public abstract int subjectEnd();
@@ -165,6 +154,7 @@
@AutoValue.Builder
public abstract static class Builder {
+
abstract Builder subjectStart(int subjectStart);
abstract Builder subjectEnd(int subjectEnd);
@@ -176,4 +166,51 @@
abstract CommitMessageRange build();
}
}
+
+ /** Helper class for JSON serialization. Timestamp is taken from the commit. */
+ private static class AttentionStatusInNoteDb {
+
+ final String personIdent;
+ final AttentionStatus.Operation operation;
+ final String reason;
+
+ AttentionStatusInNoteDb(
+ String personIndent, AttentionStatus.Operation operation, String reason) {
+ this.personIdent = personIndent;
+ this.operation = operation;
+ this.reason = reason;
+ }
+ }
+
+ /** The returned {@link Optional} holds the parsed entity or is empty if parsing failed. */
+ static Optional<AttentionStatus> attentionStatusFromJson(
+ Instant timestamp, String attentionString) {
+ AttentionStatusInNoteDb inNoteDb =
+ gson.fromJson(attentionString, AttentionStatusInNoteDb.class);
+ PersonIdent personIdent = RawParseUtils.parsePersonIdent(inNoteDb.personIdent);
+ if (personIdent == null) {
+ return Optional.empty();
+ }
+ Optional<Account.Id> account = NoteDbUtil.parseIdent(personIdent);
+ return account.map(
+ id -> AttentionStatus.createFromRead(timestamp, id, inNoteDb.operation, inNoteDb.reason));
+ }
+
+ String attentionStatusToJson(AttentionStatus attentionStatus) {
+ PersonIdent personIdent =
+ new PersonIdent(
+ getUsername(attentionStatus.account()), getEmailAddress(attentionStatus.account()));
+ StringBuilder stringBuilder = new StringBuilder();
+ appendIdentString(stringBuilder, personIdent.getName(), personIdent.getEmailAddress());
+ return gson.toJson(
+ new AttentionStatusInNoteDb(
+ stringBuilder.toString(), attentionStatus.operation(), attentionStatus.reason()));
+ }
+
+ static void appendIdentString(StringBuilder stringBuilder, String name, String emailAddress) {
+ PersonIdent.appendSanitized(stringBuilder, name);
+ stringBuilder.append(" <");
+ PersonIdent.appendSanitized(stringBuilder, emailAddress);
+ stringBuilder.append('>');
+ }
}
diff --git a/java/com/google/gerrit/server/notedb/ChangeNotes.java b/java/com/google/gerrit/server/notedb/ChangeNotes.java
index 8cf0046..2de2195 100644
--- a/java/com/google/gerrit/server/notedb/ChangeNotes.java
+++ b/java/com/google/gerrit/server/notedb/ChangeNotes.java
@@ -40,6 +40,7 @@
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.entities.Account;
+import com.google.gerrit.entities.AttentionStatus;
import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.ChangeMessage;
@@ -211,6 +212,7 @@
return sr.all().stream().map(id -> scanOneChange(project, sr, id)).filter(Objects::nonNull);
}
+ @Nullable
private ChangeNotesResult scanOneChange(Project.NameKey project, ScanResult sr, Change.Id id) {
if (!sr.fromMetaRefs().contains(id)) {
// Stray patch set refs can happen due to normal error conditions, e.g. failed
@@ -219,10 +221,15 @@
}
// TODO(dborowitz): See discussion in BatchUpdate#newChangeContext.
- Change change = ChangeNotes.Factory.newChange(project, id);
-
- logger.atFine().log("adding change %s found in project %s", id, project);
- return toResult(change);
+ try {
+ Change change = ChangeNotes.Factory.newChange(project, id);
+ logger.atFine().log("adding change %s found in project %s", id, project);
+ return toResult(change);
+ } catch (InvalidServerIdException ise) {
+ logger.atWarning().withCause(ise).log(
+ "skipping change %d in project %s because of an invalid server id", id.get(), project);
+ return null;
+ }
}
@Nullable
@@ -369,6 +376,10 @@
return state.reviewerUpdates();
}
+ public ImmutableList<AttentionStatus> getAttentionUpdates() {
+ return state.attentionUpdates();
+ }
+
/**
* @return an ImmutableSet of Account.Ids of all users that have been assigned to this change. The
* order of the set is the order in which they were assigned.
@@ -531,9 +542,9 @@
* be to bump the cache version, but that would invalidate all persistent cache entries, what we
* rather try to avoid.
*/
- checkState(
- Strings.isNullOrEmpty(stateServerId) || args.serverId.equals(stateServerId),
- String.format("invalid server id, expected %s: actual: %s", args.serverId, stateServerId));
+ if (!Strings.isNullOrEmpty(stateServerId) && !args.serverId.equals(stateServerId)) {
+ throw new InvalidServerIdException(args.serverId, stateServerId);
+ }
state.copyColumnsTo(change);
revisionNoteMap = v.revisionNoteMap();
diff --git a/java/com/google/gerrit/server/notedb/ChangeNotesParser.java b/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
index 428df16..ed6039f 100644
--- a/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
+++ b/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
@@ -16,6 +16,7 @@
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_ASSIGNEE;
+import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_ATTENTION;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_BRANCH;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_CHANGE_ID;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_CHERRY_PICK_OF;
@@ -43,6 +44,7 @@
import com.google.common.base.Enums;
import com.google.common.base.Splitter;
import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.ListMultimap;
@@ -57,6 +59,7 @@
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.entities.Account;
+import com.google.gerrit.entities.AttentionStatus;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.ChangeMessage;
import com.google.gerrit.entities.Comment;
@@ -75,6 +78,7 @@
import java.io.IOException;
import java.nio.charset.Charset;
import java.sql.Timestamp;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -102,7 +106,6 @@
// Private final members initialized in the constructor.
private final ChangeNoteJson changeNoteJson;
-
private final NoteDbMetrics metrics;
private final Change.Id id;
private final ObjectId tip;
@@ -114,6 +117,9 @@
private final Table<Address, ReviewerStateInternal, Timestamp> reviewersByEmail;
private final List<Account.Id> allPastReviewers;
private final List<ReviewerStatusUpdate> reviewerUpdates;
+ /** Holds only the most recent update per user. Older updates are discarded. */
+ private final Map<Account.Id, AttentionStatus> latestAttentionStatus;
+
private final List<AssigneeStatusUpdate> assigneeUpdates;
private final List<SubmitRecord> submitRecords;
private final ListMultimap<ObjectId, Comment> comments;
@@ -169,6 +175,7 @@
pendingReviewersByEmail = ReviewerByEmailSet.empty();
allPastReviewers = new ArrayList<>();
reviewerUpdates = new ArrayList<>();
+ latestAttentionStatus = new HashMap<>();
assigneeUpdates = new ArrayList<>();
submitRecords = Lists.newArrayListWithExpectedSize(1);
allChangeMessages = new ArrayList<>();
@@ -239,6 +246,7 @@
pendingReviewersByEmail,
allPastReviewers,
buildReviewerUpdates(),
+ ImmutableList.copyOf(latestAttentionStatus.values()),
assigneeUpdates,
submitRecords,
buildAllMessages(),
@@ -359,6 +367,7 @@
}
parseHashtags(commit);
+ parseAttentionUpdates(commit);
parseAssigneeUpdates(ts, commit);
if (submissionId == null) {
@@ -569,6 +578,21 @@
}
}
+ private void parseAttentionUpdates(ChangeNotesCommit commit) throws ConfigInvalidException {
+ List<String> attentionStrings = commit.getFooterLineValues(FOOTER_ATTENTION);
+ for (String attentionString : attentionStrings) {
+
+ Optional<AttentionStatus> attentionStatus =
+ ChangeNoteUtil.attentionStatusFromJson(
+ Instant.ofEpochSecond(commit.getCommitTime()), attentionString);
+ if (!attentionStatus.isPresent()) {
+ throw invalidFooter(FOOTER_ATTENTION, attentionString);
+ }
+ // Processing is in reverse chronological order. Keep only the latest update.
+ latestAttentionStatus.putIfAbsent(attentionStatus.get().account(), attentionStatus.get());
+ }
+ }
+
private void parseAssigneeUpdates(Timestamp ts, ChangeNotesCommit commit)
throws ConfigInvalidException {
String assigneeValue = parseOneFooter(commit, FOOTER_ASSIGNEE);
diff --git a/java/com/google/gerrit/server/notedb/ChangeNotesState.java b/java/com/google/gerrit/server/notedb/ChangeNotesState.java
index 064e43b..1931e7e 100644
--- a/java/com/google/gerrit/server/notedb/ChangeNotesState.java
+++ b/java/com/google/gerrit/server/notedb/ChangeNotesState.java
@@ -35,6 +35,7 @@
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.entities.Account;
+import com.google.gerrit.entities.AttentionStatus;
import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.ChangeMessage;
@@ -55,6 +56,7 @@
import com.google.gerrit.server.ReviewerStatusUpdate;
import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto;
import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto.AssigneeStatusUpdateProto;
+import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto.AttentionStatusProto;
import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto.ChangeColumnsProto;
import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto.ReviewerByEmailSetEntryProto;
import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto.ReviewerSetEntryProto;
@@ -66,6 +68,7 @@
import com.google.protobuf.ByteString;
import com.google.protobuf.MessageLite;
import java.sql.Timestamp;
+import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -83,11 +86,12 @@
*/
@AutoValue
public abstract class ChangeNotesState {
+
static ChangeNotesState empty(Change change) {
return Builder.empty(change.getId()).build();
}
- static Builder builder() {
+ private static Builder builder() {
return new AutoValue_ChangeNotesState.Builder();
}
@@ -115,6 +119,7 @@
ReviewerByEmailSet pendingReviewersByEmail,
List<Account.Id> allPastReviewers,
List<ReviewerStatusUpdate> reviewerUpdates,
+ List<AttentionStatus> attentionStatusUpdates,
List<AssigneeStatusUpdate> assigneeUpdates,
List<SubmitRecord> submitRecords,
List<ChangeMessage> changeMessages,
@@ -165,6 +170,7 @@
.pendingReviewersByEmail(pendingReviewersByEmail)
.allPastReviewers(allPastReviewers)
.reviewerUpdates(reviewerUpdates)
+ .attentionUpdates(attentionStatusUpdates)
.assigneeUpdates(assigneeUpdates)
.submitRecords(submitRecords)
.changeMessages(changeMessages)
@@ -180,6 +186,7 @@
*/
@AutoValue
abstract static class ChangeColumns {
+
static Builder builder() {
return new AutoValue_ChangeNotesState_ChangeColumns.Builder();
}
@@ -229,6 +236,7 @@
@AutoValue.Builder
abstract static class Builder {
+
abstract Builder changeKey(Change.Key changeKey);
abstract Builder createdOn(Timestamp createdOn);
@@ -297,6 +305,8 @@
abstract ImmutableList<ReviewerStatusUpdate> reviewerUpdates();
+ abstract ImmutableList<AttentionStatus> attentionUpdates();
+
abstract ImmutableList<AssigneeStatusUpdate> assigneeUpdates();
abstract ImmutableList<SubmitRecord> submitRecords();
@@ -361,6 +371,7 @@
@AutoValue.Builder
abstract static class Builder {
+
static Builder empty(Change.Id changeId) {
return new AutoValue_ChangeNotesState.Builder()
.changeId(changeId)
@@ -373,6 +384,7 @@
.pendingReviewersByEmail(ReviewerByEmailSet.empty())
.allPastReviewers(ImmutableList.of())
.reviewerUpdates(ImmutableList.of())
+ .attentionUpdates(ImmutableList.of())
.assigneeUpdates(ImmutableList.of())
.submitRecords(ImmutableList.of())
.changeMessages(ImmutableList.of())
@@ -406,6 +418,8 @@
abstract Builder reviewerUpdates(List<ReviewerStatusUpdate> reviewerUpdates);
+ abstract Builder attentionUpdates(List<AttentionStatus> attentionUpdates);
+
abstract Builder assigneeUpdates(List<AssigneeStatusUpdate> assigneeUpdates);
abstract Builder submitRecords(List<SubmitRecord> submitRecords);
@@ -473,6 +487,7 @@
object.allPastReviewers().forEach(a -> b.addPastReviewer(a.get()));
object.reviewerUpdates().forEach(u -> b.addReviewerUpdate(toReviewerStatusUpdateProto(u)));
+ object.attentionUpdates().forEach(u -> b.addAttentionStatus(toAttentionStatusProto(u)));
object.assigneeUpdates().forEach(u -> b.addAssigneeUpdate(toAssigneeStatusUpdateProto(u)));
object
.submitRecords()
@@ -556,6 +571,15 @@
.build();
}
+ private static AttentionStatusProto toAttentionStatusProto(AttentionStatus attentionStatus) {
+ return AttentionStatusProto.newBuilder()
+ .setDate(attentionStatus.timestamp().toEpochMilli())
+ .setAccount(attentionStatus.account().get())
+ .setOperation(attentionStatus.operation().name())
+ .setReason(attentionStatus.reason())
+ .build();
+ }
+
private static AssigneeStatusUpdateProto toAssigneeStatusUpdateProto(AssigneeStatusUpdate u) {
AssigneeStatusUpdateProto.Builder builder =
AssigneeStatusUpdateProto.newBuilder()
@@ -596,6 +620,7 @@
.allPastReviewers(
proto.getPastReviewerList().stream().map(Account::id).collect(toImmutableList()))
.reviewerUpdates(toReviewerStatusUpdateList(proto.getReviewerUpdateList()))
+ .attentionUpdates(toAttentionUpdateList(proto.getAttentionStatusList()))
.assigneeUpdates(toAssigneeStatusUpdateList(proto.getAssigneeUpdateList()))
.submitRecords(
proto.getSubmitRecordList().stream()
@@ -694,6 +719,20 @@
return b.build();
}
+ private static ImmutableList<AttentionStatus> toAttentionUpdateList(
+ List<AttentionStatusProto> protos) {
+ ImmutableList.Builder<AttentionStatus> b = ImmutableList.builder();
+ for (AttentionStatusProto proto : protos) {
+ b.add(
+ AttentionStatus.createFromRead(
+ Instant.ofEpochMilli(proto.getDate()),
+ Account.id(proto.getAccount()),
+ AttentionStatus.Operation.valueOf(proto.getOperation()),
+ proto.getReason()));
+ }
+ return b.build();
+ }
+
private static ImmutableList<AssigneeStatusUpdate> toAssigneeStatusUpdateList(
List<AssigneeStatusUpdateProto> protos) {
ImmutableList.Builder<AssigneeStatusUpdate> b = ImmutableList.builder();
diff --git a/java/com/google/gerrit/server/notedb/ChangeUpdate.java b/java/com/google/gerrit/server/notedb/ChangeUpdate.java
index 2822f61..3ef631b 100644
--- a/java/com/google/gerrit/server/notedb/ChangeUpdate.java
+++ b/java/com/google/gerrit/server/notedb/ChangeUpdate.java
@@ -19,6 +19,7 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.gerrit.entities.RefNames.changeMetaRef;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_ASSIGNEE;
+import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_ATTENTION;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_BRANCH;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_CHANGE_ID;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_CHERRY_PICK_OF;
@@ -52,6 +53,7 @@
import com.google.common.collect.TreeBasedTable;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.entities.Account;
+import com.google.gerrit.entities.AttentionStatus;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.Comment;
import com.google.gerrit.entities.Project;
@@ -125,6 +127,7 @@
private String submissionId;
private String topic;
private String commit;
+ private List<AttentionStatus> attentionUpdates;
private Optional<Account.Id> assignee;
private Set<String> hashtags;
private String changeMessage;
@@ -368,6 +371,21 @@
this.hashtags = hashtags;
}
+ /**
+ * All updates must have a timestamp of null since we use the commit's timestamp. There also must
+ * not be multiple updates for a single user.
+ */
+ void setAttentionUpdates(List<AttentionStatus> attentionUpdates) {
+ checkArgument(
+ attentionUpdates.stream().noneMatch(x -> x.timestamp() != null),
+ "must not specify timestamp for write");
+ checkArgument(
+ attentionUpdates.stream().map(AttentionStatus::account).distinct().count()
+ == attentionUpdates.size(),
+ "must not specify multiple updates for single user");
+ this.attentionUpdates = attentionUpdates;
+ }
+
public void setAssignee(Account.Id assignee) {
checkArgument(assignee != null, "use removeAssignee");
this.assignee = Optional.of(assignee);
@@ -578,6 +596,12 @@
addFooter(msg, FOOTER_COMMIT, commit);
}
+ if (attentionUpdates != null) {
+ for (AttentionStatus attentionUpdate : attentionUpdates) {
+ addFooter(msg, FOOTER_ATTENTION, noteUtil.attentionStatusToJson(attentionUpdate));
+ }
+ }
+
if (assignee != null) {
if (assignee.isPresent()) {
addFooter(msg, FOOTER_ASSIGNEE);
@@ -713,6 +737,7 @@
&& status == null
&& submissionId == null
&& submitRecords == null
+ && attentionUpdates == null
&& assignee == null
&& hashtags == null
&& topic == null
@@ -774,12 +799,8 @@
}
private StringBuilder addIdent(StringBuilder sb, Account.Id accountId) {
- PersonIdent ident = newIdent(accountId, when);
-
- PersonIdent.appendSanitized(sb, ident.getName());
- sb.append(" <");
- PersonIdent.appendSanitized(sb, ident.getEmailAddress());
- sb.append('>');
+ PersonIdent ident = noteUtil.newIdent(accountId, when, serverIdent);
+ ChangeNoteUtil.appendIdentString(sb, ident.getName(), ident.getEmailAddress());
return sb;
}
}
diff --git a/java/com/google/gerrit/server/notedb/DeleteZombieCommentsRefs.java b/java/com/google/gerrit/server/notedb/DeleteZombieCommentsRefs.java
index 9ec1d69..128e185 100644
--- a/java/com/google/gerrit/server/notedb/DeleteZombieCommentsRefs.java
+++ b/java/com/google/gerrit/server/notedb/DeleteZombieCommentsRefs.java
@@ -17,6 +17,7 @@
import static com.google.common.collect.ImmutableList.toImmutableList;
import com.google.common.collect.Iterables;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Change;
import com.google.gerrit.git.RefUpdateUtil;
import com.google.gerrit.server.config.AllUsersName;
@@ -42,9 +43,12 @@
* and not get deleted. These refs point to an empty tree.
*/
public class DeleteZombieCommentsRefs {
- private final String EMPTY_TREE_ID = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
- private final String DRAFT_REFS_PREFIX = "refs/draft-comments";
- private final int CHUNK_SIZE = 100; // log progress after deleting every CHUNK_SIZE refs
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ private static final String EMPTY_TREE_ID = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
+ private static final String DRAFT_REFS_PREFIX = "refs/draft-comments";
+ private static final int CHUNK_SIZE = 100; // log progress after deleting every CHUNK_SIZE refs
+
private final GitRepositoryManager repoManager;
private final AllUsersName allUsers;
private final int cleanupPercentage;
@@ -70,18 +74,15 @@
List<Ref> draftRefs = allUsersRepo.getRefDatabase().getRefsByPrefix(DRAFT_REFS_PREFIX);
List<Ref> zombieRefs = filterZombieRefs(draftRefs);
- System.out.println(
- String.format(
- "Found a total of %d zombie draft refs in %s repo.",
- zombieRefs.size(), allUsers.get()));
+ logger.atInfo().log(
+ "Found a total of %d zombie draft refs in %s repo.", zombieRefs.size(), allUsers.get());
- System.out.println(String.format("Cleanup percentage = %d", cleanupPercentage));
+ logger.atInfo().log("Cleanup percentage = %d", cleanupPercentage);
zombieRefs =
zombieRefs.stream()
.filter(ref -> Change.Id.fromAllUsersRef(ref.getName()).get() % 100 < cleanupPercentage)
.collect(toImmutableList());
- System.out.println(
- String.format("Number of zombie refs to be cleaned = %d", zombieRefs.size()));
+ logger.atInfo().log("Number of zombie refs to be cleaned = %d", zombieRefs.size());
long zombieRefsCnt = zombieRefs.size();
long deletedRefsCnt = 0;
@@ -124,7 +125,7 @@
}
private void logProgress(long deletedRefsCount, long allRefsCount, long elapsed) {
- System.out.format(
+ logger.atInfo().log(
"Deleted %d/%d zombie draft refs (%d seconds)\n", deletedRefsCount, allRefsCount, elapsed);
}
}
diff --git a/java/com/google/gerrit/server/notedb/InvalidServerIdException.java b/java/com/google/gerrit/server/notedb/InvalidServerIdException.java
new file mode 100644
index 0000000..f79e07c
--- /dev/null
+++ b/java/com/google/gerrit/server/notedb/InvalidServerIdException.java
@@ -0,0 +1,25 @@
+// 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.server.notedb;
+
+public class InvalidServerIdException extends IllegalStateException {
+ private static final long serialVersionUID = 5302751510361680907L;
+
+ public InvalidServerIdException(String expectedServerId, String actualServerId) {
+ super(
+ String.format(
+ "invalid server id, expected %s: actual: %s", expectedServerId, actualServerId));
+ }
+}
diff --git a/java/com/google/gerrit/server/permissions/PermissionBackend.java b/java/com/google/gerrit/server/permissions/PermissionBackend.java
index 8ee0fee..653c3b5f 100644
--- a/java/com/google/gerrit/server/permissions/PermissionBackend.java
+++ b/java/com/google/gerrit/server/permissions/PermissionBackend.java
@@ -484,12 +484,12 @@
public Set<LabelPermission.WithValue> testLabels(Collection<LabelType> types)
throws PermissionBackendException {
requireNonNull(types, "LabelType");
- return test(types.stream().flatMap((t) -> valuesOf(t).stream()).collect(toSet()));
+ return test(types.stream().flatMap(t -> valuesOf(t).stream()).collect(toSet()));
}
private static Set<LabelPermission.WithValue> valuesOf(LabelType label) {
return label.getValues().stream()
- .map((v) -> new LabelPermission.WithValue(label, v))
+ .map(v -> new LabelPermission.WithValue(label, v))
.collect(toSet());
}
}
diff --git a/java/com/google/gerrit/server/project/BooleanProjectConfigTransformations.java b/java/com/google/gerrit/server/project/BooleanProjectConfigTransformations.java
index 3a73d0c..ae9828a 100644
--- a/java/com/google/gerrit/server/project/BooleanProjectConfigTransformations.java
+++ b/java/com/google/gerrit/server/project/BooleanProjectConfigTransformations.java
@@ -27,7 +27,7 @@
/** Provides transformations to get and set BooleanProjectConfigs from the API. */
public class BooleanProjectConfigTransformations {
- private static ImmutableMap<BooleanProjectConfig, Mapper> MAPPER =
+ private static final ImmutableMap<BooleanProjectConfig, Mapper> MAPPER =
ImmutableMap.<BooleanProjectConfig, Mapper>builder()
.put(
BooleanProjectConfig.USE_CONTRIBUTOR_AGREEMENTS,
diff --git a/java/com/google/gerrit/server/project/ProjectsConsistencyChecker.java b/java/com/google/gerrit/server/project/ProjectsConsistencyChecker.java
index 110beaf..7ed2491 100644
--- a/java/com/google/gerrit/server/project/ProjectsConsistencyChecker.java
+++ b/java/com/google/gerrit/server/project/ProjectsConsistencyChecker.java
@@ -233,7 +233,7 @@
predicates.add(new CommitPredicate(commit.name()));
}
- if (predicates.size() > 0) {
+ if (!predicates.isEmpty()) {
// Execute the query with the remaining predicates that were collected.
autoCloseableChanges.addAll(
executeQueryAndAutoCloseChanges(
diff --git a/java/com/google/gerrit/server/query/account/InternalAccountQuery.java b/java/com/google/gerrit/server/query/account/InternalAccountQuery.java
index b233260..091edca 100644
--- a/java/com/google/gerrit/server/query/account/InternalAccountQuery.java
+++ b/java/com/google/gerrit/server/query/account/InternalAccountQuery.java
@@ -71,7 +71,7 @@
List<AccountState> accountStates = byExternalId(externalId);
if (accountStates.size() == 1) {
return accountStates.get(0);
- } else if (accountStates.size() > 0) {
+ } else if (!accountStates.isEmpty()) {
StringBuilder msg = new StringBuilder();
msg.append("Ambiguous external ID ").append(externalId).append(" for accounts: ");
Joiner.on(", ")
diff --git a/java/com/google/gerrit/server/query/change/AndChangeSource.java b/java/com/google/gerrit/server/query/change/AndChangeSource.java
index 4a3b936..749204f 100644
--- a/java/com/google/gerrit/server/query/change/AndChangeSource.java
+++ b/java/com/google/gerrit/server/query/change/AndChangeSource.java
@@ -35,9 +35,7 @@
@Override
public boolean hasChange() {
- return source != null
- && source instanceof ChangeDataSource
- && ((ChangeDataSource) source).hasChange();
+ return source instanceof ChangeDataSource && ((ChangeDataSource) source).hasChange();
}
@Override
diff --git a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index 327c21f..f8610db 100644
--- a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -512,7 +512,7 @@
return ChangeStatusPredicate.parse(statusName);
}
- public Predicate<ChangeData> status_open() {
+ public Predicate<ChangeData> statusOpen() {
return ChangeStatusPredicate.open();
}
@@ -561,7 +561,7 @@
}
if ("visible".equalsIgnoreCase(value)) {
- return is_visible();
+ return isVisible();
}
if ("reviewed".equalsIgnoreCase(value)) {
@@ -973,7 +973,7 @@
public Predicate<ChangeData> visibleto(String who)
throws QueryParseException, IOException, ConfigInvalidException {
if (isSelf(who)) {
- return is_visible();
+ return isVisible();
}
try {
return Predicate.or(
@@ -1008,7 +1008,7 @@
args.anonymousUserProvider);
}
- public Predicate<ChangeData> is_visible() throws QueryParseException {
+ public Predicate<ChangeData> isVisible() throws QueryParseException {
return visibleto(args.getUser());
}
diff --git a/java/com/google/gerrit/server/query/change/IsWatchedByPredicate.java b/java/com/google/gerrit/server/query/change/IsWatchedByPredicate.java
index 218a89d..3a43fd3 100644
--- a/java/com/google/gerrit/server/query/change/IsWatchedByPredicate.java
+++ b/java/com/google/gerrit/server/query/change/IsWatchedByPredicate.java
@@ -77,13 +77,13 @@
} else if (f != null) {
r.add(f);
} else {
- r.add(builder.status_open());
+ r.add(builder.statusOpen());
}
}
if (r.isEmpty()) {
return ImmutableList.of(ChangeIndexPredicate.none());
} else if (checkIsVisible) {
- return ImmutableList.of(or(r), builder.is_visible());
+ return ImmutableList.of(or(r), builder.isVisible());
} else {
return ImmutableList.of(or(r));
}
diff --git a/java/com/google/gerrit/server/restapi/account/DeleteExternalIds.java b/java/com/google/gerrit/server/restapi/account/DeleteExternalIds.java
index 442b6a4..80f0bb1 100644
--- a/java/com/google/gerrit/server/restapi/account/DeleteExternalIds.java
+++ b/java/com/google/gerrit/server/restapi/account/DeleteExternalIds.java
@@ -76,7 +76,7 @@
permissionBackend.currentUser().check(GlobalPermission.ACCESS_DATABASE);
}
- if (extIds == null || extIds.size() == 0) {
+ if (extIds == null || extIds.isEmpty()) {
throw new BadRequestException("external IDs are required");
}
diff --git a/java/com/google/gerrit/server/restapi/change/CreateChange.java b/java/com/google/gerrit/server/restapi/change/CreateChange.java
index a6a1eef..9e792d0 100644
--- a/java/com/google/gerrit/server/restapi/change/CreateChange.java
+++ b/java/com/google/gerrit/server/restapi/change/CreateChange.java
@@ -335,9 +335,10 @@
Timestamp now = TimeUtil.nowTs();
+ PersonIdent committer = me.newCommitterIdent(now, serverTimeZone);
PersonIdent author =
input.author == null
- ? me.newCommitterIdent(now, serverTimeZone)
+ ? committer
: new PersonIdent(input.author.name, input.author.email, now, serverTimeZone);
String commitMessage = getCommitMessage(input.subject, me);
@@ -345,7 +346,9 @@
CodeReviewCommit c;
if (input.merge != null) {
// create a merge commit
- c = newMergeCommit(git, oi, rw, projectState, mergeTip, input.merge, author, commitMessage);
+ c =
+ newMergeCommit(
+ git, oi, rw, projectState, mergeTip, input.merge, author, committer, commitMessage);
if (!c.getFilesWithGitConflicts().isEmpty()) {
logger.atFine().log(
"merge commit has conflicts in the following files: %s",
@@ -353,7 +356,7 @@
}
} else {
// create an empty commit
- c = newCommit(oi, rw, author, mergeTip, commitMessage);
+ c = newCommit(oi, rw, author, committer, mergeTip, commitMessage);
}
Change.Id changeId = Change.id(seq.nextChangeId());
@@ -495,6 +498,7 @@
ObjectInserter oi,
CodeReviewRevWalk rw,
PersonIdent authorIdent,
+ PersonIdent committerIdent,
RevCommit mergeTip,
String commitMessage)
throws IOException {
@@ -507,7 +511,7 @@
commit.setParentId(mergeTip);
}
commit.setAuthor(authorIdent);
- commit.setCommitter(authorIdent);
+ commit.setCommitter(committerIdent);
commit.setMessage(commitMessage);
return rw.parseCommit(insert(oi, commit));
}
@@ -520,6 +524,7 @@
RevCommit mergeTip,
MergeInput merge,
PersonIdent authorIdent,
+ PersonIdent committerIdent,
String commitMessage)
throws RestApiException, IOException {
logger.atFine().log(
@@ -556,6 +561,7 @@
mergeStrategy,
merge.allowConflicts,
authorIdent,
+ committerIdent,
commitMessage,
rw);
} catch (NoMergeBaseException e) {
diff --git a/java/com/google/gerrit/server/restapi/change/GetPatch.java b/java/com/google/gerrit/server/restapi/change/GetPatch.java
index 66ccef3..187ebce 100644
--- a/java/com/google/gerrit/server/restapi/change/GetPatch.java
+++ b/java/com/google/gerrit/server/restapi/change/GetPatch.java
@@ -43,7 +43,7 @@
public class GetPatch implements RestReadView<RevisionResource> {
private final GitRepositoryManager repoManager;
- private final String FILE_NOT_FOUND = "File not found: %s.";
+ private static final String FILE_NOT_FOUND = "File not found: %s.";
@Option(name = "--zip")
private boolean zip;
diff --git a/java/com/google/gerrit/server/restapi/change/RevertSubmission.java b/java/com/google/gerrit/server/restapi/change/RevertSubmission.java
index b5035d8..e8395f0 100644
--- a/java/com/google/gerrit/server/restapi/change/RevertSubmission.java
+++ b/java/com/google/gerrit/server/restapi/change/RevertSubmission.java
@@ -308,8 +308,6 @@
cherryPickInput.message = revertInput.message;
ObjectId generatedChangeId = CommitMessageUtil.generateChangeId();
Change.Id cherryPickRevertChangeId = Change.id(seq.nextChangeId());
- // TODO (paiking): In the the future, the timestamp should be the same for all the revert
- // changes.
try (BatchUpdate bu = updateFactory.create(project, user.get(), TimeUtil.nowTs())) {
bu.setNotify(
notifyResolver.resolve(
diff --git a/java/com/google/gerrit/server/restapi/change/SubmittedTogether.java b/java/com/google/gerrit/server/restapi/change/SubmittedTogether.java
index caa256f..214a001 100644
--- a/java/com/google/gerrit/server/restapi/change/SubmittedTogether.java
+++ b/java/com/google/gerrit/server/restapi/change/SubmittedTogether.java
@@ -46,6 +46,7 @@
import java.util.Comparator;
import java.util.EnumSet;
import java.util.List;
+import java.util.Set;
import org.kohsuke.args4j.Option;
public class SubmittedTogether implements RestReadView<ChangeResource> {
@@ -97,12 +98,12 @@
this.sorter = sorter;
}
- public SubmittedTogether addListChangesOption(EnumSet<ListChangesOption> o) {
+ public SubmittedTogether addListChangesOption(Set<ListChangesOption> o) {
jsonOpt.addAll(o);
return this;
}
- public SubmittedTogether addSubmittedTogetherOption(EnumSet<SubmittedTogetherOption> o) {
+ public SubmittedTogether addSubmittedTogetherOption(Set<SubmittedTogetherOption> o) {
options.addAll(o);
return this;
}
diff --git a/java/com/google/gerrit/server/restapi/group/ListGroups.java b/java/com/google/gerrit/server/restapi/group/ListGroups.java
index adc251c..a0e1e2e 100644
--- a/java/com/google/gerrit/server/restapi/group/ListGroups.java
+++ b/java/com/google/gerrit/server/restapi/group/ListGroups.java
@@ -86,7 +86,7 @@
private final Groups groups;
private final GroupResolver groupResolver;
- private EnumSet<ListGroupsOption> options = EnumSet.noneOf(ListGroupsOption.class);
+ private Set<ListGroupsOption> options = EnumSet.noneOf(ListGroupsOption.class);
private boolean visibleToAll;
private Account.Id user;
private boolean owned;
@@ -220,7 +220,7 @@
this.groupResolver = groupResolver;
}
- public void setOptions(EnumSet<ListGroupsOption> options) {
+ public void setOptions(Set<ListGroupsOption> options) {
this.options = options;
}
diff --git a/java/com/google/gerrit/server/restapi/project/ListProjects.java b/java/com/google/gerrit/server/restapi/project/ListProjects.java
index 345340b..6384282 100644
--- a/java/com/google/gerrit/server/restapi/project/ListProjects.java
+++ b/java/com/google/gerrit/server/restapi/project/ListProjects.java
@@ -350,7 +350,7 @@
queries.add(String.format("(state:%s)", state.name()));
}
- return Joiner.on(" AND ").join(queries).toString();
+ return Joiner.on(" AND ").join(queries);
}
private SortedMap<String, ProjectInfo> applyAsQuery(String query) throws BadRequestException {
diff --git a/java/com/google/gerrit/server/restapi/project/SetParent.java b/java/com/google/gerrit/server/restapi/project/SetParent.java
index 4cf0182..a610dd4 100644
--- a/java/com/google/gerrit/server/restapi/project/SetParent.java
+++ b/java/com/google/gerrit/server/restapi/project/SetParent.java
@@ -165,12 +165,7 @@
throw new ResourceConflictException("cannot set parent to self");
}
- if (Iterables.tryFind(
- parent.tree(),
- p -> {
- return p.getNameKey().equals(project);
- })
- .isPresent()) {
+ if (Iterables.tryFind(parent.tree(), p -> p.getNameKey().equals(project)).isPresent()) {
throw new ResourceConflictException(
"cycle exists between " + project.get() + " and " + parent.getName());
}
diff --git a/java/com/google/gerrit/sshd/BUILD b/java/com/google/gerrit/sshd/BUILD
index f567a3a..a5b88b4 100644
--- a/java/com/google/gerrit/sshd/BUILD
+++ b/java/com/google/gerrit/sshd/BUILD
@@ -22,6 +22,7 @@
"//java/com/google/gerrit/server/restapi",
"//java/com/google/gerrit/server/util/time",
"//java/com/google/gerrit/util/cli",
+ "//java/com/google/gerrit/util/logging",
"//lib:args4j",
"//lib:gson",
"//lib:guava",
diff --git a/java/com/google/gerrit/sshd/SshLog.java b/java/com/google/gerrit/sshd/SshLog.java
index e8df441..2b3052c 100644
--- a/java/com/google/gerrit/sshd/SshLog.java
+++ b/java/com/google/gerrit/sshd/SshLog.java
@@ -45,15 +45,18 @@
@Singleton
class SshLog implements LifecycleListener, GerritConfigListener {
private static final Logger log = Logger.getLogger(SshLog.class);
- private static final String LOG_NAME = "sshd_log";
- private static final String P_SESSION = "session";
- private static final String P_USER_NAME = "userName";
- private static final String P_ACCOUNT_ID = "accountId";
- private static final String P_WAIT = "queueWaitTime";
- private static final String P_EXEC = "executionTime";
- private static final String P_STATUS = "status";
- private static final String P_AGENT = "agent";
- private static final String P_MESSAGE = "message";
+
+ private static final String JSON_SUFFIX = ".json";
+
+ protected static final String LOG_NAME = "sshd_log";
+ protected static final String P_SESSION = "session";
+ protected static final String P_USER_NAME = "userName";
+ protected static final String P_ACCOUNT_ID = "accountId";
+ protected static final String P_WAIT = "queueWaitTime";
+ protected static final String P_EXEC = "executionTime";
+ protected static final String P_STATUS = "status";
+ protected static final String P_AGENT = "agent";
+ protected static final String P_MESSAGE = "message";
private final Provider<SshSession> session;
private final Provider<Context> context;
@@ -61,6 +64,9 @@
private final GroupAuditService auditService;
private final SystemLog systemLog;
+ private final boolean json;
+ private final boolean text;
+
private final Object lock = new Object();
@Inject
@@ -75,6 +81,9 @@
this.auditService = auditService;
this.systemLog = systemLog;
+ this.json = config.getBoolean("log", "jsonLogging", false);
+ this.text = config.getBoolean("log", "textLogging", true) || !json;
+
if (config.getBoolean("sshd", "requestLog", true)) {
enableLogging();
}
@@ -84,7 +93,16 @@
public boolean enableLogging() {
synchronized (lock) {
if (async == null) {
- async = systemLog.createAsyncAppender(LOG_NAME, new SshLogLayout());
+ async = new AsyncAppender();
+
+ if (text) {
+ async.addAppender(systemLog.createAsyncAppender(LOG_NAME, new SshLogLayout()));
+ }
+
+ if (json) {
+ async.addAppender(
+ systemLog.createAsyncAppender(LOG_NAME + JSON_SUFFIX, new SshLogJsonLayout()));
+ }
return true;
}
return false;
diff --git a/java/com/google/gerrit/sshd/SshLogJsonLayout.java b/java/com/google/gerrit/sshd/SshLogJsonLayout.java
new file mode 100644
index 0000000..5ece5af
--- /dev/null
+++ b/java/com/google/gerrit/sshd/SshLogJsonLayout.java
@@ -0,0 +1,96 @@
+// 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.sshd;
+
+import static com.google.gerrit.sshd.SshLog.P_ACCOUNT_ID;
+import static com.google.gerrit.sshd.SshLog.P_AGENT;
+import static com.google.gerrit.sshd.SshLog.P_EXEC;
+import static com.google.gerrit.sshd.SshLog.P_MESSAGE;
+import static com.google.gerrit.sshd.SshLog.P_SESSION;
+import static com.google.gerrit.sshd.SshLog.P_STATUS;
+import static com.google.gerrit.sshd.SshLog.P_USER_NAME;
+import static com.google.gerrit.sshd.SshLog.P_WAIT;
+
+import com.google.gerrit.util.logging.JsonLayout;
+import com.google.gerrit.util.logging.JsonLogEntry;
+import java.time.format.DateTimeFormatter;
+import org.apache.log4j.spi.LoggingEvent;
+
+public class SshLogJsonLayout extends JsonLayout {
+
+ @Override
+ public DateTimeFormatter createDateTimeFormatter() {
+ return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss,SSS Z");
+ }
+
+ @Override
+ public JsonLogEntry toJsonLogEntry(LoggingEvent event) {
+ return new SshJsonLogEntry(event);
+ }
+
+ @SuppressWarnings("unused")
+ private class SshJsonLogEntry extends JsonLogEntry {
+ public String timestamp;
+ public String session;
+ public String thread;
+ public String user;
+ public String accountId;
+ public String message;
+ public String waitTime;
+ public String execTime;
+ public String status;
+ public String agent;
+ public String timeNegotiating;
+ public String timeSearchReuse;
+ public String timeSearchSizes;
+ public String timeCounting;
+ public String timeCompressing;
+ public String timeWriting;
+ public String timeTotal;
+ public String bitmapIndexMisses;
+ public String deltasTotal;
+ public String objectsTotal;
+ public String bytesTotal;
+
+ public SshJsonLogEntry(LoggingEvent event) {
+ this.timestamp = formatDate(event.getTimeStamp());
+ this.session = getMdcString(event, P_SESSION);
+ this.thread = event.getThreadName();
+ this.user = getMdcString(event, P_USER_NAME);
+ this.accountId = getMdcString(event, P_ACCOUNT_ID);
+ this.message = (String) event.getMessage();
+ this.waitTime = getMdcString(event, P_WAIT);
+ this.execTime = getMdcString(event, P_EXEC);
+ this.status = getMdcString(event, P_STATUS);
+ this.agent = getMdcString(event, P_AGENT);
+
+ String metricString = getMdcString(event, P_MESSAGE);
+ if (metricString != null && !metricString.isEmpty()) {
+ String[] ssh_metrics = metricString.split(" ");
+ this.timeNegotiating = ssh_metrics[0];
+ this.timeSearchReuse = ssh_metrics[1];
+ this.timeSearchSizes = ssh_metrics[2];
+ this.timeCounting = ssh_metrics[3];
+ this.timeCompressing = ssh_metrics[4];
+ this.timeWriting = ssh_metrics[5];
+ this.timeTotal = ssh_metrics[6];
+ this.bitmapIndexMisses = ssh_metrics[7];
+ this.deltasTotal = ssh_metrics[8];
+ this.objectsTotal = ssh_metrics[9];
+ this.bytesTotal = ssh_metrics[10];
+ }
+ }
+ }
+}
diff --git a/java/com/google/gerrit/sshd/SshLogLayout.java b/java/com/google/gerrit/sshd/SshLogLayout.java
index f16dd73..c676be9 100644
--- a/java/com/google/gerrit/sshd/SshLogLayout.java
+++ b/java/com/google/gerrit/sshd/SshLogLayout.java
@@ -14,6 +14,15 @@
package com.google.gerrit.sshd;
+import static com.google.gerrit.sshd.SshLog.P_ACCOUNT_ID;
+import static com.google.gerrit.sshd.SshLog.P_AGENT;
+import static com.google.gerrit.sshd.SshLog.P_EXEC;
+import static com.google.gerrit.sshd.SshLog.P_MESSAGE;
+import static com.google.gerrit.sshd.SshLog.P_SESSION;
+import static com.google.gerrit.sshd.SshLog.P_STATUS;
+import static com.google.gerrit.sshd.SshLog.P_USER_NAME;
+import static com.google.gerrit.sshd.SshLog.P_WAIT;
+
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;
@@ -23,15 +32,6 @@
public final class SshLogLayout extends Layout {
- private static final String P_SESSION = "session";
- private static final String P_USER_NAME = "userName";
- private static final String P_ACCOUNT_ID = "accountId";
- private static final String P_WAIT = "queueWaitTime";
- private static final String P_EXEC = "executionTime";
- private static final String P_STATUS = "status";
- private static final String P_AGENT = "agent";
- private static final String P_MESSAGE = "message";
-
private final Calendar calendar;
private long lastTimeMillis;
private final char[] lastTimeString = new char[20];
diff --git a/java/com/google/gerrit/sshd/commands/FlushCaches.java b/java/com/google/gerrit/sshd/commands/FlushCaches.java
index 0c9bbb5..2afc009 100644
--- a/java/com/google/gerrit/sshd/commands/FlushCaches.java
+++ b/java/com/google/gerrit/sshd/commands/FlushCaches.java
@@ -57,14 +57,14 @@
protected void run() throws Failure {
try {
if (list) {
- if (all || caches.size() > 0) {
+ if (all || !caches.isEmpty()) {
throw die("cannot use --list with --all or --cache");
}
doList();
return;
}
- if (all && caches.size() > 0) {
+ if (all && !caches.isEmpty()) {
throw die("cannot combine --all and --cache");
} else if (!all && caches.size() == 1 && caches.contains("all")) {
caches.clear();
diff --git a/java/com/google/gerrit/testing/BUILD b/java/com/google/gerrit/testing/BUILD
index a76275b..16c15ad 100644
--- a/java/com/google/gerrit/testing/BUILD
+++ b/java/com/google/gerrit/testing/BUILD
@@ -45,6 +45,8 @@
"//lib/flogger:api",
"//lib/guice",
"//lib/guice:guice-servlet",
+ "//lib/log:impl-log4j",
+ "//lib/log:log4j",
"//lib/truth",
],
)
diff --git a/java/com/google/gerrit/testing/GerritTestName.java b/java/com/google/gerrit/testing/GerritTestName.java
index d003289..d287837 100644
--- a/java/com/google/gerrit/testing/GerritTestName.java
+++ b/java/com/google/gerrit/testing/GerritTestName.java
@@ -15,6 +15,7 @@
package com.google.gerrit.testing;
import com.google.common.base.CharMatcher;
+import org.junit.BeforeClass;
import org.junit.rules.TestName;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
@@ -23,6 +24,11 @@
public class GerritTestName implements TestRule {
private final TestName delegate = new TestName();
+ @BeforeClass
+ public static void beforeClassTest() {
+ TestLoggingActivator.configureLogging();
+ }
+
public String getSanitizedMethodName() {
String name = delegate.getMethodName().toLowerCase();
name =
diff --git a/java/com/google/gerrit/testing/TestLoggingActivator.java b/java/com/google/gerrit/testing/TestLoggingActivator.java
new file mode 100644
index 0000000..2049bfd
--- /dev/null
+++ b/java/com/google/gerrit/testing/TestLoggingActivator.java
@@ -0,0 +1,102 @@
+// 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.testing;
+
+import static org.apache.log4j.Logger.getLogger;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMap;
+import org.apache.log4j.ConsoleAppender;
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PatternLayout;
+
+public class TestLoggingActivator {
+ private static final ImmutableMap<String, Level> LOG_LEVELS =
+ ImmutableMap.<String, Level>builder()
+ .put("com.google.gerrit", getGerritLogLevel())
+
+ // Silence non-critical messages from MINA SSHD.
+ .put("org.apache.mina", Level.WARN)
+ .put("org.apache.sshd.common", Level.WARN)
+ .put("org.apache.sshd.server", Level.WARN)
+ .put("org.apache.sshd.common.keyprovider.FileKeyPairProvider", Level.INFO)
+ .put("com.google.gerrit.sshd.GerritServerSession", Level.WARN)
+
+ // Silence non-critical messages from mime-util.
+ .put("eu.medsea.mimeutil", Level.WARN)
+
+ // Silence non-critical messages from openid4java.
+ .put("org.apache.xml", Level.WARN)
+ .put("org.openid4java", Level.WARN)
+ .put("org.openid4java.consumer.ConsumerManager", Level.FATAL)
+ .put("org.openid4java.discovery.Discovery", Level.ERROR)
+ .put("org.openid4java.server.RealmVerifier", Level.ERROR)
+ .put("org.openid4java.message.AuthSuccess", Level.ERROR)
+
+ // Silence non-critical messages from c3p0 (if used).
+ .put("com.mchange.v2.c3p0", Level.WARN)
+ .put("com.mchange.v2.resourcepool", Level.WARN)
+ .put("com.mchange.v2.sql", Level.WARN)
+
+ // Silence non-critical messages from apache.http.
+ .put("org.apache.http", Level.WARN)
+
+ // Silence non-critical messages from Jetty.
+ .put("org.eclipse.jetty", Level.WARN)
+
+ // Silence non-critical messages from JGit.
+ .put("org.eclipse.jgit.transport.PacketLineIn", Level.WARN)
+ .put("org.eclipse.jgit.transport.PacketLineOut", Level.WARN)
+ .put("org.eclipse.jgit.internal.storage.file.FileSnapshot", Level.WARN)
+ .put("org.eclipse.jgit.util.FS", Level.WARN)
+ .put("org.eclipse.jgit.util.SystemReader", Level.WARN)
+
+ // Silence non-critical messages from Elasticsearch.
+ .put("org.elasticsearch", Level.WARN)
+
+ // Silence non-critical messages from Docker for Elasticsearch query tests.
+ .put("org.testcontainers", Level.WARN)
+ .put("com.github.dockerjava.core", Level.WARN)
+ .build();
+
+ private static Level getGerritLogLevel() {
+ String value = Strings.nullToEmpty(System.getenv("GERRIT_LOG_LEVEL"));
+ if (value.isEmpty()) {
+ value = Strings.nullToEmpty(System.getProperty("gerrit.logLevel"));
+ }
+ return Level.toLevel(value, Level.INFO);
+ }
+
+ public static void configureLogging() {
+ LogManager.resetConfiguration();
+
+ PatternLayout layout = new PatternLayout();
+ layout.setConversionPattern("%-5p %c %x: %m%n");
+
+ ConsoleAppender dst = new ConsoleAppender();
+ dst.setLayout(layout);
+ dst.setTarget("System.err");
+ dst.setThreshold(Level.DEBUG);
+ dst.activateOptions();
+
+ Logger root = LogManager.getRootLogger();
+ root.removeAllAppenders();
+ root.addAppender(dst);
+
+ LOG_LEVELS.entrySet().stream().forEach(e -> getLogger(e.getKey()).setLevel(e.getValue()));
+ }
+}
diff --git a/java/com/google/gerrit/util/logging/BUILD b/java/com/google/gerrit/util/logging/BUILD
new file mode 100644
index 0000000..b8db49bd
--- /dev/null
+++ b/java/com/google/gerrit/util/logging/BUILD
@@ -0,0 +1,13 @@
+load("@rules_java//java:defs.bzl", "java_library")
+
+java_library(
+ name = "logging",
+ srcs = glob(
+ ["*.java"],
+ ),
+ visibility = ["//visibility:public"],
+ deps = [
+ "//lib:gson",
+ "//lib/log:log4j",
+ ],
+)
diff --git a/java/com/google/gerrit/util/logging/JsonLayout.java b/java/com/google/gerrit/util/logging/JsonLayout.java
new file mode 100644
index 0000000..45fbd32
--- /dev/null
+++ b/java/com/google/gerrit/util/logging/JsonLayout.java
@@ -0,0 +1,72 @@
+// 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.gson.FieldNamingPolicy;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import org.apache.log4j.Layout;
+import org.apache.log4j.spi.LoggingEvent;
+
+public abstract class JsonLayout extends Layout {
+ private final DateTimeFormatter dateFormatter;
+ private final Gson gson;
+ private final ZoneOffset timeOffset;
+
+ public JsonLayout() {
+ dateFormatter = createDateTimeFormatter();
+ timeOffset = OffsetDateTime.now(ZoneId.systemDefault()).getOffset();
+
+ gson = newGson();
+ }
+
+ public abstract DateTimeFormatter createDateTimeFormatter();
+
+ public abstract JsonLogEntry toJsonLogEntry(LoggingEvent event);
+
+ @Override
+ public String format(LoggingEvent event) {
+ return gson.toJson(toJsonLogEntry(event)) + "\n";
+ }
+
+ private static Gson newGson() {
+ GsonBuilder gb =
+ new GsonBuilder()
+ .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
+ .disableHtmlEscaping();
+ return gb.create();
+ }
+
+ public String formatDate(long now) {
+ return ZonedDateTime.of(
+ LocalDateTime.ofInstant(Instant.ofEpochMilli(now), timeOffset), ZoneId.systemDefault())
+ .format(dateFormatter);
+ }
+
+ @Override
+ public void activateOptions() {}
+
+ @Override
+ public boolean ignoresThrowable() {
+ return false;
+ }
+}
diff --git a/java/com/google/gerrit/util/logging/JsonLogEntry.java b/java/com/google/gerrit/util/logging/JsonLogEntry.java
new file mode 100644
index 0000000..ceac427
--- /dev/null
+++ b/java/com/google/gerrit/util/logging/JsonLogEntry.java
@@ -0,0 +1,23 @@
+// 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 org.apache.log4j.spi.LoggingEvent;
+
+public abstract class JsonLogEntry {
+ public String getMdcString(LoggingEvent event, String key) {
+ return (String) event.getMDC(key);
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
index 625d0fb..e2d2501 100644
--- a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
@@ -130,7 +130,6 @@
import com.google.gerrit.server.index.account.AccountIndexer;
import com.google.gerrit.server.index.account.StalenessChecker;
import com.google.gerrit.server.notedb.Sequences;
-import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.project.ProjectConfig;
import com.google.gerrit.server.project.RefPattern;
@@ -213,7 +212,6 @@
@Inject private Sequences seq;
@Inject private StalenessChecker stalenessChecker;
@Inject private VersionedAuthorizedKeys.Accessor authorizedKeys;
- @Inject private PermissionBackend permissionBackend;
@Inject private ExtensionRegistry extensionRegistry;
@Inject private PluginSetContext<ExceptionHook> exceptionHooks;
@@ -859,7 +857,7 @@
gApi.changes().id(r.getChangeId()).abandon();
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
- assertThat(messages.get(0).rcpt()).containsExactly(user2.getEmailAddress());
+ assertThat(messages.get(0).rcpt()).containsExactly(user2.getNameEmail());
accountIndexedCounter.assertNoReindex();
}
}
@@ -885,7 +883,7 @@
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
Message message = messages.get(0);
- assertThat(message.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(message.rcpt()).containsExactly(user.getNameEmail());
assertMailReplyTo(message, admin.email());
accountIndexedCounter.assertNoReindex();
}
@@ -1842,7 +1840,7 @@
assertThat(sender.getMessages()).hasSize(1);
Message message = sender.getMessages().get(0);
- assertThat(message.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(message.rcpt()).containsExactly(user.getNameEmail());
assertThat(message.body()).contains("new SSH keys have been added");
// Delete key
@@ -1854,7 +1852,7 @@
assertThat(sender.getMessages()).hasSize(1);
message = sender.getMessages().get(0);
- assertThat(message.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(message.rcpt()).containsExactly(user.getNameEmail());
assertThat(message.body()).contains("SSH keys have been deleted");
}
}
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 0eefe02..9399c3b 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -1518,7 +1518,7 @@
assertThat(messages).hasSize(1);
Message m = messages.get(0);
assertThat(m.from().getName()).isEqualTo("Administrator (Code Review)");
- assertThat(m.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user.getNameEmail());
assertThat(m.body()).contains("I'd like you to do a code review");
assertThat(m.body()).contains("Change subject: " + PushOneCommit.SUBJECT + "\n");
assertMailReplyTo(m, admin.email());
@@ -1587,7 +1587,7 @@
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
Message m = messages.get(0);
- assertThat(m.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user.getNameEmail());
assertThat(m.body()).contains("Hello " + user.fullName() + ",\n");
assertThat(m.body()).contains("I'd like you to do a code review.");
assertThat(m.body()).contains("Change subject: " + PushOneCommit.SUBJECT + "\n");
@@ -1771,7 +1771,7 @@
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
Message m = messages.get(0);
- assertThat(m.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user.getNameEmail());
assertThat(m.body()).contains("Hello " + user.fullName() + ",\n");
assertThat(m.body()).contains("I'd like you to do a code review.");
assertThat(m.body()).contains("Change subject: " + PushOneCommit.SUBJECT + "\n");
@@ -2162,7 +2162,7 @@
assertThat(sender.getMessages()).hasSize(1);
Message m = sender.getMessages().get(0);
- assertThat(m.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user.getNameEmail());
}
@Test
@@ -2411,7 +2411,7 @@
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
Message msg = messages.get(0);
- assertThat(msg.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(msg.rcpt()).containsExactly(user.getNameEmail());
assertThat(msg.body()).contains(admin.fullName() + " has removed a vote from this change.");
assertThat(msg.body())
.contains("Removed Code-Review+1 by " + user.fullName() + " <" + user.email() + ">\n");
@@ -3065,7 +3065,7 @@
assertThat(commitPatchSetCreation.getShortMessage()).isEqualTo("Create patch set 2");
PersonIdent expectedAuthor =
- changeNoteUtil.newIdent(getAccount(admin.id()), c.updated, serverIdent.get());
+ changeNoteUtil.newIdent(getAccount(admin.id()).id(), c.updated, serverIdent.get());
assertThat(commitPatchSetCreation.getAuthorIdent()).isEqualTo(expectedAuthor);
assertThat(commitPatchSetCreation.getCommitterIdent())
.isEqualTo(new PersonIdent(serverIdent.get(), c.updated));
@@ -3074,7 +3074,7 @@
RevCommit commitChangeCreation = rw.parseCommit(commitPatchSetCreation.getParent(0));
assertThat(commitChangeCreation.getShortMessage()).isEqualTo("Create change");
expectedAuthor =
- changeNoteUtil.newIdent(getAccount(admin.id()), c.created, serverIdent.get());
+ changeNoteUtil.newIdent(getAccount(admin.id()).id(), c.created, serverIdent.get());
assertThat(commitChangeCreation.getAuthorIdent()).isEqualTo(expectedAuthor);
assertThat(commitChangeCreation.getCommitterIdent())
.isEqualTo(new PersonIdent(serverIdent.get(), c.created));
@@ -4527,7 +4527,7 @@
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
- assertThat(messages.get(0).rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(messages.get(0).rcpt()).containsExactly(user.getNameEmail());
}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java b/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
index 2801b36..72ab2e6 100644
--- a/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
@@ -41,7 +41,6 @@
import com.google.gerrit.acceptance.config.GerritConfig;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
-import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.Project;
@@ -1011,7 +1010,6 @@
}
}
- @Nullable
protected RevCommit getRemoteHead(String project, String branch) throws Exception {
return projectOperations.project(Project.nameKey(project)).getHead(branch);
}
diff --git a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
index 51dee72..4ee1f35 100644
--- a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
+++ b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -545,7 +545,7 @@
r.assertOkStatus();
assertThat(sender.getMessages()).hasSize(1);
Message m = sender.getMessages().get(0);
- assertThat(m.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user.getNameEmail());
sender.clear();
r = pushTo(pushSpec + ",notify=" + NotifyHandling.ALL);
@@ -553,7 +553,7 @@
assertThat(sender.getMessages()).hasSize(1);
m = sender.getMessages().get(0);
assertThat(m.rcpt())
- .containsExactly(user.getEmailAddress(), user2.getEmailAddress(), user3.getEmailAddress());
+ .containsExactly(user.getNameEmail(), user2.getNameEmail(), user3.getNameEmail());
sender.clear();
r = pushTo(pushSpec + ",notify=" + NotifyHandling.NONE + ",notify-to=" + user3.email());
@@ -1116,7 +1116,7 @@
assertThat(sender.getMessages()).hasSize(1);
assertThat(sender.getMessages().get(0).rcpt())
- .containsExactly(user.getEmailAddress(), user2.getEmailAddress());
+ .containsExactly(user.getNameEmail(), user2.getNameEmail());
}
@Test
@@ -1141,7 +1141,7 @@
assertThat(sender.getMessages()).hasSize(1);
assertThat(sender.getMessages().get(0).rcpt())
- .containsExactly(user.getEmailAddress(), user2.getEmailAddress());
+ .containsExactly(user.getNameEmail(), user2.getNameEmail());
}
/**
@@ -1838,7 +1838,7 @@
@Test
public void pushWithEmailInFooter() throws Exception {
- pushWithReviewerInFooter(user.getEmailAddress().toString(), user);
+ pushWithReviewerInFooter(user.getNameEmail().toString(), user);
}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java b/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java
index 56d9ff2..1083377 100644
--- a/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java
+++ b/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java
@@ -1071,7 +1071,7 @@
PersonIdent committer = serverIdent.get();
PersonIdent author =
- noteUtil.newIdent(getAccount(admin.id()), committer.getWhen(), committer);
+ noteUtil.newIdent(getAccount(admin.id()).id(), committer.getWhen(), committer);
tr.branch(RefNames.changeMetaRef(cd3.getId()))
.commit()
.author(author)
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/AssigneeIT.java b/javatests/com/google/gerrit/acceptance/rest/change/AssigneeIT.java
index 0f5def6..420ddda 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/AssigneeIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/AssigneeIT.java
@@ -61,7 +61,7 @@
assertThat(sender.getMessages()).hasSize(1);
Message m = sender.getMessages().get(0);
- assertThat(m.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user.getNameEmail());
}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/ChangeReviewersByEmailIT.java b/javatests/com/google/gerrit/acceptance/rest/change/ChangeReviewersByEmailIT.java
index ac00e38..090146e 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/ChangeReviewersByEmailIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/ChangeReviewersByEmailIT.java
@@ -209,7 +209,7 @@
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
assertThat(messages.get(0).rcpt())
- .containsExactly(Address.parse(addInput.reviewer), user.getEmailAddress());
+ .containsExactly(Address.parse(addInput.reviewer), user.getNameEmail());
sender.clear();
}
}
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/ChangeReviewersIT.java b/javatests/com/google/gerrit/acceptance/rest/change/ChangeReviewersIT.java
index fbe6533..0a006fa 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/ChangeReviewersIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/ChangeReviewersIT.java
@@ -150,7 +150,7 @@
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
Message m = messages.get(0);
- assertThat(m.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user.getNameEmail());
assertThat(m.body()).contains(admin.fullName() + " has uploaded this change for review.");
}
@@ -188,7 +188,7 @@
Message m = messages.get(0);
List<Address> expectedAddresses = new ArrayList<>(firstUsers.size());
for (TestAccount u : firstUsers) {
- expectedAddresses.add(u.getEmailAddress());
+ expectedAddresses.add(u.getNameEmail());
}
assertThat(m.rcpt()).containsExactlyElementsIn(expectedAddresses);
@@ -216,9 +216,9 @@
m = messages.get(0);
expectedAddresses = new ArrayList<>(4);
for (int i = 0; i < 3; i++) {
- expectedAddresses.add(users.get(users.size() - i - 1).getEmailAddress());
+ expectedAddresses.add(users.get(users.size() - i - 1).getNameEmail());
}
- expectedAddresses.add(reviewer.getEmailAddress());
+ expectedAddresses.add(reviewer.getNameEmail());
assertThat(m.rcpt()).containsExactlyElementsIn(expectedAddresses);
}
@@ -398,13 +398,13 @@
assertThat(messages).hasSize(2);
Message m = messages.get(0);
- assertThat(m.rcpt()).containsExactly(user.getEmailAddress(), observer.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user.getNameEmail(), observer.getNameEmail());
assertThat(m.body()).contains(admin.fullName() + " has posted comments on this change.");
assertThat(m.body()).contains("Change subject: " + PushOneCommit.SUBJECT + "\n");
assertThat(m.body()).contains("Patch Set 1: Code-Review+2");
m = messages.get(1);
- assertThat(m.rcpt()).containsExactly(user.getEmailAddress(), observer.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user.getNameEmail(), observer.getNameEmail());
assertThat(m.body()).contains("Hello " + user.fullName() + ",\n");
assertThat(m.body()).contains("I'd like you to do a code review.");
}
@@ -635,7 +635,7 @@
sender.clear();
gApi.changes().id(r.getChangeId()).current().review(reviewInput);
assertThat(sender.getMessages()).hasSize(1);
- assertThat(sender.getMessages().get(0).rcpt()).containsExactly(userToNotify.getEmailAddress());
+ assertThat(sender.getMessages().get(0).rcpt()).containsExactly(userToNotify.getNameEmail());
}
@Test
@@ -652,7 +652,7 @@
sender.clear();
gApi.changes().id(r.getChangeId()).addReviewer(addReviewer);
assertThat(sender.getMessages()).hasSize(1);
- assertThat(sender.getMessages().get(0).rcpt()).containsExactly(userToNotify.getEmailAddress());
+ assertThat(sender.getMessages().get(0).rcpt()).containsExactly(userToNotify.getNameEmail());
}
@Test
@@ -829,7 +829,7 @@
}
private void assertThatUserIsOnlyReviewer(String changeId) throws Exception {
- AccountInfo userInfo = new AccountInfo(user.fullName(), user.getEmailAddress().getEmail());
+ AccountInfo userInfo = new AccountInfo(user.fullName(), user.getNameEmail().getEmail());
userInfo._accountId = user.id().get();
userInfo.username = user.username();
assertThat(gApi.changes().id(changeId).get().reviewers)
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java b/javatests/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
index 0af1295..d831b62 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
@@ -216,7 +216,7 @@
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
Message m = messages.get(0);
- assertThat(m.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user.getNameEmail());
assertThat(m.body()).contains(admin.fullName() + " has uploaded this change for review.");
// check that watcher is not notified if notify=NONE
@@ -299,9 +299,11 @@
ChangeInfo info = assertCreateSucceeds(input);
RevisionApi rApi = gApi.changes().id(info.id).current();
- GitPerson person = rApi.commit(false).author;
- assertThat(person).email().isEqualTo(input.author.email);
- assertThat(person).name().isEqualTo(input.author.name);
+ GitPerson author = rApi.commit(false).author;
+ assertThat(author).email().isEqualTo(input.author.email);
+ assertThat(author).name().isEqualTo(input.author.name);
+ GitPerson committer = rApi.commit(false).committer;
+ assertThat(committer).email().isEqualTo(admin.getNameEmail().getEmail());
}
@Test
@@ -331,7 +333,19 @@
changeInTwoBranches("foo", "foo.txt", "bar", "bar.txt");
ChangeInput input = newChangeInput(ChangeStatus.NEW);
input.baseCommit = setup.get("master").getCommit().getId().name();
- assertCreateSucceeds(input);
+ ChangeInfo result = assertCreateSucceeds(input);
+ assertThat(gApi.changes().id(result.id).current().commit(false).parents.get(0).commit)
+ .isEqualTo(input.baseCommit);
+ }
+
+ @Test
+ public void createChangeWithParentChange() throws Exception {
+ Result change = createChange();
+ ChangeInput input = newChangeInput(ChangeStatus.NEW);
+ input.baseChange = change.getChangeId();
+ ChangeInfo result = assertCreateSucceeds(input);
+ assertThat(gApi.changes().id(result.id).current().commit(false).parents.get(0).commit)
+ .isEqualTo(change.getCommit().getId().name());
}
@Test
@@ -415,7 +429,7 @@
assertThat(commit.getShortMessage()).isEqualTo("Create change");
PersonIdent expectedAuthor =
- changeNoteUtil.newIdent(getAccount(admin.id()), c.created, serverIdent.get());
+ changeNoteUtil.newIdent(getAccount(admin.id()).id(), c.created, serverIdent.get());
assertThat(commit.getAuthorIdent()).isEqualTo(expectedAuthor);
assertThat(commit.getCommitterIdent())
@@ -437,6 +451,22 @@
}
@Test
+ public void createMergeChangeAuthor() throws Exception {
+ changeInTwoBranches("branchA", "a.txt", "branchB", "b.txt");
+ ChangeInput in = newMergeChangeInput("branchA", "branchB", "");
+ in.author = new AccountInput();
+ in.author.name = "Gerritless Jane";
+ in.author.email = "gerritlessjane@invalid";
+ ChangeInfo change = assertCreateSucceeds(in);
+
+ RevisionApi rApi = gApi.changes().id(change.id).current();
+ GitPerson author = rApi.commit(false).author;
+ assertThat(author).email().isEqualTo(in.author.email);
+ GitPerson committer = rApi.commit(false).committer;
+ assertThat(committer).email().isEqualTo(admin.getNameEmail().getEmail());
+ }
+
+ @Test
public void createMergeChange_Conflicts() throws Exception {
changeInTwoBranches("branchA", "shared.txt", "branchB", "shared.txt");
ChangeInput in = newMergeChangeInput("branchA", "branchB", "");
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/DeleteVoteIT.java b/javatests/com/google/gerrit/acceptance/rest/change/DeleteVoteIT.java
index 37fa2ce..25e5647 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/DeleteVoteIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/DeleteVoteIT.java
@@ -73,7 +73,7 @@
List<FakeEmailSender.Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
FakeEmailSender.Message msg = messages.get(0);
- assertThat(msg.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(msg.rcpt()).containsExactly(user.getNameEmail());
assertThat(msg.body()).contains(admin.fullName() + " has removed a vote from this change.");
assertThat(msg.body())
.contains("Removed Code-Review+1 by " + user.fullName() + " <" + user.email() + ">\n");
diff --git a/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java b/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java
index ba41d7e..b60cce5 100644
--- a/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java
@@ -81,10 +81,10 @@
public class CommentsIT extends AbstractDaemonTest {
@Inject private ChangeNoteUtil noteUtil;
@Inject private FakeEmailSender email;
+ @Inject private ProjectOperations projectOperations;
@Inject private Provider<ChangesCollection> changes;
@Inject private Provider<PostReview> postReview;
@Inject private RequestScopeOperations requestScopeOperations;
- @Inject ProjectOperations projectOperations;
private final Integer[] lines = {0, 1};
@@ -387,6 +387,39 @@
assertThat(list.stream().map(infoToInput(file))).containsExactlyElementsIn(expectedComments);
}
+ /**
+ * This test makes sure that the commits in the refs/draft-comments ref in NoteDb have no parent
+ * commits. This is important so that each new draft update (add, modify, delete) does not keep
+ * track of previous history.
+ */
+ @Test
+ public void commitsInDraftCommentsRefHaveNoParent() throws Exception {
+ PushOneCommit.Result r = createChange();
+ String changeId = r.getChangeId();
+ String revId = r.getCommit().getName();
+ String draftRefName = RefNames.refsDraftComments(r.getChange().getId(), user.id());
+
+ DraftInput comment1 = newDraft("file_1", Side.REVISION, 1, "comment 1");
+ CommentInfo commentInfo1 = addDraft(changeId, revId, comment1);
+ assertThat(getHeadOfDraftCommentsRef(draftRefName).getParentCount()).isEqualTo(0);
+
+ DraftInput comment2 = newDraft("file_2", Side.REVISION, 2, "comment 2");
+ CommentInfo commentInfo2 = addDraft(changeId, revId, comment2);
+ assertThat(getHeadOfDraftCommentsRef(draftRefName).getParentCount()).isEqualTo(0);
+
+ deleteDraft(changeId, revId, commentInfo1.id);
+ assertThat(getHeadOfDraftCommentsRef(draftRefName).getParentCount()).isEqualTo(0);
+ assertThat(
+ getDraftComments(changeId, revId).values().stream()
+ .flatMap(List::stream)
+ .map(commentInfo -> commentInfo.message))
+ .containsExactly("comment 2");
+
+ deleteDraft(changeId, revId, commentInfo2.id);
+ assertThat(projectOperations.project(allUsers).hasHead(draftRefName)).isFalse();
+ assertThat(getDraftComments(changeId, revId).values().stream().flatMap(List::stream)).isEmpty();
+ }
+
@Test
public void putDraft() throws Exception {
for (Integer line : lines) {
@@ -1112,6 +1145,12 @@
}
}
+ private RevCommit getHeadOfDraftCommentsRef(String refName) throws Exception {
+ try (Repository repo = repoManager.openRepository(allUsers)) {
+ return getHead(repo, refName);
+ }
+ }
+
private static String extractComments(String msg) {
// Extract lines between start "....." and end "-- ".
Pattern p = Pattern.compile(".*[.]{5}\n+(.*)\\n+-- \n.*", Pattern.DOTALL);
diff --git a/javatests/com/google/gerrit/acceptance/server/change/ConsistencyCheckerIT.java b/javatests/com/google/gerrit/acceptance/server/change/ConsistencyCheckerIT.java
index ee5f117..069387c 100644
--- a/javatests/com/google/gerrit/acceptance/server/change/ConsistencyCheckerIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/change/ConsistencyCheckerIT.java
@@ -830,7 +830,8 @@
private void addNoteDbCommit(Change.Id id, String commitMessage) throws Exception {
PersonIdent committer = serverIdent.get();
- PersonIdent author = noteUtil.newIdent(getAccount(admin.id()), committer.getWhen(), committer);
+ PersonIdent author =
+ noteUtil.newIdent(getAccount(admin.id()).id(), committer.getWhen(), committer);
serverSideTestRepo
.branch(RefNames.changeMetaRef(id))
.commit()
diff --git a/javatests/com/google/gerrit/acceptance/server/mail/AbstractMailIT.java b/javatests/com/google/gerrit/acceptance/server/mail/AbstractMailIT.java
index 3b0e27b..9e0de92 100644
--- a/javatests/com/google/gerrit/acceptance/server/mail/AbstractMailIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/mail/AbstractMailIT.java
@@ -38,8 +38,8 @@
MailMessage.Builder messageBuilderWithDefaultFields() {
MailMessage.Builder b = MailMessage.builder();
b.id("some id");
- b.from(user.getEmailAddress());
- b.addTo(user.getEmailAddress()); // Not evaluated
+ b.from(user.getNameEmail());
+ b.addTo(user.getNameEmail()); // Not evaluated
b.subject("");
b.dateReceived(Instant.now());
return b;
diff --git a/javatests/com/google/gerrit/acceptance/server/mail/ChangeNotificationsIT.java b/javatests/com/google/gerrit/acceptance/server/mail/ChangeNotificationsIT.java
index ae92bea..2dc1e24 100644
--- a/javatests/com/google/gerrit/acceptance/server/mail/ChangeNotificationsIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/mail/ChangeNotificationsIT.java
@@ -104,7 +104,7 @@
assertThat(sender)
.sent("abandon", sc)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ABANDONED_CHANGES)
.noOneElse();
@@ -119,7 +119,7 @@
.sent("abandon", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ABANDONED_CHANGES)
.noOneElse();
@@ -135,7 +135,7 @@
.sent("abandon", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ABANDONED_CHANGES)
.noOneElse();
@@ -151,7 +151,7 @@
.sent("abandon", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer, other)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ABANDONED_CHANGES)
.noOneElse();
@@ -165,7 +165,7 @@
assertThat(sender)
.sent("abandon", sc)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -217,7 +217,7 @@
assertThat(sender)
.sent("abandon", sc)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ABANDONED_CHANGES)
.noOneElse();
@@ -238,7 +238,7 @@
assertThat(sender)
.sent("abandon", sc)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ABANDONED_CHANGES)
.noOneElse();
@@ -284,7 +284,7 @@
.sent("newchange", sc)
.to(reviewer)
.cc(sc.reviewer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -308,7 +308,7 @@
.sent("newchange", sc)
.to(reviewer)
.cc(sc.owner, sc.reviewer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -333,7 +333,7 @@
.sent("newchange", sc)
.to(reviewer)
.cc(sc.owner, sc.reviewer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -358,7 +358,7 @@
.sent("newchange", sc)
.to(reviewer)
.cc(sc.owner, sc.reviewer, other)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -382,7 +382,7 @@
.sent("newchange", sc)
.to(email)
.cc(sc.reviewer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -438,7 +438,7 @@
.sent("newchange", sc)
.to(reviewer)
.cc(sc.reviewer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
}
@@ -451,7 +451,7 @@
.sent("newchange", sc)
.to(reviewer)
.cc(sc.reviewer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -475,7 +475,7 @@
.sent("newchange", sc)
.to(reviewer)
.cc(sc.reviewer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -533,7 +533,7 @@
.sent("newchange", sc)
.to("nonexistent@example.com")
.cc(sc.reviewer)
- .cc(sc.ccerByEmail, sc.reviewerByEmail)
+ .cc(StagedUsers.CC_BY_EMAIL, StagedUsers.REVIEWER_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -555,7 +555,7 @@
.sent("newchange", sc)
.cc("nonexistent@example.com")
.cc(sc.reviewer)
- .cc(sc.ccerByEmail, sc.reviewerByEmail)
+ .cc(StagedUsers.CC_BY_EMAIL, StagedUsers.REVIEWER_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -641,7 +641,7 @@
assertThat(sender)
.sent("comment", sc)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -656,7 +656,7 @@
.sent("comment", sc)
.to(sc.owner)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -671,7 +671,7 @@
.sent("comment", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -686,7 +686,7 @@
.sent("comment", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -702,7 +702,7 @@
.sent("comment", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -718,7 +718,7 @@
.sent("comment", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer, other)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -732,7 +732,7 @@
assertThat(sender)
.sent("comment", sc)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -776,7 +776,7 @@
.sent("comment", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -802,7 +802,7 @@
assertThat(sender)
.sent("comment", sc)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -836,7 +836,7 @@
.sent("comment", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -850,7 +850,7 @@
assertThat(sender)
.sent("comment", sc)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -873,7 +873,7 @@
assertThat(sender)
.sent("comment", sc)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -888,7 +888,7 @@
assertThat(sender)
.sent("comment", sc)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -903,7 +903,7 @@
assertThat(sender)
.sent("comment", sc)
.cc(sc.reviewer, sc.ccer, other)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -912,7 +912,7 @@
.sent("newchange", sc)
.to(other)
.cc(sc.reviewer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -1082,7 +1082,7 @@
.sent("deleteReviewer", sc)
.to(extraReviewer)
.cc(extraCcer, sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -1098,7 +1098,7 @@
.sent("deleteReviewer", sc)
.to(sc.owner, extraReviewer)
.cc(extraCcer, sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -1114,7 +1114,7 @@
.sent("deleteReviewer", sc)
.to(sc.owner, extraReviewer)
.cc(extraCcer, sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -1131,7 +1131,7 @@
.sent("deleteReviewer", sc)
.to(sc.owner, extraReviewer)
.cc(admin, extraCcer, sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -1147,7 +1147,7 @@
.sent("deleteReviewer", sc)
.to(extraCcer)
.cc(sc.reviewer, sc.ccer, extraReviewer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -1163,7 +1163,7 @@
.sent("deleteReviewer", sc)
.to(extraReviewer)
.cc(extraCcer, sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -1222,7 +1222,7 @@
.sent("deleteReviewer", sc)
.to(extraReviewer)
.cc(extraCcer, sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -1250,7 +1250,7 @@
@Test
public void deleteReviewerByEmailFromWipChange() throws Exception {
StagedChange sc = stageWipChangeWithExtraReviewer();
- gApi.changes().id(sc.changeId).reviewer(sc.reviewerByEmail).remove();
+ gApi.changes().id(sc.changeId).reviewer(StagedUsers.REVIEWER_BY_EMAIL).remove();
assertThat(sender).didNotSend();
}
@@ -1317,7 +1317,7 @@
assertThat(sender)
.sent("deleteVote", sc)
.cc(sc.reviewer, sc.ccer, extraReviewer, extraCcer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -1335,7 +1335,7 @@
.sent("deleteVote", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer, extraReviewer, extraCcer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -1352,7 +1352,7 @@
.sent("deleteVote", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer, extraReviewer, extraCcer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -1370,7 +1370,7 @@
.sent("deleteVote", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer, admin, extraReviewer, extraCcer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -1386,7 +1386,7 @@
assertThat(sender)
.sent("deleteVote", sc)
.cc(sc.reviewer, sc.ccer, extraReviewer, extraCcer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -1402,7 +1402,7 @@
.sent("deleteVote", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer, extraReviewer, extraCcer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -1445,7 +1445,7 @@
assertThat(sender)
.sent("deleteVote", sc)
.cc(sc.reviewer, sc.ccer, extraReviewer, extraCcer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -1461,7 +1461,7 @@
assertThat(sender)
.sent("deleteVote", sc)
.cc(sc.reviewer, sc.ccer, extraReviewer, extraCcer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -1524,7 +1524,7 @@
.that(sender)
.sent("merged", sc)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS, SUBMITTED_CHANGES)
.noOneElse();
@@ -1540,7 +1540,7 @@
.sent("merged", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS, SUBMITTED_CHANGES)
.noOneElse();
@@ -1555,7 +1555,7 @@
.sent("merged", sc)
.to(sc.owner)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS, SUBMITTED_CHANGES)
.noOneElse();
@@ -1570,7 +1570,7 @@
.sent("merged", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS, SUBMITTED_CHANGES)
.noOneElse();
@@ -1585,7 +1585,7 @@
.sent("merged", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -1667,7 +1667,7 @@
.sent("newpatchset", sc)
.to(sc.reviewer)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(NEW_PATCHSETS)
.noOneElse();
@@ -1683,7 +1683,7 @@
.notTo(sc.owner) // TODO(logan): This shouldn't be sent *from* the owner.
.to(sc.reviewer, other)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(NEW_PATCHSETS)
.noOneElse();
@@ -1699,7 +1699,7 @@
.notTo(sc.owner) // TODO(logan): This shouldn't be sent *from* the owner.
.to(sc.reviewer, other)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(NEW_PATCHSETS)
.noOneElse();
@@ -1716,7 +1716,7 @@
.to(sc.reviewer)
.to(other)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -1732,7 +1732,7 @@
.to(sc.reviewer)
.to(other)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -1791,7 +1791,7 @@
.sent("newpatchset", sc)
.to(sc.reviewer)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(NEW_PATCHSETS)
.noOneElse();
@@ -1806,7 +1806,7 @@
.sent("newpatchset", sc)
.to(sc.reviewer)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(NEW_PATCHSETS)
.noOneElse();
@@ -1829,7 +1829,7 @@
.sent("newpatchset", sc)
.to(sc.reviewer, newReviewer)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(NEW_PATCHSETS)
.noOneElse();
@@ -1853,7 +1853,7 @@
.sent("newpatchset", sc)
.to(sc.reviewer, newReviewer)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(NEW_PATCHSETS)
.noOneElse();
@@ -1868,7 +1868,7 @@
.sent("newpatchset", sc)
.to(sc.reviewer)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(NEW_PATCHSETS)
.noOneElse();
@@ -1893,7 +1893,7 @@
.sent("newpatchset", sc)
.to(sc.reviewer)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(NEW_PATCHSETS)
.noOneElse();
@@ -1908,7 +1908,7 @@
.sent("newpatchset", sc)
.to(sc.owner, sc.reviewer)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(NEW_PATCHSETS)
.noOneElse();
@@ -1923,7 +1923,7 @@
.sent("newpatchset", sc)
.to(sc.owner, sc.reviewer, other)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(NEW_PATCHSETS)
.noOneElse();
@@ -1938,7 +1938,7 @@
.sent("newpatchset", sc)
.to(sc.owner, sc.reviewer)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -1952,7 +1952,7 @@
.sent("newpatchset", sc)
.to(sc.owner, sc.reviewer)
.cc(sc.ccer, other)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -2018,7 +2018,7 @@
.sent("newpatchset", sc)
.to(sc.reviewer)
.cc(sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(NEW_PATCHSETS)
.noOneElse();
@@ -2061,7 +2061,7 @@
assertThat(sender)
.sent("restore", sc)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -2075,7 +2075,7 @@
assertThat(sender)
.sent("restore", sc)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -2089,7 +2089,7 @@
assertThat(sender)
.sent("restore", sc)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -2104,7 +2104,7 @@
.sent("restore", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -2119,7 +2119,7 @@
.sent("restore", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -2134,7 +2134,7 @@
.sent("restore", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer, admin)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -2173,7 +2173,7 @@
assertThat(sender)
.sent("revert", sc)
.cc(sc.reviewer, sc.ccer, admin)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -2198,7 +2198,7 @@
.sent("revert", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer, admin)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -2223,7 +2223,7 @@
.sent("revert", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer, admin)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -2248,7 +2248,7 @@
.sent("revert", sc)
.to(sc.owner)
.cc(other, sc.reviewer, sc.ccer, admin)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -2285,7 +2285,9 @@
assign(sc, sc.owner, sc.assignee);
assertThat(sender)
.sent("setassignee", sc)
- .cc(sc.reviewerByEmail, sc.ccerByEmail) // TODO(logan): This is probably not intended!
+ .cc(
+ StagedUsers.REVIEWER_BY_EMAIL,
+ StagedUsers.CC_BY_EMAIL) // TODO(logan): This is probably not intended!
.to(sc.assignee)
.noOneElse();
assertThat(sender).didNotSend();
@@ -2298,7 +2300,9 @@
assertThat(sender)
.sent("setassignee", sc)
.cc(sc.owner)
- .cc(sc.reviewerByEmail, sc.ccerByEmail) // TODO(logan): This is probably not intended!
+ .cc(
+ StagedUsers.REVIEWER_BY_EMAIL,
+ StagedUsers.CC_BY_EMAIL) // TODO(logan): This is probably not intended!
.to(sc.assignee)
.noOneElse();
assertThat(sender).didNotSend();
@@ -2310,7 +2314,9 @@
assign(sc, admin, sc.assignee);
assertThat(sender)
.sent("setassignee", sc)
- .cc(sc.reviewerByEmail, sc.ccerByEmail) // TODO(logan): This is probably not intended!
+ .cc(
+ StagedUsers.REVIEWER_BY_EMAIL,
+ StagedUsers.CC_BY_EMAIL) // TODO(logan): This is probably not intended!
.to(sc.assignee)
.noOneElse();
assertThat(sender).didNotSend();
@@ -2323,7 +2329,9 @@
assertThat(sender)
.sent("setassignee", sc)
.cc(admin)
- .cc(sc.reviewerByEmail, sc.ccerByEmail) // TODO(logan): This is probably not intended!
+ .cc(
+ StagedUsers.REVIEWER_BY_EMAIL,
+ StagedUsers.CC_BY_EMAIL) // TODO(logan): This is probably not intended!
.to(sc.assignee)
.noOneElse();
assertThat(sender).didNotSend();
@@ -2335,7 +2343,9 @@
assign(sc, sc.owner, sc.owner);
assertThat(sender)
.sent("setassignee", sc)
- .cc(sc.reviewerByEmail, sc.ccerByEmail) // TODO(logan): This is probably not intended!
+ .cc(
+ StagedUsers.REVIEWER_BY_EMAIL,
+ StagedUsers.CC_BY_EMAIL) // TODO(logan): This is probably not intended!
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -2349,7 +2359,9 @@
assign(sc, sc.owner, sc.assignee);
assertThat(sender)
.sent("setassignee", sc)
- .cc(sc.reviewerByEmail, sc.ccerByEmail) // TODO(logan): This is probably not intended!
+ .cc(
+ StagedUsers.REVIEWER_BY_EMAIL,
+ StagedUsers.CC_BY_EMAIL) // TODO(logan): This is probably not intended!
.to(sc.assignee)
.noOneElse();
assertThat(sender).didNotSend();
@@ -2363,7 +2375,9 @@
assign(sc, sc.owner, sc.owner);
assertThat(sender)
.sent("setassignee", sc)
- .cc(sc.reviewerByEmail, sc.ccerByEmail) // TODO(logan): This is probably not intended!
+ .cc(
+ StagedUsers.REVIEWER_BY_EMAIL,
+ StagedUsers.CC_BY_EMAIL) // TODO(logan): This is probably not intended!
.noOneElse();
assertThat(sender).didNotSend();
}
@@ -2374,7 +2388,9 @@
assign(sc, sc.owner, sc.assignee);
assertThat(sender)
.sent("setassignee", sc)
- .cc(sc.reviewerByEmail, sc.ccerByEmail) // TODO(logan): This is probably not intended!
+ .cc(
+ StagedUsers.REVIEWER_BY_EMAIL,
+ StagedUsers.CC_BY_EMAIL) // TODO(logan): This is probably not intended!
.to(sc.assignee)
.noOneElse();
assertThat(sender).didNotSend();
@@ -2386,7 +2402,9 @@
assign(sc, sc.owner, sc.assignee);
assertThat(sender)
.sent("setassignee", sc)
- .cc(sc.reviewerByEmail, sc.ccerByEmail) // TODO(logan): This is probably not intended!
+ .cc(
+ StagedUsers.REVIEWER_BY_EMAIL,
+ StagedUsers.CC_BY_EMAIL) // TODO(logan): This is probably not intended!
.to(sc.assignee)
.noOneElse();
assertThat(sender).didNotSend();
@@ -2416,7 +2434,7 @@
assertThat(sender)
.sent("comment", sc)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
@@ -2432,7 +2450,7 @@
.sent("comment", sc)
.to(sc.owner)
.cc(sc.reviewer, sc.ccer)
- .cc(sc.reviewerByEmail, sc.ccerByEmail)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
.bcc(sc.starrer)
.bcc(ALL_COMMENTS)
.noOneElse();
diff --git a/javatests/com/google/gerrit/acceptance/server/mail/MailProcessorIT.java b/javatests/com/google/gerrit/acceptance/server/mail/MailProcessorIT.java
index 502194a..49f25e4 100644
--- a/javatests/com/google/gerrit/acceptance/server/mail/MailProcessorIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/mail/MailProcessorIT.java
@@ -237,7 +237,7 @@
newPlaintextBody(getChangeUrl(changeInfo) + "/1", "Test Message", null, null, null);
MailMessage.Builder b =
messageBuilderWithDefaultFields()
- .from(user.getEmailAddress())
+ .from(user.getNameEmail())
.textContent(txt + textFooterForChange(changeInfo._number, ts));
sender.clear();
@@ -259,7 +259,7 @@
newPlaintextBody(getChangeUrl(changeInfo) + "/1", "Test Message", null, null, null);
MailMessage.Builder b =
messageBuilderWithDefaultFields()
- .from(user.getEmailAddress())
+ .from(user.getNameEmail())
.textContent(txt + textFooterForChange(changeInfo._number, ts));
sender.clear();
diff --git a/javatests/com/google/gerrit/acceptance/server/project/ProjectWatchIT.java b/javatests/com/google/gerrit/acceptance/server/project/ProjectWatchIT.java
index 29574c4..8b12b9d 100644
--- a/javatests/com/google/gerrit/acceptance/server/project/ProjectWatchIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/project/ProjectWatchIT.java
@@ -241,7 +241,7 @@
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
Message m = messages.get(0);
- assertThat(m.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user.getNameEmail());
assertThat(m.body()).contains("Change subject: TRIGGER\n");
assertThat(m.body()).contains("Gerrit-PatchSet: 1\n");
}
@@ -273,7 +273,7 @@
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
Message m = messages.get(0);
- assertThat(m.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user.getNameEmail());
assertThat(m.body()).contains("Change subject: TRIGGER\n");
assertThat(m.body()).contains("Gerrit-PatchSet: 1\n");
sender.clear();
@@ -295,7 +295,7 @@
messages = sender.getMessages();
assertThat(messages).hasSize(1);
m = messages.get(0);
- assertThat(m.rcpt()).containsExactly(user2.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user2.getNameEmail());
assertThat(m.body()).contains("Change subject: TRIGGER_USER2\n");
assertThat(m.body()).contains("Gerrit-PatchSet: 1\n");
}
@@ -322,7 +322,7 @@
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
Message m = messages.get(0);
- assertThat(m.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user.getNameEmail());
assertThat(m.body()).contains("Change subject: Document multiprimary setup\n");
assertThat(m.body()).contains("Gerrit-PatchSet: 1\n");
sender.clear();
@@ -357,7 +357,7 @@
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
Message m = messages.get(0);
- assertThat(m.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user.getNameEmail());
assertThat(m.body()).contains("Change subject: TRIGGER\n");
assertThat(m.body()).contains("Gerrit-PatchSet: 1\n");
}
@@ -385,7 +385,7 @@
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
Message m = messages.get(0);
- assertThat(m.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user.getNameEmail());
assertThat(m.body()).contains("Change subject: TRIGGER\n");
assertThat(m.body()).contains("Gerrit-PatchSet: 1\n");
sender.clear();
@@ -407,7 +407,7 @@
messages = sender.getMessages();
assertThat(messages).hasSize(1);
m = messages.get(0);
- assertThat(m.rcpt()).containsExactly(user2.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user2.getNameEmail());
assertThat(m.body()).contains("Change subject: TRIGGER_USER2\n");
assertThat(m.body()).contains("Gerrit-PatchSet: 1\n");
}
@@ -434,7 +434,7 @@
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
Message m = messages.get(0);
- assertThat(m.rcpt()).containsExactly(user.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(user.getNameEmail());
assertThat(m.body()).contains("Change subject: Document multiprimary setup\n");
assertThat(m.body()).contains("Gerrit-PatchSet: 1\n");
sender.clear();
@@ -547,7 +547,7 @@
List<Message> messages = sender.getMessages();
assertThat(messages).hasSize(1);
Message m = messages.get(0);
- assertThat(m.rcpt()).containsExactly(userThatCanViewPrivateChanges.getEmailAddress());
+ assertThat(m.rcpt()).containsExactly(userThatCanViewPrivateChanges.getNameEmail());
assertThat(m.body()).contains("Change subject: TRIGGER\n");
assertThat(m.body()).contains("Gerrit-PatchSet: 1\n");
}
diff --git a/javatests/com/google/gerrit/pgm/BUILD b/javatests/com/google/gerrit/pgm/BUILD
index b68aacc..5a3a824 100644
--- a/javatests/com/google/gerrit/pgm/BUILD
+++ b/javatests/com/google/gerrit/pgm/BUILD
@@ -5,7 +5,6 @@
name = "pgm_tests",
srcs = glob(["**/*.java"]),
deps = [
- "//java/com/google/gerrit/pgm/http/jetty",
"//java/com/google/gerrit/pgm/init/api",
"//java/com/google/gerrit/server",
"//java/com/google/gerrit/server/securestore/testing",
diff --git a/javatests/com/google/gerrit/server/notedb/ChangeNotesParserTest.java b/javatests/com/google/gerrit/server/notedb/ChangeNotesParserTest.java
index 013939a..8ffcc8b 100644
--- a/javatests/com/google/gerrit/server/notedb/ChangeNotesParserTest.java
+++ b/javatests/com/google/gerrit/server/notedb/ChangeNotesParserTest.java
@@ -518,7 +518,9 @@
private RevCommit writeCommit(String body) throws Exception {
ChangeNoteUtil noteUtil = injector.getInstance(ChangeNoteUtil.class);
return writeCommit(
- body, noteUtil.newIdent(changeOwner.getAccount(), TimeUtil.nowTs(), serverIdent), false);
+ body,
+ noteUtil.newIdent(changeOwner.getAccount().id(), TimeUtil.nowTs(), serverIdent),
+ false);
}
private RevCommit writeCommit(String body, PersonIdent author) throws Exception {
@@ -529,7 +531,7 @@
ChangeNoteUtil noteUtil = injector.getInstance(ChangeNoteUtil.class);
return writeCommit(
body,
- noteUtil.newIdent(changeOwner.getAccount(), TimeUtil.nowTs(), serverIdent),
+ noteUtil.newIdent(changeOwner.getAccount().id(), TimeUtil.nowTs(), serverIdent),
initWorkInProgress);
}
diff --git a/javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java b/javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java
index 16981dc..68c7883 100644
--- a/javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java
+++ b/javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java
@@ -28,6 +28,7 @@
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.common.data.SubmitRequirement;
import com.google.gerrit.entities.Account;
+import com.google.gerrit.entities.AttentionStatus;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.ChangeMessage;
import com.google.gerrit.entities.Comment;
@@ -44,6 +45,7 @@
import com.google.gerrit.server.ReviewerStatusUpdate;
import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto;
import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto.AssigneeStatusUpdateProto;
+import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto.AttentionStatusProto;
import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto.ChangeColumnsProto;
import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto.ReviewerByEmailSetEntryProto;
import com.google.gerrit.server.cache.proto.Cache.ChangeNotesStateProto.ReviewerSetEntryProto;
@@ -55,6 +57,7 @@
import com.google.protobuf.ByteString;
import java.lang.reflect.Type;
import java.sql.Timestamp;
+import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -64,6 +67,7 @@
import org.junit.Test;
public class ChangeNotesStateTest {
+
private static final Change.Id ID = Change.id(123);
private static final ObjectId SHA =
ObjectId.fromString("1234567812345678123456781234567812345678");
@@ -95,6 +99,13 @@
return ChangeNotesState.Builder.empty(ID).metaId(SHA).columns(cols);
}
+ private ChangeNotesStateProto.Builder newProtoBuilder() {
+ return ChangeNotesStateProto.newBuilder()
+ .setMetaId(SHA_BYTES)
+ .setChangeId(ID.get())
+ .setColumns(colsProto);
+ }
+
@Test
public void serializeChangeKey() throws Exception {
assertRoundTrip(
@@ -589,6 +600,39 @@
}
@Test
+ public void serializeAttentionUpdates() throws Exception {
+ assertRoundTrip(
+ newBuilder()
+ .attentionUpdates(
+ ImmutableList.of(
+ AttentionStatus.createFromRead(
+ Instant.EPOCH.plusSeconds(23),
+ Account.id(1000),
+ AttentionStatus.Operation.ADD,
+ "reason 1"),
+ AttentionStatus.createFromRead(
+ Instant.EPOCH.plusSeconds(42),
+ Account.id(2000),
+ AttentionStatus.Operation.REMOVE,
+ "reason 2")))
+ .build(),
+ newProtoBuilder()
+ .addAttentionStatus(
+ AttentionStatusProto.newBuilder()
+ .setDate(23_000) // epoch millis
+ .setAccount(1000)
+ .setOperation("ADD")
+ .setReason("reason 1"))
+ .addAttentionStatus(
+ AttentionStatusProto.newBuilder()
+ .setDate(42_000) // epoch millis
+ .setAccount(2000)
+ .setOperation("REMOVE")
+ .setReason("reason 2"))
+ .build());
+ }
+
+ @Test
public void serializeAssigneeUpdates() throws Exception {
assertRoundTrip(
newBuilder()
@@ -745,6 +789,9 @@
"reviewerUpdates",
new TypeLiteral<ImmutableList<ReviewerStatusUpdate>>() {}.getType())
.put(
+ "attentionUpdates",
+ new TypeLiteral<ImmutableList<AttentionStatus>>() {}.getType())
+ .put(
"assigneeUpdates",
new TypeLiteral<ImmutableList<AssigneeStatusUpdate>>() {}.getType())
.put("submitRecords", new TypeLiteral<ImmutableList<SubmitRecord>>() {}.getType())
@@ -824,10 +871,10 @@
.hasFields(
ImmutableMap.of(
"table",
- new TypeLiteral<
- ImmutableTable<
- ReviewerStateInternal, Account.Id, Timestamp>>() {}.getType(),
- "accounts", new TypeLiteral<ImmutableSet<Account.Id>>() {}.getType()));
+ new TypeLiteral<
+ ImmutableTable<ReviewerStateInternal, Account.Id, Timestamp>>() {}.getType(),
+ "accounts",
+ new TypeLiteral<ImmutableSet<Account.Id>>() {}.getType()));
}
@Test
@@ -836,9 +883,10 @@
.hasFields(
ImmutableMap.of(
"table",
- new TypeLiteral<
- ImmutableTable<ReviewerStateInternal, Address, Timestamp>>() {}.getType(),
- "users", new TypeLiteral<ImmutableSet<Address>>() {}.getType()));
+ new TypeLiteral<
+ ImmutableTable<ReviewerStateInternal, Address, Timestamp>>() {}.getType(),
+ "users",
+ new TypeLiteral<ImmutableSet<Address>>() {}.getType()));
}
@Test
diff --git a/javatests/com/google/gerrit/server/notedb/ChangeNotesTest.java b/javatests/com/google/gerrit/server/notedb/ChangeNotesTest.java
index db0dec8..4e068ba 100644
--- a/javatests/com/google/gerrit/server/notedb/ChangeNotesTest.java
+++ b/javatests/com/google/gerrit/server/notedb/ChangeNotesTest.java
@@ -38,6 +38,8 @@
import com.google.common.collect.Lists;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.entities.Account;
+import com.google.gerrit.entities.AttentionStatus;
+import com.google.gerrit.entities.AttentionStatus.Operation;
import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.ChangeMessage;
@@ -58,6 +60,7 @@
import com.google.gerrit.testing.TestChanges;
import com.google.inject.Inject;
import java.sql.Timestamp;
+import java.time.Instant;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -688,6 +691,92 @@
}
@Test
+ public void defaultAttentionSetIsEmpty() throws Exception {
+ Change c = newChange();
+ ChangeNotes notes = newNotes(c);
+ assertThat(notes.getAttentionUpdates()).isEmpty();
+ }
+
+ @Test
+ public void addAttentionStatus() throws Exception {
+ Change c = newChange();
+ ChangeUpdate update = newUpdate(c, changeOwner);
+ AttentionStatus attentionStatus =
+ AttentionStatus.createForWrite(changeOwner.getAccountId(), Operation.ADD, "test");
+ update.setAttentionUpdates(ImmutableList.of(attentionStatus));
+ update.commit();
+
+ ChangeNotes notes = newNotes(c);
+ assertThat(notes.getAttentionUpdates()).containsExactly(addTimestamp(attentionStatus, c));
+ }
+
+ @Test
+ public void filterLatestAttentionStatus() throws Exception {
+ Change c = newChange();
+ ChangeUpdate update = newUpdate(c, changeOwner);
+ AttentionStatus attentionStatus =
+ AttentionStatus.createForWrite(changeOwner.getAccountId(), Operation.ADD, "test");
+ update.setAttentionUpdates(ImmutableList.of(attentionStatus));
+ update.commit();
+ update = newUpdate(c, changeOwner);
+ attentionStatus =
+ AttentionStatus.createForWrite(changeOwner.getAccountId(), Operation.REMOVE, "test");
+ update.setAttentionUpdates(ImmutableList.of(attentionStatus));
+ update.commit();
+
+ ChangeNotes notes = newNotes(c);
+ assertThat(notes.getAttentionUpdates()).containsExactly(addTimestamp(attentionStatus, c));
+ }
+
+ @Test
+ public void addAttentionStatus_rejectTimestamp() throws Exception {
+ Change c = newChange();
+ ChangeUpdate update = newUpdate(c, changeOwner);
+ AttentionStatus attentionStatus =
+ AttentionStatus.createFromRead(
+ Instant.now(), changeOwner.getAccountId(), Operation.ADD, "test");
+ IllegalArgumentException thrown =
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> update.setAttentionUpdates(ImmutableList.of(attentionStatus)));
+ assertThat(thrown).hasMessageThat().contains("must not specify timestamp for write");
+ }
+
+ @Test
+ public void addAttentionStatus_rejectMultiplePerUser() throws Exception {
+ Change c = newChange();
+ ChangeUpdate update = newUpdate(c, changeOwner);
+ AttentionStatus attentionStatus0 =
+ AttentionStatus.createForWrite(changeOwner.getAccountId(), Operation.ADD, "test 0");
+ AttentionStatus attentionStatus1 =
+ AttentionStatus.createForWrite(changeOwner.getAccountId(), Operation.ADD, "test 1");
+ IllegalArgumentException thrown =
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> update.setAttentionUpdates(ImmutableList.of(attentionStatus0, attentionStatus1)));
+ assertThat(thrown)
+ .hasMessageThat()
+ .contains("must not specify multiple updates for single user");
+ }
+
+ @Test
+ public void addAttentionStatusForMultipleUsers() throws Exception {
+ Change c = newChange();
+ ChangeUpdate update = newUpdate(c, changeOwner);
+ AttentionStatus attentionStatus0 =
+ AttentionStatus.createForWrite(changeOwner.getAccountId(), Operation.ADD, "test");
+ AttentionStatus attentionStatus1 =
+ AttentionStatus.createForWrite(otherUser.getAccountId(), Operation.ADD, "test");
+
+ update.setAttentionUpdates(ImmutableList.of(attentionStatus0, attentionStatus1));
+ update.commit();
+
+ ChangeNotes notes = newNotes(c);
+ assertThat(notes.getAttentionUpdates())
+ .containsExactly(addTimestamp(attentionStatus0, c), addTimestamp(attentionStatus1, c));
+ }
+
+ @Test
public void assigneeCommit() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
@@ -3140,4 +3229,13 @@
update.commit();
return tr.parseBody(commit);
}
+
+ private AttentionStatus addTimestamp(AttentionStatus attentionStatus, Change c) {
+ Timestamp timestamp = newNotes(c).getChange().getLastUpdatedOn();
+ return AttentionStatus.createFromRead(
+ timestamp.toInstant(),
+ attentionStatus.account(),
+ attentionStatus.operation(),
+ attentionStatus.reason());
+ }
}
diff --git a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
index 31d2048..e7f0812 100644
--- a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
+++ b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
@@ -91,14 +91,10 @@
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
-import org.apache.log4j.Level;
-import org.apache.log4j.LogManager;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.junit.After;
-import org.junit.AfterClass;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
@@ -150,20 +146,6 @@
protected abstract Injector createInjector();
- @BeforeClass
- public static void setLogLevel() {
- if (Boolean.getBoolean("debug")) {
- LogManager.getRootLogger().setLevel(Level.DEBUG);
- }
- }
-
- @AfterClass
- public static void resetLogLevel() {
- if (Boolean.getBoolean("debug")) {
- LogManager.getRootLogger().setLevel(Level.INFO);
- }
- }
-
@Before
public void setUpInjector() throws Exception {
lifecycle = new LifecycleManager();
diff --git a/javatests/com/google/gerrit/server/query/account/BUILD b/javatests/com/google/gerrit/server/query/account/BUILD
index da37f26..5c910a0 100644
--- a/javatests/com/google/gerrit/server/query/account/BUILD
+++ b/javatests/com/google/gerrit/server/query/account/BUILD
@@ -23,10 +23,8 @@
"//lib:guava",
"//lib:jgit",
"//lib/guice",
- "//lib/log:log4j",
"//lib/truth",
"//lib/truth:truth-java8-extension",
- "//resources:log4j-config",
],
)
diff --git a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index 71bdd69..fb09c9f 100644
--- a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -132,8 +132,6 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
-import org.apache.log4j.Level;
-import org.apache.log4j.LogManager;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
@@ -145,9 +143,7 @@
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.util.SystemReader;
import org.junit.After;
-import org.junit.AfterClass;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
@@ -210,20 +206,6 @@
protected abstract Injector createInjector();
- @BeforeClass
- public static void setLogLevel() {
- if (Boolean.getBoolean("debug")) {
- LogManager.getRootLogger().setLevel(Level.DEBUG);
- }
- }
-
- @AfterClass
- public static void resetLogLevel() {
- if (Boolean.getBoolean("debug")) {
- LogManager.getRootLogger().setLevel(Level.INFO);
- }
- }
-
@Before
public void setUpInjector() throws Exception {
lifecycle = new LifecycleManager();
@@ -445,7 +427,7 @@
gApi.changes().id(change1.getChangeId()).setPrivate(true, null);
- // Change1 is not private, but should be still visible to its owner.
+ // Change1 is private, but should be still visible to its owner.
assertQuery("is:open", change1, change2);
assertQuery("is:private", change1);
@@ -943,11 +925,11 @@
public void byLabel() throws Exception {
accountManager.authenticate(AuthRequest.forUser("anotheruser"));
TestRepository<Repo> repo = createProject("repo");
- ChangeInserter ins = newChange(repo, null, null, null, null, false);
- ChangeInserter ins2 = newChange(repo, null, null, null, null, false);
- ChangeInserter ins3 = newChange(repo, null, null, null, null, false);
- ChangeInserter ins4 = newChange(repo, null, null, null, null, false);
- ChangeInserter ins5 = newChange(repo, null, null, null, null, false);
+ ChangeInserter ins = newChange(repo);
+ ChangeInserter ins2 = newChange(repo);
+ ChangeInserter ins3 = newChange(repo);
+ ChangeInserter ins4 = newChange(repo);
+ ChangeInserter ins5 = newChange(repo);
Change reviewMinus2Change = insert(repo, ins);
gApi.changes().id(reviewMinus2Change.getId().get()).current().review(ReviewInput.reject());
@@ -1048,11 +1030,11 @@
.update();
ReviewInput reviewVerified = new ReviewInput().label("Verified", 1);
- ChangeInserter ins = newChange(repo, null, null, null, null, false);
- ChangeInserter ins2 = newChange(repo, null, null, null, null, false);
- ChangeInserter ins3 = newChange(repo, null, null, null, null, false);
- ChangeInserter ins4 = newChange(repo, null, null, null, null, false);
- ChangeInserter ins5 = newChange(repo, null, null, null, null, false);
+ ChangeInserter ins = newChange(repo);
+ ChangeInserter ins2 = newChange(repo);
+ ChangeInserter ins3 = newChange(repo);
+ ChangeInserter ins4 = newChange(repo);
+ ChangeInserter ins5 = newChange(repo);
// CR+1
Change reviewCRplus1 = insert(repo, ins);
@@ -1093,7 +1075,7 @@
@Test
public void byLabelNotOwner() throws Exception {
TestRepository<Repo> repo = createProject("repo");
- ChangeInserter ins = newChange(repo, null, null, null, null, false);
+ ChangeInserter ins = newChange(repo);
Account.Id user1 = createAccount("user1");
Change reviewPlus1Change = insert(repo, ins);
@@ -1790,25 +1772,27 @@
public void visible() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(repo, newChange(repo));
- Change change2 = insert(repo, newChange(repo));
-
- gApi.changes().id(change2.getChangeId()).setPrivate(true, "private");
+ Change change2 = insert(repo, newChangePrivate(repo));
String q = "project:repo";
- assertQuery(q, change2, change1);
- // Second user cannot see first user's private change.
- Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ // Bad request for query with non-existent user
+ assertThatQueryException(q + " visibleto:notexisting");
+
+ // Current user can see all changes
+ assertQuery(q, change2, change1);
+ assertQuery(q + " visibleto:self", change2, change1);
+
+ // Second user cannot see first user's private change
+ Account.Id user2 = createAccount("anotheruser");
assertQuery(q + " visibleto:" + user2.get(), change1);
+ assertQuery(q + " visibleto:anotheruser", change1);
String g1 = createGroup("group1", "Administrators");
gApi.groups().id(g1).addMembers("anotheruser");
assertQuery(q + " visibleto:" + g1, change1);
- requestContext.setContext(
- newRequestContext(
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId()));
+ requestContext.setContext(newRequestContext(user2));
assertQuery("is:visible", change1);
}
@@ -3117,12 +3101,12 @@
}
protected ChangeInserter newChange(TestRepository<Repo> repo) throws Exception {
- return newChange(repo, null, null, null, null, false);
+ return newChange(repo, null, null, null, null, false, false);
}
protected ChangeInserter newChangeForCommit(TestRepository<Repo> repo, RevCommit commit)
throws Exception {
- return newChange(repo, commit, null, null, null, false);
+ return newChange(repo, commit, null, null, null, false, false);
}
protected ChangeInserter newChangeWithFiles(TestRepository<Repo> repo, String... paths)
@@ -3136,21 +3120,25 @@
protected ChangeInserter newChangeForBranch(TestRepository<Repo> repo, String branch)
throws Exception {
- return newChange(repo, null, branch, null, null, false);
+ return newChange(repo, null, branch, null, null, false, false);
}
protected ChangeInserter newChangeWithStatus(TestRepository<Repo> repo, Change.Status status)
throws Exception {
- return newChange(repo, null, null, status, null, false);
+ return newChange(repo, null, null, status, null, false, false);
}
protected ChangeInserter newChangeWithTopic(TestRepository<Repo> repo, String topic)
throws Exception {
- return newChange(repo, null, null, null, topic, false);
+ return newChange(repo, null, null, null, topic, false, false);
}
protected ChangeInserter newChangeWorkInProgress(TestRepository<Repo> repo) throws Exception {
- return newChange(repo, null, null, null, null, true);
+ return newChange(repo, null, null, null, null, true, false);
+ }
+
+ protected ChangeInserter newChangePrivate(TestRepository<Repo> repo) throws Exception {
+ return newChange(repo, null, null, null, null, false, true);
}
protected ChangeInserter newChange(
@@ -3159,7 +3147,8 @@
@Nullable String branch,
@Nullable Change.Status status,
@Nullable String topic,
- boolean workInProgress)
+ boolean workInProgress,
+ boolean isPrivate)
throws Exception {
if (commit == null) {
commit = repo.parseBody(repo.commit().message("message").create());
@@ -3177,7 +3166,8 @@
.setValidate(false)
.setStatus(status)
.setTopic(topic)
- .setWorkInProgress(workInProgress);
+ .setWorkInProgress(workInProgress)
+ .setPrivate(isPrivate);
return ins;
}
diff --git a/javatests/com/google/gerrit/server/query/change/BUILD b/javatests/com/google/gerrit/server/query/change/BUILD
index 520e65a..e5b51e7 100644
--- a/javatests/com/google/gerrit/server/query/change/BUILD
+++ b/javatests/com/google/gerrit/server/query/change/BUILD
@@ -34,9 +34,7 @@
"//lib:jgit",
"//lib:jgit-junit",
"//lib/guice",
- "//lib/log:log4j",
"//lib/truth",
- "//resources:log4j-config",
],
)
diff --git a/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java b/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
index 9b01f8d..d80eac0 100644
--- a/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
+++ b/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
@@ -68,12 +68,8 @@
import java.util.List;
import java.util.Locale;
import java.util.Optional;
-import org.apache.log4j.Level;
-import org.apache.log4j.LogManager;
import org.junit.After;
-import org.junit.AfterClass;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
@@ -119,20 +115,6 @@
protected abstract Injector createInjector();
- @BeforeClass
- public static void setLogLevel() {
- if (Boolean.getBoolean("debug")) {
- LogManager.getRootLogger().setLevel(Level.DEBUG);
- }
- }
-
- @AfterClass
- public static void resetLogLevel() {
- if (Boolean.getBoolean("debug")) {
- LogManager.getRootLogger().setLevel(Level.INFO);
- }
- }
-
@Before
public void setUpInjector() throws Exception {
lifecycle = new LifecycleManager();
diff --git a/javatests/com/google/gerrit/server/query/group/BUILD b/javatests/com/google/gerrit/server/query/group/BUILD
index 8f6fd6d..e14350f 100644
--- a/javatests/com/google/gerrit/server/query/group/BUILD
+++ b/javatests/com/google/gerrit/server/query/group/BUILD
@@ -20,10 +20,8 @@
"//lib:guava",
"//lib:jgit",
"//lib/guice",
- "//lib/log:log4j",
"//lib/truth",
"//lib/truth:truth-java8-extension",
- "//resources:log4j-config",
],
)
diff --git a/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java b/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java
index e142e0c..dfd7928 100644
--- a/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java
+++ b/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java
@@ -68,12 +68,8 @@
import java.util.List;
import java.util.Locale;
import java.util.Set;
-import org.apache.log4j.Level;
-import org.apache.log4j.LogManager;
import org.junit.After;
-import org.junit.AfterClass;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
@@ -115,20 +111,6 @@
protected abstract Injector createInjector();
- @BeforeClass
- public static void setLogLevel() {
- if (Boolean.getBoolean("debug")) {
- LogManager.getRootLogger().setLevel(Level.DEBUG);
- }
- }
-
- @AfterClass
- public static void resetLogLevel() {
- if (Boolean.getBoolean("debug")) {
- LogManager.getRootLogger().setLevel(Level.INFO);
- }
- }
-
@Before
public void setUpInjector() throws Exception {
lifecycle = new LifecycleManager();
diff --git a/javatests/com/google/gerrit/server/query/project/BUILD b/javatests/com/google/gerrit/server/query/project/BUILD
index 996be2f..984d824 100644
--- a/javatests/com/google/gerrit/server/query/project/BUILD
+++ b/javatests/com/google/gerrit/server/query/project/BUILD
@@ -21,9 +21,7 @@
"//lib:guava",
"//lib:jgit",
"//lib/guice",
- "//lib/log:log4j",
"//lib/truth",
- "//resources:log4j-config",
],
)
diff --git a/plugins/replication b/plugins/replication
index 0bf9f5a..8be6db9 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 0bf9f5ae26220bfdcff0b3332e810f00aa9a7789
+Subproject commit 8be6db961b2c6c3a32e0b3db2f04475ca2c4c520
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
index bfe5ddc..bd21015 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
@@ -535,25 +535,24 @@
</div>
</section>
- <template is="dom-if" if="[[_showPrimaryTabs]]">
- <paper-tabs id="primaryTabs" on-selected-changed="_handleFileTabChange">
- <paper-tab>Files</paper-tab>
- <template is="dom-repeat" items="[[_dynamicTabHeaderEndpoints]]"
- as="tabHeader">
- <paper-tab>
- <gr-endpoint-decorator name$="[[tabHeader]]">
- <gr-endpoint-param name="change" value="[[_change]]">
- </gr-endpoint-param>
- <gr-endpoint-param name="revision" value="[[_selectedRevision]]">
- </gr-endpoint-param>
- </gr-endpoint-decorator>
- </paper-tab>
- </template>
- </paper-tabs>
- </template>
-
<section class="patchInfo">
- <div hidden$="[[!_showFileTabContent]]">
+ <template is="dom-if" if="[[_showPrimaryTabs]]">
+ <paper-tabs id="primaryTabs" on-selected-changed="_handleFileTabChange">
+ <paper-tab data-name$="[[_files_tab_name]]">Files</paper-tab>
+ <template is="dom-repeat" items="[[_dynamicTabHeaderEndpoints]]"
+ as="tabHeader">
+ <paper-tab data-name$="[[tabHeader]]">
+ <gr-endpoint-decorator name$="[[tabHeader]]">
+ <gr-endpoint-param name="change" value="[[_change]]">
+ </gr-endpoint-param>
+ <gr-endpoint-param name="revision" value="[[_selectedRevision]]">
+ </gr-endpoint-param>
+ </gr-endpoint-decorator>
+ </paper-tab>
+ </template>
+ </paper-tabs>
+ </template>
+ <div hidden$="[[!_findIfTabMatches(_currentTabName, _files_tab_name)]]">
<gr-file-list-header
id="fileListHeader"
account="[[_account]]"
@@ -604,13 +603,13 @@
on-reload-drafts="_reloadDraftsWithCallback"></gr-file-list>
</div>
- <template is="dom-if" if="[[!_showFileTabContent]]">
- <gr-endpoint-decorator name$="[[_selectedFilesTabPluginEndpoint]]">
- <gr-endpoint-param name="change" value="[[_change]]">
- </gr-endpoint-param>
- <gr-endpoint-param name="revision" value="[[_selectedRevision]]">
- </gr-endpoint-param>
- </gr-endpoint-decorator>
+ <template is="dom-if" if="[[_findIfTabMatches(_currentTabName, _selectedTabPluginHeader)]]">
+ <gr-endpoint-decorator name$="[[_selectedTabPluginEndpoint]]">
+ <gr-endpoint-param name="change" value="[[_change]]">
+ </gr-endpoint-param>
+ <gr-endpoint-param name="revision" value="[[_selectedRevision]]">
+ </gr-endpoint-param>
+ </gr-endpoint-decorator>
</template>
</section>
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
index 1622ebd..b55d964 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
@@ -68,6 +68,7 @@
const CHANGE_DATA_TIMING_LABEL = 'ChangeDataLoaded';
const CHANGE_RELOAD_TIMING_LABEL = 'ChangeReloaded';
const SEND_REPLY_TIMING_LABEL = 'SendReply';
+ const FILES_TAB_NAME = 'files';
/**
* @appliesMixin Gerrit.FireMixin
@@ -322,7 +323,12 @@
_dynamicTabContentEndpoints: {
type: Array,
},
- _selectedFilesTabPluginEndpoint: {
+ // The dynamic content of the plugin added tab
+ _selectedTabPluginEndpoint: {
+ type: String,
+ },
+ // The dynamic heading of the plugin added tab
+ _selectedTabPluginHeader: {
type: String,
},
_robotCommentsPatchSetDropdownItems: {
@@ -333,6 +339,14 @@
_currentRobotCommentsPatchSet: {
type: Number,
},
+ _files_tab_name: {
+ type: String,
+ value: FILES_TAB_NAME,
+ },
+ _currentTabName: {
+ type: String,
+ value: FILES_TAB_NAME,
+ },
};
}
@@ -503,30 +517,44 @@
return currentView === view;
}
- _handleFileTabChange(e) {
- const selectedIndex = this.shadowRoot
- .querySelector('#primaryTabs').selected;
- this._showFileTabContent = selectedIndex === 0;
- // Initial tab is the static files list.
- const newSelectedTab =
- this._dynamicTabContentEndpoints[selectedIndex - 1];
- if (newSelectedTab !== this._selectedFilesTabPluginEndpoint) {
- this._selectedFilesTabPluginEndpoint = newSelectedTab;
+ _findIfTabMatches(currentTab, tab) {
+ return currentTab === tab;
+ }
- const tabName = this._selectedFilesTabPluginEndpoint || 'files';
- const source = e && e.type ? e.type : '';
- this.$.reporting.reportInteraction('tab-changed', {tabName, source});
+ _handleFileTabChange(e) {
+ const selectedIndex = e.target.selected;
+ const tabs = e.target.querySelectorAll('paper-tab');
+ this._currentTabName = tabs[selectedIndex] &&
+ tabs[selectedIndex].dataset.name;
+ const source = e && e.type ? e.type : '';
+ const pluginIndex = this._dynamicTabHeaderEndpoints.indexOf(
+ this._currentTabName);
+ if (pluginIndex !== -1) {
+ this._selectedTabPluginEndpoint = this._dynamicTabContentEndpoints[
+ pluginIndex];
+ this._selectedTabPluginHeader = this._dynamicTabHeaderEndpoints[
+ pluginIndex];
+ } else {
+ this._selectedTabPluginEndpoint = '';
+ this._selectedTabPluginHeader = '';
}
+ this.$.reporting.reportInteraction('tab-changed',
+ {tabName: this._currentTabName, source});
}
_handleShowTab(e) {
- const idx = this._dynamicTabContentEndpoints.indexOf(e.detail.tab);
+ const primaryTabs = this.shadowRoot.querySelector('#primaryTabs');
+ const tabs = primaryTabs.querySelectorAll('paper-tab');
+ let idx = -1;
+ tabs.forEach((tab, index) => {
+ if (tab.dataset.name === e.detail.tab) idx = index;
+ });
if (idx === -1) {
- console.warn(e.detail.tab + ' tab not found');
+ console.error(e.detail.tab + ' tab not found');
return;
}
- this.shadowRoot.querySelector('#primaryTabs').selected = idx + 1;
- this.shadowRoot.querySelector('#primaryTabs').scrollIntoView();
+ primaryTabs.selected = idx;
+ primaryTabs.scrollIntoView();
this.$.reporting.reportInteraction('show-tab', {tabName: e.detail.tab});
}
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
index 934eeaf..3fe8faf 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
@@ -280,6 +280,20 @@
element = fixture('basic');
sandbox.stub(element.$.actions, 'reload').returns(Promise.resolve());
Gerrit._loadPlugins([]);
+ Gerrit.install(
+ plugin => {
+ plugin.registerDynamicCustomComponent(
+ 'change-view-tab-header',
+ 'gr-checks-change-view-tab-header-view'
+ );
+ plugin.registerDynamicCustomComponent(
+ 'change-view-tab-content',
+ 'gr-checks-view'
+ );
+ },
+ '0.1',
+ 'http://some/plugins/url.html'
+ );
});
teardown(done => {
@@ -305,6 +319,44 @@
assert.isTrue(replaceStateStub.called);
});
+ suite('plugins adding to file tab', () => {
+ setup(done => {
+ // Resolving it here instead of during setup() as other tests depend
+ // on flush() not being called during setup.
+ flush(() => done());
+ });
+
+ test('plugin added tab shows up as a dynamic endpoint', () => {
+ assert(element._dynamicTabHeaderEndpoints.includes(
+ 'change-view-tab-header-url'));
+ const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
+ assert.equal(paperTabs.querySelectorAll('paper-tab').length, 2);
+ assert.equal(paperTabs.querySelectorAll('paper-tab')[1].dataset.name,
+ 'change-view-tab-header-url');
+ });
+
+ test('handleShowTab switched tab correctly', done => {
+ const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
+ assert.equal(paperTabs.selected, 0);
+ element._handleShowTab({detail:
+ {tab: 'change-view-tab-header-url'}});
+ flush(() => {
+ assert.equal(paperTabs.selected, 1);
+ done();
+ });
+ });
+
+ test('switching tab sets _selectedTabPluginEndpoint', done => {
+ const paperTabs = element.shadowRoot.querySelector('#primaryTabs');
+ MockInteractions.tap(paperTabs.querySelectorAll('paper-tab')[1]);
+ flush(() => {
+ assert.equal(element._selectedTabPluginEndpoint,
+ 'change-view-tab-content-url');
+ done();
+ });
+ });
+ });
+
suite('keyboard shortcuts', () => {
test('t to add topic', () => {
const editStub = sandbox.stub(element.$.metadata, 'editTopic');
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.html b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.html
index 06edb9b..c650bb5 100644
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.html
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.html
@@ -76,10 +76,10 @@
</div>
<div slot="footer" class="fix-picker" hidden$="[[hasSingleFix(_fixSuggestions)]]">
<span>Suggested fix [[addOneTo(_selectedFixIdx)]] of [[_fixSuggestions.length]]</span>
- <gr-button on-click="_onPrevFixClick" disabled$="[[_noPrevFix(_selectedFixIdx)]]">
+ <gr-button id="prevFix" on-click="_onPrevFixClick" disabled$="[[_noPrevFix(_selectedFixIdx)]]">
<iron-icon icon="gr-icons:chevron-left"></iron-icon>
</gr-button>
- <gr-button on-click="_onNextFixClick" disabled$="[[_noNextFix(_selectedFixIdx)]]">
+ <gr-button id="nextFix" on-click="_onNextFixClick" disabled$="[[_noNextFix(_selectedFixIdx, _fixSuggestions)]]">
<iron-icon icon="gr-icons:chevron-right"></iron-icon>
</gr-button>
</div>
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.js b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.js
index 45e8c07..94549ee 100644
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.js
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.js
@@ -105,11 +105,7 @@
})
.catch(err => {
this._close();
- this.dispatchEvent(new CustomEvent('show-error', {
- bubbles: true,
- composed: true,
- detail: {message: `Error generating fix preview: ${err}`},
- }));
+ throw err;
});
},
@@ -144,8 +140,8 @@
_onNextFixClick(e) {
if (e) e.stopPropagation();
- if (this._selectedFixIdx < this._fixSuggestions.length &&
- this._fixSuggestions != null) {
+ if (this._fixSuggestions &&
+ this._selectedFixIdx < this._fixSuggestions.length) {
this._selectedFixIdx += 1;
return this._showSelectedFixSuggestion(
this._fixSuggestions[this._selectedFixIdx]);
@@ -156,9 +152,9 @@
return _selectedFixIdx === 0;
},
- _noNextFix(_selectedFixIdx) {
- if (this._fixSuggestions == null) return true;
- return _selectedFixIdx === this._fixSuggestions.length - 1;
+ _noNextFix(_selectedFixIdx, fixSuggestions) {
+ if (fixSuggestions == null) return true;
+ return _selectedFixIdx === fixSuggestions.length - 1;
},
_close() {
@@ -189,14 +185,7 @@
this._currentFix.fix_id).then(res => {
Gerrit.Nav.navigateToChange(this.change, 'edit', this._patchNum);
this._close();
- })
- .catch(err => {
- this.dispatchEvent(new CustomEvent('show-error', {
- bubbles: true,
- composed: true,
- detail: {message: `Error applying fix suggestion: ${err}`},
- }));
- });
+ });
},
getFixDescription(currentFix) {
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.html b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.html
index d4ab8f1..f3f748f 100644
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.html
@@ -17,11 +17,12 @@
-->
<meta name='viewport' content='width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes'>
<title>gr-apply-fix-dialog</title>
-<script src='/test/common-test-setup.js'></script>
+<link rel='import' href='../../../test/common-test-setup.html'>
<script src='/bower_components/webcomponentsjs/custom-elements-es5-adapter.js'></script>
<script src='/bower_components/webcomponentsjs/webcomponents-lite.js'></script>
<script src='/bower_components/web-component-tester/browser.js'></script>
+<script src="../../../test/test-pre-setup.js"></script>
<link rel='import' href='../../../test/common-test-setup.html' />
<link rel='import' href='./gr-apply-fix-dialog.html'>
@@ -39,11 +40,16 @@
await readyToTest();
let element;
let sandbox;
- const ROBOT_COMMENT = {
+ const ROBOT_COMMENT_WITH_TWO_FIXES = {
robot_id: 'robot_1',
fix_suggestions: [{fix_id: 'fix_1'}, {fix_id: 'fix_2'}],
};
+ const ROBOT_COMMENT_WITH_ONE_FIX = {
+ robot_id: 'robot_1',
+ fix_suggestions: [{fix_id: 'fix_1'}],
+ };
+
setup(() => {
sandbox = sinon.sandbox.create();
element = fixture('basic');
@@ -100,7 +106,7 @@
}));
sandbox.stub(element.$.applyFixOverlay, 'open').returns(Promise.resolve());
- element.open({detail: {patchNum: 2, comment: ROBOT_COMMENT}})
+ element.open({detail: {patchNum: 2, comment: ROBOT_COMMENT_WITH_TWO_FIXES}})
.then(() => {
assert.equal(element._currentFix.fix_id, 'fix_1');
assert.equal(element._currentPreviews.length, 2);
@@ -109,16 +115,42 @@
});
});
+ test('next button state updated when suggestions changed', done => {
+ sandbox.stub(element.$.restAPI, 'getRobotCommentFixPreview')
+ .returns(Promise.resolve({}));
+ sandbox.stub(element.$.applyFixOverlay, 'open').returns(Promise.resolve());
+
+ element.open({detail: {patchNum: 2, comment: ROBOT_COMMENT_WITH_ONE_FIX}})
+ .then(() => assert.isTrue(element.$.nextFix.disabled))
+ .then(() =>
+ element.open({detail: {patchNum: 2,
+ comment: ROBOT_COMMENT_WITH_TWO_FIXES}}))
+ .then(() => {
+ assert.isFalse(element.$.nextFix.disabled);
+ done();
+ });
+ });
+
test('preview endpoint throws error should reset dialog', done => {
- element.addEventListener('show-error', () => {
+ sandbox.stub(window, 'fetch', (url => {
+ if (url.endsWith('/preview')) {
+ return Promise.reject(new Error('backend error'));
+ }
+ return Promise.resolve({
+ ok: true,
+ text() { return Promise.resolve(''); },
+ status: 200,
+ });
+ }));
+ const errorStub = sinon.stub();
+ document.addEventListener('network-error', errorStub);
+ element.open({detail: {patchNum: 2,
+ comment: ROBOT_COMMENT_WITH_TWO_FIXES}});
+ flush(() => {
+ assert.isTrue(errorStub.called);
assert.deepEqual(element._currentFix, {});
- assert.equal(element._currentPreviews.length, 0);
done();
});
- sandbox.stub(element.$.restAPI, 'getRobotCommentFixPreview',
- () => Promise.reject(new Error('backend error')));
-
- element.open({detail: {patchNum: 2, comment: ROBOT_COMMENT}});
});
test('apply fix button should call apply' +
@@ -179,7 +211,7 @@
}));
sandbox.stub(element.$.applyFixOverlay, 'open').returns(Promise.resolve());
- element.open({detail: {patchNum: 2, comment: ROBOT_COMMENT}})
+ element.open({detail: {patchNum: 2, comment: ROBOT_COMMENT_WITH_TWO_FIXES}})
.then(() => {
element._onNextFixClick();
assert.equal(element._currentFix.fix_id, 'fix_2');
@@ -188,5 +220,28 @@
done();
});
});
+
+ test('server-error should throw for failed apply call', done => {
+ sandbox.stub(window, 'fetch', (url => {
+ if (url.endsWith('/apply')) {
+ return Promise.reject(new Error('backend error'));
+ }
+ return Promise.resolve({
+ ok: true,
+ text() { return Promise.resolve(''); },
+ status: 200,
+ });
+ }));
+ const errorStub = sinon.stub();
+ document.addEventListener('network-error', errorStub);
+ sandbox.stub(Gerrit.Nav, 'navigateToChange');
+ element._currentFix = {fix_id: '123'};
+ element._handleApplyFix();
+ flush(() => {
+ assert.isFalse(Gerrit.Nav.navigateToChange.called);
+ assert.isTrue(errorStub.called);
+ done();
+ });
+ });
});
</script>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.html b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.html
index 7d60f13..2d9369f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.html
@@ -51,7 +51,9 @@
coverage-ranges="[[_coverageRanges]]"
blame="[[_blame]]"
layers="[[_layers]]"
- diff="[[diff]]">
+ diff="[[diff]]"
+ show-newline-warning-left="[[_showNewlineWarningLeft(diff)]]"
+ show-newline-warning-right="[[_showNewlineWarningRight(diff)]]">
</gr-diff>
<gr-syntax-layer
id="syntaxLayer"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.js b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.js
index da22f6b..a44e366 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.js
@@ -1037,6 +1037,73 @@
'diff-context-expanded', {numLines: event.detail.numLines}
);
}
+
+ /**
+ * Find the last chunk for the given side.
+ *
+ * @param {!Object} diff
+ * @param {boolean} leftSide true if checking the base of the diff,
+ * false if testing the revision.
+ * @return {Object|null} returns the chunk object or null if there was
+ * no chunk for that side.
+ */
+ _lastChunkForSide(diff, leftSide) {
+ if (!diff.content.length) { return null; }
+
+ let chunkIndex = diff.content.length;
+ let chunk;
+
+ // Walk backwards until we find a chunk for the given side.
+ do {
+ chunkIndex--;
+ chunk = diff.content[chunkIndex];
+ } while (
+ // We haven't reached the beginning.
+ chunkIndex >= 0 &&
+
+ // The chunk doesn't have both sides.
+ !chunk.ab &&
+
+ // The chunk doesn't have the given side.
+ ((leftSide && (!chunk.a || !chunk.a.length)) ||
+ (!leftSide && (!chunk.b || !chunk.b.length))));
+
+ // If we reached the beginning of the diff and failed to find a chunk
+ // with the given side, return null.
+ if (chunkIndex === -1) { return null; }
+
+ return chunk;
+ }
+
+ /**
+ * Check whether the specified side of the diff has a trailing newline.
+ *
+ * @param {!Object} diff
+ * @param {boolean} leftSide true if checking the base of the diff,
+ * false if testing the revision.
+ * @return {boolean|null} Return true if the side has a trailing newline.
+ * Return false if it doesn't. Return null if not applicable (for
+ * example, if the diff has no content on the specified side).
+ */
+ _hasTrailingNewlines(diff, leftSide) {
+ const chunk = this._lastChunkForSide(diff, leftSide);
+ if (!chunk) { return null; }
+ let lines;
+ if (chunk.ab) {
+ lines = chunk.ab;
+ } else {
+ lines = leftSide ? chunk.a : chunk.b;
+ }
+ return lines[lines.length - 1] === '';
+ }
+
+ _showNewlineWarningLeft(diff) {
+ return this._hasTrailingNewlines(diff, true) === false;
+ }
+
+ _showNewlineWarningRight(diff) {
+ return this._hasTrailingNewlines(diff, false) === false;
+ }
}
customElements.define(GrDiffHost.is, GrDiffHost);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html
index fd93cb4..5a42fc4 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.html
@@ -1530,5 +1530,102 @@
});
});
});
+
+ suite('trailing newlines', () => {
+ setup(() => {
+ });
+
+ suite('_lastChunkForSide', () => {
+ test('deltas', () => {
+ const diff = {content: [
+ {a: ['foo', 'bar'], b: ['baz']},
+ {ab: ['foo', 'bar', 'baz']},
+ {b: ['foo']},
+ ]};
+ assert.equal(element._lastChunkForSide(diff, false), diff.content[2]);
+ assert.equal(element._lastChunkForSide(diff, true), diff.content[1]);
+
+ diff.content.push({a: ['foo'], b: ['bar']});
+ assert.equal(element._lastChunkForSide(diff, false), diff.content[3]);
+ assert.equal(element._lastChunkForSide(diff, true), diff.content[3]);
+ });
+
+ test('addition with a undefined', () => {
+ const diff = {content: [
+ {b: ['foo', 'bar', 'baz']},
+ ]};
+ assert.equal(element._lastChunkForSide(diff, false), diff.content[0]);
+ assert.isNull(element._lastChunkForSide(diff, true));
+ });
+
+ test('addition with a empty', () => {
+ const diff = {content: [
+ {a: [], b: ['foo', 'bar', 'baz']},
+ ]};
+ assert.equal(element._lastChunkForSide(diff, false), diff.content[0]);
+ assert.isNull(element._lastChunkForSide(diff, true));
+ });
+
+ test('deletion with b undefined', () => {
+ const diff = {content: [
+ {a: ['foo', 'bar', 'baz']},
+ ]};
+ assert.isNull(element._lastChunkForSide(diff, false));
+ assert.equal(element._lastChunkForSide(diff, true), diff.content[0]);
+ });
+
+ test('deletion with b empty', () => {
+ const diff = {content: [
+ {a: ['foo', 'bar', 'baz'], b: []},
+ ]};
+ assert.isNull(element._lastChunkForSide(diff, false));
+ assert.equal(element._lastChunkForSide(diff, true), diff.content[0]);
+ });
+
+ test('empty', () => {
+ const diff = {content: []};
+ assert.isNull(element._lastChunkForSide(diff, false));
+ assert.isNull(element._lastChunkForSide(diff, true));
+ });
+ });
+
+ suite('_hasTrailingNewlines', () => {
+ test('shared no trailing', () => {
+ const diff = undefined;
+ sandbox.stub(element, '_lastChunkForSide')
+ .returns({ab: ['foo', 'bar']});
+ assert.isFalse(element._hasTrailingNewlines(diff, false));
+ assert.isFalse(element._hasTrailingNewlines(diff, true));
+ });
+
+ test('delta trailing in right', () => {
+ const diff = undefined;
+ sandbox.stub(element, '_lastChunkForSide')
+ .returns({a: ['foo', 'bar'], b: ['baz', '']});
+ assert.isTrue(element._hasTrailingNewlines(diff, false));
+ assert.isFalse(element._hasTrailingNewlines(diff, true));
+ });
+
+ test('addition', () => {
+ const diff = undefined;
+ sandbox.stub(element, '_lastChunkForSide', (diff, leftSide) => {
+ if (leftSide) { return null; }
+ return {b: ['foo', '']};
+ });
+ assert.isTrue(element._hasTrailingNewlines(diff, false));
+ assert.isNull(element._hasTrailingNewlines(diff, true));
+ });
+
+ test('deletion', () => {
+ const diff = undefined;
+ sandbox.stub(element, '_lastChunkForSide', (diff, leftSide) => {
+ if (!leftSide) { return null; }
+ return {a: ['foo']};
+ });
+ assert.isNull(element._hasTrailingNewlines(diff, false));
+ assert.isFalse(element._hasTrailingNewlines(diff, true));
+ });
+ });
+ });
});
</script>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
index ef22188..8e96147 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
@@ -249,9 +249,19 @@
parentIndex: Number,
+ showNewlineWarningLeft: {
+ type: Boolean,
+ value: false,
+ },
+ showNewlineWarningRight: {
+ type: Boolean,
+ value: false,
+ },
+
_newlineWarning: {
type: String,
- computed: '_computeNewlineWarning(diff)',
+ computed: '_computeNewlineWarning(' +
+ 'showNewlineWarningLeft, showNewlineWarningRight)',
},
_diffLength: Number,
@@ -916,76 +926,16 @@
}
/**
- * Find the last chunk for the given side.
- *
- * @param {!Object} diff
- * @param {boolean} leftSide true if checking the base of the diff,
- * false if testing the revision.
- * @return {Object|null} returns the chunk object or null if there was
- * no chunk for that side.
- */
- _lastChunkForSide(diff, leftSide) {
- if (!diff.content.length) { return null; }
-
- let chunkIndex = diff.content.length;
- let chunk;
-
- // Walk backwards until we find a chunk for the given side.
- do {
- chunkIndex--;
- chunk = diff.content[chunkIndex];
- } while (
- // We haven't reached the beginning.
- chunkIndex >= 0 &&
-
- // The chunk doesn't have both sides.
- !chunk.ab &&
-
- // The chunk doesn't have the given side.
- ((leftSide && (!chunk.a || !chunk.a.length)) ||
- (!leftSide && (!chunk.b || !chunk.b.length))));
-
- // If we reached the beginning of the diff and failed to find a chunk
- // with the given side, return null.
- if (chunkIndex === -1) { return null; }
-
- return chunk;
- }
-
- /**
- * Check whether the specified side of the diff has a trailing newline.
- *
- * @param {!Object} diff
- * @param {boolean} leftSide true if checking the base of the diff,
- * false if testing the revision.
- * @return {boolean|null} Return true if the side has a trailing newline.
- * Return false if it doesn't. Return null if not applicable (for
- * example, if the diff has no content on the specified side).
- */
- _hasTrailingNewlines(diff, leftSide) {
- const chunk = this._lastChunkForSide(diff, leftSide);
- if (!chunk) { return null; }
- let lines;
- if (chunk.ab) {
- lines = chunk.ab;
- } else {
- lines = leftSide ? chunk.a : chunk.b;
- }
- return lines[lines.length - 1] === '';
- }
-
- /**
- * @param {!Object} diff
+ * @param {!boolean} warnLeft
+ * @param {!boolean} warnRight
* @return {string|null}
*/
- _computeNewlineWarning(diff) {
- const hasLeft = this._hasTrailingNewlines(diff, true);
- const hasRight = this._hasTrailingNewlines(diff, false);
+ _computeNewlineWarning(warnLeft, warnRight) {
const messages = [];
- if (hasLeft === false) {
+ if (warnLeft) {
messages.push(NO_NEWLINE_BASE);
}
- if (hasRight === false) {
+ if (warnRight) {
messages.push(NO_NEWLINE_REVISION);
}
if (!messages.length) { return null; }
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
index 9fcf1ca..b14cc203 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
@@ -834,137 +834,60 @@
});
});
- suite('trailing newlines', () => {
+ suite('trailing newline warnings', () => {
+ const NO_NEWLINE_BASE = 'No newline at end of base file.';
+ const NO_NEWLINE_REVISION = 'No newline at end of revision file.';
+
+ const getWarning = element =>
+ element.shadowRoot.querySelector('.newlineWarning').textContent;
+
setup(() => {
element = fixture('basic');
+ element.showNewlineWarningLeft = false;
+ element.showNewlineWarningRight = false;
});
- suite('_lastChunkForSide', () => {
- test('deltas', () => {
- const diff = {content: [
- {a: ['foo', 'bar'], b: ['baz']},
- {ab: ['foo', 'bar', 'baz']},
- {b: ['foo']},
- ]};
- assert.equal(element._lastChunkForSide(diff, false), diff.content[2]);
- assert.equal(element._lastChunkForSide(diff, true), diff.content[1]);
-
- diff.content.push({a: ['foo'], b: ['bar']});
- assert.equal(element._lastChunkForSide(diff, false), diff.content[3]);
- assert.equal(element._lastChunkForSide(diff, true), diff.content[3]);
- });
-
- test('addition with a undefined', () => {
- const diff = {content: [
- {b: ['foo', 'bar', 'baz']},
- ]};
- assert.equal(element._lastChunkForSide(diff, false), diff.content[0]);
- assert.isNull(element._lastChunkForSide(diff, true));
- });
-
- test('addition with a empty', () => {
- const diff = {content: [
- {a: [], b: ['foo', 'bar', 'baz']},
- ]};
- assert.equal(element._lastChunkForSide(diff, false), diff.content[0]);
- assert.isNull(element._lastChunkForSide(diff, true));
- });
-
- test('deletion with b undefined', () => {
- const diff = {content: [
- {a: ['foo', 'bar', 'baz']},
- ]};
- assert.isNull(element._lastChunkForSide(diff, false));
- assert.equal(element._lastChunkForSide(diff, true), diff.content[0]);
- });
-
- test('deletion with b empty', () => {
- const diff = {content: [
- {a: ['foo', 'bar', 'baz'], b: []},
- ]};
- assert.isNull(element._lastChunkForSide(diff, false));
- assert.equal(element._lastChunkForSide(diff, true), diff.content[0]);
- });
-
- test('empty', () => {
- const diff = {content: []};
- assert.isNull(element._lastChunkForSide(diff, false));
- assert.isNull(element._lastChunkForSide(diff, true));
- });
- });
-
- suite('_hasTrailingNewlines', () => {
- test('shared no trailing', () => {
- const diff = undefined;
- sandbox.stub(element, '_lastChunkForSide')
- .returns({ab: ['foo', 'bar']});
- assert.isFalse(element._hasTrailingNewlines(diff, false));
- assert.isFalse(element._hasTrailingNewlines(diff, true));
- });
-
- test('delta trailing in right', () => {
- const diff = undefined;
- sandbox.stub(element, '_lastChunkForSide')
- .returns({a: ['foo', 'bar'], b: ['baz', '']});
- assert.isTrue(element._hasTrailingNewlines(diff, false));
- assert.isFalse(element._hasTrailingNewlines(diff, true));
- });
-
- test('addition', () => {
- const diff = undefined;
- sandbox.stub(element, '_lastChunkForSide', (diff, leftSide) => {
- if (leftSide) { return null; }
- return {b: ['foo', '']};
- });
- assert.isTrue(element._hasTrailingNewlines(diff, false));
- assert.isNull(element._hasTrailingNewlines(diff, true));
- });
-
- test('deletion', () => {
- const diff = undefined;
- sandbox.stub(element, '_lastChunkForSide', (diff, leftSide) => {
- if (!leftSide) { return null; }
- return {a: ['foo']};
- });
- assert.isNull(element._hasTrailingNewlines(diff, false));
- assert.isFalse(element._hasTrailingNewlines(diff, true));
- });
- });
-
- test('_computeNewlineWarning', () => {
- const NO_NEWLINE_BASE = 'No newline at end of base file.';
- const NO_NEWLINE_REVISION = 'No newline at end of revision file.';
-
- let hasLeft;
- let hasRight;
- sandbox.stub(element, '_hasTrailingNewlines', (diff, left) => {
- if (left) { return hasLeft; }
- return hasRight;
- });
- const diff = undefined;
-
- // The revision has a trailing newline, but the base doesn't.
- hasLeft = true;
- hasRight = false;
- assert.equal(element._computeNewlineWarning(diff), NO_NEWLINE_REVISION);
-
- // Trailing newlines were undetermined in the revision.
- hasLeft = true;
- hasRight = null;
- assert.isNull(element._computeNewlineWarning(diff));
-
- // Missing trailing newlines in the base.
- hasLeft = false;
- hasRight = null;
- assert.equal(element._computeNewlineWarning(diff), NO_NEWLINE_BASE);
-
- // Missing trailing newlines in both.
- hasLeft = false;
- hasRight = false;
- assert.equal(element._computeNewlineWarning(diff),
+ test('shows combined warning if both sides set to warn', () => {
+ element.showNewlineWarningLeft = true;
+ element.showNewlineWarningRight = true;
+ assert.include(getWarning(element),
NO_NEWLINE_BASE + ' — ' + NO_NEWLINE_REVISION);
});
+ suite('showNewlineWarningLeft', () => {
+ test('show warning if true', () => {
+ element.showNewlineWarningLeft = true;
+ assert.include(getWarning(element), NO_NEWLINE_BASE);
+ });
+
+ test('hide warning if false', () => {
+ element.showNewlineWarningLeft = false;
+ assert.notInclude(getWarning(element), NO_NEWLINE_BASE);
+ });
+
+ test('hide warning if undefined', () => {
+ element.showNewlineWarningLeft = undefined;
+ assert.notInclude(getWarning(element), NO_NEWLINE_BASE);
+ });
+ });
+
+ suite('showNewlineWarningRight', () => {
+ test('show warning if true', () => {
+ element.showNewlineWarningRight = true;
+ assert.include(getWarning(element), NO_NEWLINE_REVISION);
+ });
+
+ test('hide warning if false', () => {
+ element.showNewlineWarningRight = false;
+ assert.notInclude(getWarning(element), NO_NEWLINE_REVISION);
+ });
+
+ test('hide warning if undefined', () => {
+ element.showNewlineWarningRight = undefined;
+ assert.notInclude(getWarning(element), NO_NEWLINE_REVISION);
+ });
+ });
+
test('_computeNewlineWarningClass', () => {
const hidden = 'newlineWarning hidden';
const shown = 'newlineWarning';
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.js b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.js
index 5a2f104..1c10642 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.js
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.js
@@ -60,7 +60,7 @@
*/
_import(url) {
return new Promise((resolve, reject) => {
- (this.importHref || Polymer.importHref)(url, resolve, reject);
+ Polymer.importHref(url, resolve, reject);
});
}
diff --git a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js
index 2e3bee1..d12a571 100644
--- a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js
+++ b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js
@@ -44,7 +44,7 @@
if (this._urlsImported.includes(url)) { return Promise.resolve(); }
this._urlsImported.push(url);
return new Promise((resolve, reject) => {
- (this.importHref || Polymer.importHref)(url, resolve, reject);
+ Polymer.importHref(url, resolve, reject);
});
}
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.html b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.html
index ac5c2e9..c344bf64 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.html
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.html
@@ -59,11 +59,9 @@
padding: 2px;
}
}
-
</style>
<div class="text">
<iron-input
- hidden$="[[hideInput]]"
class="copyText"
type="text"
bind-value="[[text]]"
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.html b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.html
index 677a952..55eb198 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard_test.html
@@ -68,13 +68,23 @@
});
test('_handleInputClick', () => {
- const inputElement = element.$$('input');
+ // iron-input as parent should never be hidden as copy won't work
+ // on nested hidden elements
+ const ironInputElement = element.shadowRoot.querySelector('iron-input');
+ assert.notEqual(getComputedStyle(ironInputElement).display, 'none');
+
+ const inputElement = element.shadowRoot.querySelector('input');
MockInteractions.tap(inputElement);
assert.equal(inputElement.selectionStart, 0);
assert.equal(inputElement.selectionEnd, element.text.length - 1);
});
test('hideInput', () => {
+ // iron-input as parent should never be hidden as copy won't work
+ // on nested hidden elements
+ const ironInputElement = element.shadowRoot.querySelector('iron-input');
+ assert.notEqual(getComputedStyle(ironInputElement).display, 'none');
+
assert.notEqual(getComputedStyle(element.$.input).display, 'none');
element.hideInput = true;
flushAsynchronousOperations();
diff --git a/polygerrit-ui/app/elements/shared/gr-event-interface/gr-event-interface_test.html b/polygerrit-ui/app/elements/shared/gr-event-interface/gr-event-interface_test.html
index 6e62b15..305702a 100644
--- a/polygerrit-ui/app/elements/shared/gr-event-interface/gr-event-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-event-interface/gr-event-interface_test.html
@@ -19,7 +19,7 @@
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-api-interface</title>
-<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
+<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<script src="../../../bower_components/web-component-tester/browser.js"></script>
<script src="../../../test/test-pre-setup.js"></script>
<link rel="import" href="../../../test/common-test-setup.html"/>
diff --git a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.js b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.js
index defc6bd..81126ec 100644
--- a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.js
+++ b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.js
@@ -77,7 +77,7 @@
*/
getDarkTheme() {
return new Promise((resolve, reject) => {
- (this.importHref || Polymer.importHref)(
+ Polymer.importHref(
this._getLibRoot() + DARK_THEME_PATH, () => {
const module = document.createElement('style');
module.setAttribute('include', 'dark-theme');
@@ -85,7 +85,8 @@
cs.appendChild(module);
resolve(cs);
- });
+ },
+ reject);
});
}
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.js b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.js
index bbe525e..10f7ed6 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.js
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.js
@@ -76,10 +76,16 @@
this._handleParseResult.bind(this), this.removeZeroWidthSpace);
parser.parse(content);
- // Ensure that links originating from HTML commentlink configs open in a
- // new tab. @see Issue 5567
+ // Ensure that external links originating from HTML commentlink configs
+ // open in a new tab. @see Issue 5567
+ // Ensure links to the same host originating from commentlink configs
+ // open in the same tab. @see Issue 4616
output.querySelectorAll('a').forEach(anchor => {
- anchor.setAttribute('target', '_blank');
+ if (anchor.hostname === window.location.hostname) {
+ anchor.setAttribute('target', '_self');
+ } else {
+ anchor.setAttribute('target', '_blank');
+ }
anchor.setAttribute('rel', 'noopener');
});
}
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html
index 2b2fcfc..ff94bc7 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html
@@ -146,7 +146,7 @@
const linkEl = element.$.output.childNodes[1];
assert.equal(textNode.textContent, prefix);
const url = '/q/' + changeID;
- assert.equal(linkEl.target, '_blank');
+ assert.equal(linkEl.target, '_self');
// Since url is a path, the host is added automatically.
assert.isTrue(linkEl.href.endsWith(url));
assert.equal(linkEl.textContent, changeID);
@@ -164,7 +164,7 @@
const linkEl = element.$.output.childNodes[1];
assert.equal(textNode.textContent, prefix);
const url = '/r/q/' + changeID;
- assert.equal(linkEl.target, '_blank');
+ assert.equal(linkEl.target, '_self');
// Since url is a path, the host is added automatically.
assert.isTrue(linkEl.href.endsWith(url));
assert.equal(linkEl.textContent, changeID);
@@ -205,7 +205,7 @@
assert.equal(textNode.textContent, prefix);
- assert.equal(changeLinkEl.target, '_blank');
+ assert.equal(changeLinkEl.target, '_self');
assert.isTrue(changeLinkEl.href.endsWith(changeUrl));
assert.equal(changeLinkEl.textContent, changeID);
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper.js
index 2c326df..0c8ca06 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper.js
@@ -359,15 +359,16 @@
fetchOptions: options,
anonymizedUrl: req.reportUrlAsIs ? url : req.anonymizedUrl,
};
- const xhr = this.fetch(fetchReq).then(response => {
- if (!response.ok) {
- if (req.errFn) {
- return req.errFn.call(undefined, response);
- }
- this.fire('server-error', {request: fetchReq, response});
- }
- return response;
- })
+ const xhr = this.fetch(fetchReq)
+ .then(response => {
+ if (!response.ok) {
+ if (req.errFn) {
+ return req.errFn.call(undefined, response);
+ }
+ this.fire('server-error', {request: fetchReq, response});
+ }
+ return response;
+ })
.catch(err => {
this.fire('network-error', {error: err});
if (req.errFn) {
diff --git a/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.html b/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.html
index 5fad3f4..f64d9ef 100644
--- a/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.html
+++ b/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.html
@@ -23,8 +23,8 @@
<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<script src="/bower_components/web-component-tester/browser.js"></script>
-<script src="../../../test/test-pre-setup.js"></script>
-<link rel="import" href="../../../test/common-test-setup.html"/>
+<script src="../../test/test-pre-setup.js"></script>
+<link rel="import" href="../../test/common-test-setup.html"/>
<link rel="import" href="../../elements/shared/gr-rest-api-interface/gr-rest-api-interface.html"/>
<script src="../gr-display-name-utils/gr-display-name-utils.js"></script>
<script src="gr-email-suggestions-provider.js"></script>
diff --git a/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.html b/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.html
index 7d89c2a..c46b443 100644
--- a/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.html
+++ b/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.html
@@ -23,8 +23,8 @@
<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<script src="/bower_components/web-component-tester/browser.js"></script>
-<script src="../../../test/test-pre-setup.js"></script>
-<link rel="import" href="../../../test/common-test-setup.html"/>
+<script src="../../test/test-pre-setup.js"></script>
+<link rel="import" href="../../test/common-test-setup.html"/>
<link rel="import" href="../../elements/shared/gr-rest-api-interface/gr-rest-api-interface.html"/>
<script src="../gr-display-name-utils/gr-display-name-utils.js"></script>
<script src="gr-group-suggestions-provider.js"></script>
diff --git a/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider_test.html b/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider_test.html
index af7b4bd..9696c2e 100644
--- a/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider_test.html
+++ b/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider_test.html
@@ -23,8 +23,8 @@
<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<script src="/bower_components/web-component-tester/browser.js"></script>
-<script src="../../../test/test-pre-setup.js"></script>
-<link rel="import" href="../../../test/common-test-setup.html"/>
+<script src="../../test/test-pre-setup.js"></script>
+<link rel="import" href="../../test/common-test-setup.html"/>
<link rel="import" href="../../elements/shared/gr-rest-api-interface/gr-rest-api-interface.html"/>
<script src="../gr-display-name-utils/gr-display-name-utils.js"></script>
<script src="gr-reviewer-suggestions-provider.js"></script>
diff --git a/proto/cache.proto b/proto/cache.proto
index 8f73388..b881e3d 100644
--- a/proto/cache.proto
+++ b/proto/cache.proto
@@ -75,7 +75,7 @@
// Instead, we just take the tedious yet simple approach of having a "has_foo"
// field for each nullable field "foo", indicating whether or not foo is null.
//
-// Next ID: 23
+// Next ID: 24
message ChangeNotesStateProto {
// Effectively required, even though the corresponding ChangeNotesState field
// is optional, since the field is only absent when NoteDb is disabled, in
@@ -133,7 +133,7 @@
// which case attempting to use the ChangeNotesCache is programmer error.
ChangeColumnsProto columns = 3;
- reserved 4; // past_assignee
+ reserved 4; // past_assignee
repeated string hashtag = 5;
@@ -167,6 +167,7 @@
// Next ID: 5
message ReviewerStatusUpdateProto {
+ // Epoch millis.
int64 date = 1;
int32 updated_by = 2;
int32 reviewer = 3;
@@ -194,14 +195,26 @@
bool has_server_id = 21;
message AssigneeStatusUpdateProto {
+ // Epoch millis.
int64 date = 1;
int32 updated_by = 2;
int32 current_assignee = 3;
bool has_current_assignee = 4;
}
repeated AssigneeStatusUpdateProto assignee_update = 22;
-}
+ // An update to the attention set of the change. See class AttentionStatus for
+ // context.
+ message AttentionStatusProto {
+ // Epoch millis.
+ int64 date = 1;
+ int32 account = 2;
+ // Maps to enum AttentionStatus.Operation
+ string operation = 3;
+ string reason = 4;
+ }
+ repeated AttentionStatusProto attention_status = 23;
+}
// Serialized form of com.google.gerrit.server.query.change.ConflictKey
message ConflictKeyProto {
diff --git a/tools/bzl/plugin.bzl b/tools/bzl/plugin.bzl
index 64a6e22..3cffb79 100644
--- a/tools/bzl/plugin.bzl
+++ b/tools/bzl/plugin.bzl
@@ -51,16 +51,21 @@
# TODO(davido): Remove manual merge of manifest file when this feature
# request is implemented: https://github.com/bazelbuild/bazel/issues/2009
+ # TODO(davido): Remove manual touch command when this issue is resolved:
+ # https://github.com/bazelbuild/bazel/issues/10789
genrule2(
name = name + target_suffix,
stamp = 1,
srcs = ["%s__non_stamped_deploy.jar" % name],
cmd = " && ".join([
+ "TZ=UTC",
+ "export TZ",
"GEN_VERSION=$$(cat bazel-out/stable-status.txt | grep -w STABLE_BUILD_%s_LABEL | cut -d ' ' -f 2)" % dir_name.upper(),
"cd $$TMP",
"unzip -q $$ROOT/$<",
"echo \"Implementation-Version: $$GEN_VERSION\n$$(cat META-INF/MANIFEST.MF)\" > META-INF/MANIFEST.MF",
- "zip -qr $$ROOT/$@ .",
+ "find . -exec touch '{}' ';'",
+ "zip -Xqr $$ROOT/$@ .",
]),
outs = ["%s%s.jar" % (name, target_suffix)],
visibility = ["//visibility:public"],