Merge "Fix chat panel visibility issues in dark theme"
diff --git a/java/com/google/gerrit/pgm/Daemon.java b/java/com/google/gerrit/pgm/Daemon.java
index b3e4dfc..316fee9 100644
--- a/java/com/google/gerrit/pgm/Daemon.java
+++ b/java/com/google/gerrit/pgm/Daemon.java
@@ -92,6 +92,7 @@
import com.google.gerrit.server.config.GerritRuntime;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.LogConfig;
+import com.google.gerrit.server.config.SendEmailEnabledModule;
import com.google.gerrit.server.config.SysExecutorModule;
import com.google.gerrit.server.events.EventBroker.EventBrokerModule;
import com.google.gerrit.server.events.StreamEventsApiListener.StreamEventsApiListenerModule;
@@ -543,6 +544,7 @@
modules.add(new StartupChecksModule());
modules.add(new GerritInstanceNameModule());
modules.add(new GerritInstanceIdModule());
+ modules.add(new SendEmailEnabledModule());
if (MoreObjects.firstNonNull(httpd, true)) {
modules.add(
new CanonicalWebUrlModule() {
diff --git a/java/com/google/gerrit/server/change/ChangeInserter.java b/java/com/google/gerrit/server/change/ChangeInserter.java
index 3f7b2bb..fad9208 100644
--- a/java/com/google/gerrit/server/change/ChangeInserter.java
+++ b/java/com/google/gerrit/server/change/ChangeInserter.java
@@ -58,6 +58,7 @@
import com.google.gerrit.server.change.ReviewerModifier.InternalReviewerInput;
import com.google.gerrit.server.change.ReviewerModifier.ReviewerModification;
import com.google.gerrit.server.change.ReviewerModifier.ReviewerModificationList;
+import com.google.gerrit.server.config.SendEmailEnabled;
import com.google.gerrit.server.config.SendEmailExecutor;
import com.google.gerrit.server.events.CommitReceivedEvent;
import com.google.gerrit.server.extensions.events.CommentAdded;
@@ -136,6 +137,7 @@
private final DiffOperationsForCommitValidation.Factory diffOperationsForCommitValidationFactory;
private final PluginSetContext<ValidationOptionsListener> validationOptionsListeners;
private final PluginSetContext<CommitValidationInfoListener> commitValidationInfoListeners;
+ private final boolean sendEmailEnabled;
private final Change.Id changeId;
private final PatchSet.Id psId;
@@ -184,6 +186,7 @@
ChangeMessagesUtil cmUtil,
EmailFactories emailFactories,
@SendEmailExecutor ExecutorService sendEmailExecutor,
+ @SendEmailEnabled Boolean sendEmailEnabled,
CommitValidators.Factory commitValidatorsFactory,
TopicValidator topicValidator,
CommentAdded commentAdded,
@@ -226,6 +229,7 @@
this.approvals = Collections.emptyMap();
this.fireRevisionCreated = true;
this.sendMail = true;
+ this.sendEmailEnabled = sendEmailEnabled;
this.updateRef = true;
}
@@ -601,7 +605,7 @@
public void postUpdate(PostUpdateContext ctx) throws Exception {
reviewerAdditions.postUpdate(ctx);
NotifyResolver.Result notify = ctx.getNotify(change.getId());
- if (sendMail) {
+ if (sendMail && sendEmailEnabled) {
Runnable sender =
new Runnable() {
@Override
diff --git a/java/com/google/gerrit/server/change/EmailNewPatchSet.java b/java/com/google/gerrit/server/change/EmailNewPatchSet.java
index 30d82a4..dc6935e 100644
--- a/java/com/google/gerrit/server/change/EmailNewPatchSet.java
+++ b/java/com/google/gerrit/server/change/EmailNewPatchSet.java
@@ -16,6 +16,8 @@
import static com.google.gerrit.server.mail.EmailFactories.NEW_PATCHSET_ADDED;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
@@ -29,6 +31,7 @@
import com.google.gerrit.extensions.client.ChangeKind;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.config.SendEmailEnabled;
import com.google.gerrit.server.config.SendEmailExecutor;
import com.google.gerrit.server.mail.EmailFactories;
import com.google.gerrit.server.mail.send.ChangeEmail;
@@ -68,13 +71,15 @@
private final ExecutorService sendEmailExecutor;
private final ThreadLocalRequestContext threadLocalRequestContext;
- private final AsyncSender asyncSender;
+ private final Supplier<AsyncSender> asyncSenderSupplier;
+ private final boolean sendEmailEnabled;
private RequestScopePropagator requestScopePropagator;
@Inject
EmailNewPatchSet(
@SendEmailExecutor ExecutorService sendEmailExecutor,
+ @SendEmailEnabled Boolean sendEmailEnabled,
ThreadLocalRequestContext threadLocalRequestContext,
EmailFactories emailFactories,
PatchSetInfoFactory patchSetInfoFactory,
@@ -88,45 +93,49 @@
@Assisted ChangeKind changeKind,
@Assisted ObjectId preUpdateMetaId) {
this.sendEmailExecutor = sendEmailExecutor;
+ this.sendEmailEnabled = sendEmailEnabled;
this.threadLocalRequestContext = threadLocalRequestContext;
- MessageId messageId;
- try {
- messageId =
- messageIdGenerator.fromChangeUpdateAndReason(
- postUpdateContext.getRepoView(), patchSet.id(), "EmailReplacePatchSet");
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
+ this.asyncSenderSupplier =
+ Suppliers.memoize(
+ () -> {
+ MessageId messageId;
+ try {
+ messageId =
+ messageIdGenerator.fromChangeUpdateAndReason(
+ postUpdateContext.getRepoView(), patchSet.id(), "EmailReplacePatchSet");
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
- Change.Id changeId = patchSet.id().changeId();
+ Change.Id changeId = patchSet.id().changeId();
- // Getting the change data from PostUpdateContext retrieves a cached ChangeData
- // instance. This ChangeData instance has been created when the change was (re)indexed
- // due to the update, and hence has submit requirement results already cached (since
- // (re)indexing triggers the evaluation of the submit requirements).
- Map<SubmitRequirement, SubmitRequirementResult> postUpdateSubmitRequirementResults =
- postUpdateContext
- .getChangeData(postUpdateContext.getProject(), changeId)
- .submitRequirementsIncludingLegacy();
- this.asyncSender =
- new AsyncSender(
- postUpdateContext.getIdentifiedUser(),
- emailFactories,
- patchSetInfoFactory,
- messageId,
- postUpdateContext.getNotify(changeId),
- postUpdateContext.getProject(),
- changeId,
- patchSet,
- message,
- postUpdateContext.getWhen(),
- outdatedApprovals,
- reviewers,
- extraCcs,
- changeKind,
- preUpdateMetaId,
- postUpdateSubmitRequirementResults);
+ // Getting the change data from PostUpdateContext retrieves a cached ChangeData
+ // instance. This ChangeData instance has been created when the change was (re)indexed
+ // due to the update, and hence has submit requirement results already cached (since
+ // (re)indexing triggers the evaluation of the submit requirements).
+ Map<SubmitRequirement, SubmitRequirementResult> postUpdateSubmitRequirementResults =
+ postUpdateContext
+ .getChangeData(postUpdateContext.getProject(), changeId)
+ .submitRequirementsIncludingLegacy();
+ return new AsyncSender(
+ postUpdateContext.getIdentifiedUser(),
+ emailFactories,
+ patchSetInfoFactory,
+ messageId,
+ postUpdateContext.getNotify(changeId),
+ postUpdateContext.getProject(),
+ changeId,
+ patchSet,
+ message,
+ postUpdateContext.getWhen(),
+ outdatedApprovals,
+ reviewers,
+ extraCcs,
+ changeKind,
+ preUpdateMetaId,
+ postUpdateSubmitRequirementResults);
+ });
}
public EmailNewPatchSet setRequestScopePropagator(RequestScopePropagator requestScopePropagator) {
@@ -135,15 +144,19 @@
}
public void sendAsync() {
+ if (!sendEmailEnabled) {
+ return;
+ }
@SuppressWarnings("unused")
Future<?> possiblyIgnoredError =
sendEmailExecutor.submit(
requestScopePropagator != null
- ? requestScopePropagator.wrap(asyncSender)
+ ? requestScopePropagator.wrap(asyncSenderSupplier.get())
: () -> {
- RequestContext old = threadLocalRequestContext.setContext(asyncSender);
+ RequestContext old =
+ threadLocalRequestContext.setContext(asyncSenderSupplier.get());
try {
- asyncSender.run();
+ asyncSenderSupplier.get().run();
} finally {
@SuppressWarnings("unused")
var unused = threadLocalRequestContext.setContext(old);
diff --git a/java/com/google/gerrit/server/change/EmailReviewComments.java b/java/com/google/gerrit/server/change/EmailReviewComments.java
index bb93cd3..880cca3 100644
--- a/java/com/google/gerrit/server/change/EmailReviewComments.java
+++ b/java/com/google/gerrit/server/change/EmailReviewComments.java
@@ -17,6 +17,8 @@
import static com.google.gerrit.server.CommentsUtil.COMMENT_ORDER;
import static com.google.gerrit.server.mail.EmailFactories.COMMENTS_ADDED;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
@@ -28,6 +30,7 @@
import com.google.gerrit.entities.SubmitRequirementResult;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.config.SendEmailEnabled;
import com.google.gerrit.server.config.SendEmailExecutor;
import com.google.gerrit.server.mail.EmailFactories;
import com.google.gerrit.server.mail.send.ChangeEmail;
@@ -82,11 +85,13 @@
}
private final ExecutorService sendEmailsExecutor;
- private final AsyncSender asyncSender;
+ private final Supplier<AsyncSender> asyncSenderSupplier;
+ private final boolean sendEmailEnabled;
@Inject
EmailReviewComments(
@SendEmailExecutor ExecutorService executor,
+ @SendEmailEnabled Boolean sendEmailEnabled,
PatchSetInfoFactory patchSetInfoFactory,
EmailFactories emailFactories,
ThreadLocalRequestContext requestContext,
@@ -99,49 +104,56 @@
@Nullable @Assisted("patchSetComment") String patchSetComment,
@Assisted List<LabelVote> labels) {
this.sendEmailsExecutor = executor;
+ this.sendEmailEnabled = sendEmailEnabled;
- MessageId messageId;
- try {
- messageId =
- messageIdGenerator.fromChangeUpdateAndReason(
- postUpdateContext.getRepoView(), patchSet.id(), "EmailReviewComments");
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
+ this.asyncSenderSupplier =
+ Suppliers.memoize(
+ () -> {
+ MessageId messageId;
+ try {
+ messageId =
+ messageIdGenerator.fromChangeUpdateAndReason(
+ postUpdateContext.getRepoView(), patchSet.id(), "EmailReviewComments");
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
- Change.Id changeId = patchSet.id().changeId();
+ Change.Id changeId = patchSet.id().changeId();
- // Getting the change data from PostUpdateContext retrieves a cached ChangeData
- // instance. This ChangeData instance has been created when the change was (re)indexed
- // due to the update, and hence has submit requirement results already cached (since
- // (re)indexing triggers the evaluation of the submit requirements).
- Map<SubmitRequirement, SubmitRequirementResult> postUpdateSubmitRequirementResults =
- postUpdateContext
- .getChangeData(postUpdateContext.getProject(), changeId)
- .submitRequirementsIncludingLegacy();
- this.asyncSender =
- new AsyncSender(
- requestContext,
- emailFactories,
- patchSetInfoFactory,
- postUpdateContext.getUser().asIdentifiedUser(),
- messageId,
- postUpdateContext.getNotify(changeId),
- postUpdateContext.getProject(),
- changeId,
- patchSet,
- preUpdateMetaId,
- message,
- postUpdateContext.getWhen(),
- ImmutableList.copyOf(COMMENT_ORDER.sortedCopy(comments)),
- patchSetComment,
- ImmutableList.copyOf(labels),
- postUpdateSubmitRequirementResults);
+ // Getting the change data from PostUpdateContext retrieves a cached ChangeData
+ // instance. This ChangeData instance has been created when the change was (re)indexed
+ // due to the update, and hence has submit requirement results already cached (since
+ // (re)indexing triggers the evaluation of the submit requirements).
+ Map<SubmitRequirement, SubmitRequirementResult> postUpdateSubmitRequirementResults =
+ postUpdateContext
+ .getChangeData(postUpdateContext.getProject(), changeId)
+ .submitRequirementsIncludingLegacy();
+ return new AsyncSender(
+ requestContext,
+ emailFactories,
+ patchSetInfoFactory,
+ postUpdateContext.getUser().asIdentifiedUser(),
+ messageId,
+ postUpdateContext.getNotify(changeId),
+ postUpdateContext.getProject(),
+ changeId,
+ patchSet,
+ preUpdateMetaId,
+ message,
+ postUpdateContext.getWhen(),
+ ImmutableList.copyOf(COMMENT_ORDER.sortedCopy(comments)),
+ patchSetComment,
+ ImmutableList.copyOf(labels),
+ postUpdateSubmitRequirementResults);
+ });
}
public void sendAsync() {
+ if (!sendEmailEnabled) {
+ return;
+ }
@SuppressWarnings("unused")
- Future<?> possiblyIgnoredError = sendEmailsExecutor.submit(asyncSender);
+ Future<?> possiblyIgnoredError = sendEmailsExecutor.submit(asyncSenderSupplier.get());
}
/**
diff --git a/java/com/google/gerrit/server/change/ModifyReviewersEmail.java b/java/com/google/gerrit/server/change/ModifyReviewersEmail.java
index cac40d1..369d080 100644
--- a/java/com/google/gerrit/server/change/ModifyReviewersEmail.java
+++ b/java/com/google/gerrit/server/change/ModifyReviewersEmail.java
@@ -23,6 +23,7 @@
import com.google.gerrit.entities.Address;
import com.google.gerrit.entities.Change;
import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.config.SendEmailEnabled;
import com.google.gerrit.server.config.SendEmailExecutor;
import com.google.gerrit.server.mail.EmailFactories;
import com.google.gerrit.server.mail.send.ChangeEmail;
@@ -42,14 +43,17 @@
private final EmailFactories emailFactories;
private final ExecutorService sendEmailsExecutor;
private final MessageIdGenerator messageIdGenerator;
+ private final boolean sendEmailEnabled;
@Inject
ModifyReviewersEmail(
EmailFactories emailFactories,
@SendEmailExecutor ExecutorService sendEmailsExecutor,
+ @SendEmailEnabled Boolean sendEmailEnabled,
MessageIdGenerator messageIdGenerator) {
this.emailFactories = emailFactories;
this.sendEmailsExecutor = sendEmailsExecutor;
+ this.sendEmailEnabled = sendEmailEnabled;
this.messageIdGenerator = messageIdGenerator;
}
@@ -63,6 +67,9 @@
Collection<Address> copiedByEmail,
Collection<Address> removedByEmail,
NotifyResolver.Result notify) {
+ if (!sendEmailEnabled) {
+ return;
+ }
// The user knows they added/removed themselves, don't bother emailing them.
Account.Id userId = user.getAccountId();
ImmutableList<Account.Id> immutableToMail =
diff --git a/java/com/google/gerrit/server/config/SendEmailEnabled.java b/java/com/google/gerrit/server/config/SendEmailEnabled.java
new file mode 100644
index 0000000..f52349f
--- /dev/null
+++ b/java/com/google/gerrit/server/config/SendEmailEnabled.java
@@ -0,0 +1,25 @@
+// Copyright (C) 2026 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.config;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.inject.BindingAnnotation;
+import java.lang.annotation.Retention;
+
+/** Marker on a {@link Boolean} holding whether email sending is enabled. */
+@Retention(RUNTIME)
+@BindingAnnotation
+public @interface SendEmailEnabled {}
diff --git a/java/com/google/gerrit/server/config/SendEmailEnabledModule.java b/java/com/google/gerrit/server/config/SendEmailEnabledModule.java
new file mode 100644
index 0000000..9f4e071
--- /dev/null
+++ b/java/com/google/gerrit/server/config/SendEmailEnabledModule.java
@@ -0,0 +1,30 @@
+// Copyright (C) 2026 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.config;
+
+import static com.google.inject.Scopes.SINGLETON;
+
+import com.google.inject.AbstractModule;
+
+/** Supports binding the {@link SendEmailEnabled} annotation. */
+public class SendEmailEnabledModule extends AbstractModule {
+ @Override
+ protected void configure() {
+ bind(Boolean.class)
+ .annotatedWith(SendEmailEnabled.class)
+ .toProvider(SendEmailEnabledProvider.class)
+ .in(SINGLETON);
+ }
+}
diff --git a/java/com/google/gerrit/server/config/SendEmailEnabledProvider.java b/java/com/google/gerrit/server/config/SendEmailEnabledProvider.java
new file mode 100644
index 0000000..a9a5a39
--- /dev/null
+++ b/java/com/google/gerrit/server/config/SendEmailEnabledProvider.java
@@ -0,0 +1,36 @@
+// Copyright (C) 2026 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.config;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import org.eclipse.jgit.lib.Config;
+
+/** Provides whether email sending is enabled from {@code sendemail.enable}. */
+@Singleton
+public class SendEmailEnabledProvider implements Provider<Boolean> {
+ private final boolean enabled;
+
+ @Inject
+ public SendEmailEnabledProvider(@GerritServerConfig Config cfg) {
+ enabled = cfg.getBoolean("sendemail", null, "enable", true);
+ }
+
+ @Override
+ public Boolean get() {
+ return enabled;
+ }
+}
diff --git a/java/com/google/gerrit/server/git/MergedByPushOp.java b/java/com/google/gerrit/server/git/MergedByPushOp.java
index a3c8deb..3360c3f 100644
--- a/java/com/google/gerrit/server/git/MergedByPushOp.java
+++ b/java/com/google/gerrit/server/git/MergedByPushOp.java
@@ -25,6 +25,7 @@
import com.google.gerrit.entities.SubmissionId;
import com.google.gerrit.server.ChangeMessagesUtil;
import com.google.gerrit.server.PatchSetUtil;
+import com.google.gerrit.server.config.SendEmailEnabled;
import com.google.gerrit.server.config.SendEmailExecutor;
import com.google.gerrit.server.extensions.events.ChangeMerged;
import com.google.gerrit.server.mail.EmailFactories;
@@ -76,6 +77,7 @@
private final ExecutorService sendEmailExecutor;
private final ChangeMerged changeMerged;
private final MessageIdGenerator messageIdGenerator;
+ private final boolean sendEmailEnabled;
private final PatchSet.Id psId;
private final SubmissionId submissionId;
@@ -95,6 +97,7 @@
EmailFactories emailFactories,
PatchSetUtil psUtil,
@SendEmailExecutor ExecutorService sendEmailExecutor,
+ @SendEmailEnabled Boolean sendEmailEnabled,
ChangeMerged changeMerged,
MessageIdGenerator messageIdGenerator,
@Assisted RequestScopePropagator requestScopePropagator,
@@ -107,6 +110,7 @@
this.emailFactories = emailFactories;
this.psUtil = psUtil;
this.sendEmailExecutor = sendEmailExecutor;
+ this.sendEmailEnabled = sendEmailEnabled;
this.changeMerged = changeMerged;
this.messageIdGenerator = messageIdGenerator;
this.requestScopePropagator = requestScopePropagator;
@@ -182,41 +186,44 @@
if (!correctBranch) {
return;
}
- @SuppressWarnings("unused") // Runnable already handles errors
- Future<?> possiblyIgnoredError =
- sendEmailExecutor.submit(
- requestScopePropagator.wrap(
- new Runnable() {
- @Override
- public void run() {
- try {
- // The stickyApprovalDiff is always empty here since this is not supported
- // for direct pushes.
- ChangeEmail changeEmail =
- emailFactories.createChangeEmail(
- ctx.getProject(),
- psId.changeId(),
- emailFactories.createMergedChangeEmail(
- /* stickyApprovalDiff= */ Optional.empty(),
- /* modifiedFiles= */ List.of()));
- changeEmail.setPatchSet(patchSet, info);
- OutgoingEmail outgoingEmail =
- emailFactories.createOutgoingEmail(CHANGE_MERGED, changeEmail);
- outgoingEmail.setFrom(ctx.getAccountId());
- outgoingEmail.setMessageId(
- messageIdGenerator.fromChangeUpdate(ctx.getRepoView(), patchSet.id()));
- outgoingEmail.send();
- } catch (Exception e) {
- logger.atSevere().withCause(e).log(
- "Cannot send email for submitted patch set %s", psId);
- }
- }
- @Override
- public String toString() {
- return "send-email merged";
- }
- }));
+ if (sendEmailEnabled) {
+ @SuppressWarnings("unused") // Runnable already handles errors
+ Future<?> possiblyIgnoredError =
+ sendEmailExecutor.submit(
+ requestScopePropagator.wrap(
+ new Runnable() {
+ @Override
+ public void run() {
+ try {
+ // The stickyApprovalDiff is always empty here since this is not supported
+ // for direct pushes.
+ ChangeEmail changeEmail =
+ emailFactories.createChangeEmail(
+ ctx.getProject(),
+ psId.changeId(),
+ emailFactories.createMergedChangeEmail(
+ /* stickyApprovalDiff= */ Optional.empty(),
+ /* modifiedFiles= */ List.of()));
+ changeEmail.setPatchSet(patchSet, info);
+ OutgoingEmail outgoingEmail =
+ emailFactories.createOutgoingEmail(CHANGE_MERGED, changeEmail);
+ outgoingEmail.setFrom(ctx.getAccountId());
+ outgoingEmail.setMessageId(
+ messageIdGenerator.fromChangeUpdate(ctx.getRepoView(), patchSet.id()));
+ outgoingEmail.send();
+ } catch (Exception e) {
+ logger.atSevere().withCause(e).log(
+ "Cannot send email for submitted patch set %s", psId);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "send-email merged";
+ }
+ }));
+ }
changeMerged.fire(
ctx.getChangeData(change), patchSet, ctx.getAccount(), mergeResultRevId, ctx.getWhen());
diff --git a/java/com/google/gerrit/server/mail/send/SmtpEmailSender.java b/java/com/google/gerrit/server/mail/send/SmtpEmailSender.java
index 7e5855d..c050c13 100644
--- a/java/com/google/gerrit/server/mail/send/SmtpEmailSender.java
+++ b/java/com/google/gerrit/server/mail/send/SmtpEmailSender.java
@@ -27,6 +27,7 @@
import com.google.gerrit.exceptions.EmailException;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.config.SendEmailEnabled;
import com.google.gerrit.server.mail.Encryption;
import com.google.gerrit.server.util.time.TimeUtil;
import com.google.inject.AbstractModule;
@@ -91,8 +92,8 @@
private int expiryDays;
@Inject
- SmtpEmailSender(@GerritServerConfig Config cfg) {
- enabled = cfg.getBoolean("sendemail", null, "enable", true);
+ SmtpEmailSender(@GerritServerConfig Config cfg, @SendEmailEnabled Boolean enabled) {
+ this.enabled = enabled;
connectTimeout =
Ints.checkedCast(
ConfigUtil.getTimeUnit(
diff --git a/java/com/google/gerrit/server/submit/EmailMerge.java b/java/com/google/gerrit/server/submit/EmailMerge.java
index 4bd6f3d..25c7566 100644
--- a/java/com/google/gerrit/server/submit/EmailMerge.java
+++ b/java/com/google/gerrit/server/submit/EmailMerge.java
@@ -24,6 +24,7 @@
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.change.NotifyResolver;
+import com.google.gerrit.server.config.SendEmailEnabled;
import com.google.gerrit.server.config.SendEmailExecutor;
import com.google.gerrit.server.mail.EmailFactories;
import com.google.gerrit.server.mail.send.ChangeEmail;
@@ -59,6 +60,7 @@
private final EmailFactories emailFactories;
private final ThreadLocalRequestContext requestContext;
private final MessageIdGenerator messageIdGenerator;
+ private final boolean sendEmailEnabled;
private final Project.NameKey project;
private final Change change;
@@ -71,6 +73,7 @@
@Inject
EmailMerge(
@SendEmailExecutor ExecutorService executor,
+ @SendEmailEnabled Boolean sendEmailEnabled,
EmailFactories emailFactories,
ThreadLocalRequestContext requestContext,
MessageIdGenerator messageIdGenerator,
@@ -82,6 +85,7 @@
@Assisted String stickyApprovalDiff,
@Assisted List<FileDiffOutput> modifiedFiles) {
this.sendEmailsExecutor = executor;
+ this.sendEmailEnabled = sendEmailEnabled;
this.emailFactories = emailFactories;
this.requestContext = requestContext;
this.messageIdGenerator = messageIdGenerator;
@@ -95,6 +99,9 @@
}
void sendAsync() {
+ if (!sendEmailEnabled) {
+ return;
+ }
@SuppressWarnings("unused")
Future<?> possiblyIgnoredError = sendEmailsExecutor.submit(this);
}
diff --git a/java/com/google/gerrit/server/util/AttentionSetEmail.java b/java/com/google/gerrit/server/util/AttentionSetEmail.java
index 95fc246..e6a5f3d 100644
--- a/java/com/google/gerrit/server/util/AttentionSetEmail.java
+++ b/java/com/google/gerrit/server/util/AttentionSetEmail.java
@@ -17,12 +17,15 @@
import static com.google.gerrit.server.mail.EmailFactories.ATTENTION_SET_ADDED;
import static com.google.gerrit.server.mail.EmailFactories.ATTENTION_SET_REMOVED;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.change.NotifyResolver;
+import com.google.gerrit.server.config.SendEmailEnabled;
import com.google.gerrit.server.config.SendEmailExecutor;
import com.google.gerrit.server.mail.EmailFactories;
import com.google.gerrit.server.mail.send.AttentionSetChangeEmailDecorator;
@@ -63,11 +66,13 @@
}
private final ExecutorService sendEmailsExecutor;
- private final AsyncSender asyncSender;
+ private final Supplier<AsyncSender> asyncSenderSupplier;
+ private final boolean sendEmailEnabled;
@Inject
AttentionSetEmail(
@SendEmailExecutor ExecutorService executor,
+ @SendEmailEnabled Boolean sendEmailEnabled,
ThreadLocalRequestContext requestContext,
MessageIdGenerator messageIdGenerator,
AccountTemplateUtil accountTemplateUtil,
@@ -78,33 +83,40 @@
@Assisted String reason,
@Assisted Account.Id attentionUserId) {
this.sendEmailsExecutor = executor;
+ this.sendEmailEnabled = sendEmailEnabled;
- MessageId messageId;
- try {
- messageId =
- messageIdGenerator.fromChangeUpdateAndReason(
- ctx.getRepoView(), change.currentPatchSetId(), "AttentionSetEmail");
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
+ this.asyncSenderSupplier =
+ Suppliers.memoize(
+ () -> {
+ MessageId messageId;
+ try {
+ messageId =
+ messageIdGenerator.fromChangeUpdateAndReason(
+ ctx.getRepoView(), change.currentPatchSetId(), "AttentionSetEmail");
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
- this.asyncSender =
- new AsyncSender(
- requestContext,
- emailFactories,
- ctx.getUser(),
- ctx.getProject(),
- attentionSetChange,
- messageId,
- ctx.getNotify(change.getId()),
- attentionUserId,
- accountTemplateUtil.replaceTemplates(reason),
- change.getId());
+ return new AsyncSender(
+ requestContext,
+ emailFactories,
+ ctx.getUser(),
+ ctx.getProject(),
+ attentionSetChange,
+ messageId,
+ ctx.getNotify(change.getId()),
+ attentionUserId,
+ accountTemplateUtil.replaceTemplates(reason),
+ change.getId());
+ });
}
public void sendAsync() {
+ if (!sendEmailEnabled) {
+ return;
+ }
@SuppressWarnings("unused")
- Future<?> possiblyIgnoredError = sendEmailsExecutor.submit(asyncSender);
+ Future<?> possiblyIgnoredError = sendEmailsExecutor.submit(asyncSenderSupplier.get());
}
/**
diff --git a/java/com/google/gerrit/testing/InMemoryModule.java b/java/com/google/gerrit/testing/InMemoryModule.java
index 657e1f2..745f89a 100644
--- a/java/com/google/gerrit/testing/InMemoryModule.java
+++ b/java/com/google/gerrit/testing/InMemoryModule.java
@@ -87,6 +87,7 @@
import com.google.gerrit.server.config.GerritServerId;
import com.google.gerrit.server.config.GerritServerIdProvider;
import com.google.gerrit.server.config.GlobalPluginConfigProvider;
+import com.google.gerrit.server.config.SendEmailEnabledModule;
import com.google.gerrit.server.config.SendEmailExecutor;
import com.google.gerrit.server.config.SitePath;
import com.google.gerrit.server.config.TrackingFooters;
@@ -267,6 +268,7 @@
install(NoSshKeyCache.module());
install(new GerritInstanceNameModule());
install(new GerritInstanceIdModule());
+ install(new SendEmailEnabledModule());
install(
new CanonicalWebUrlModule() {
@Override
diff --git a/polygerrit-ui/app/utils/comment-util.ts b/polygerrit-ui/app/utils/comment-util.ts
index a44d2c8..4b0c1ab 100644
--- a/polygerrit-ui/app/utils/comment-util.ts
+++ b/polygerrit-ui/app/utils/comment-util.ts
@@ -717,7 +717,12 @@
if (excludePath.path === SpecialFilePath.PATCHSET_LEVEL_COMMENTS) return '';
if (excludePath.line === FILE) return FILE;
if (excludePath.line) return `#${excludePath.line}`;
- if (excludePath.range) return `#${excludePath.range.end_line}`;
+ if (excludePath.range) {
+ // If the range is wrong, we display the start line. Happens to AI generated comments.
+ if (excludePath.range.end_line < excludePath.range.start_line)
+ return `#${excludePath.range.start_line}`;
+ return `#${excludePath.range.end_line}`;
+ }
return '';
}
diff --git a/polygerrit-ui/app/utils/comment-util_test.ts b/polygerrit-ui/app/utils/comment-util_test.ts
index 61d374b..e8fe606 100644
--- a/polygerrit-ui/app/utils/comment-util_test.ts
+++ b/polygerrit-ui/app/utils/comment-util_test.ts
@@ -730,6 +730,20 @@
);
});
+ test('invalid range', () => {
+ assert.equal(
+ computeDisplayLine({
+ range: {
+ start_line: 12,
+ start_character: 1,
+ end_line: 1,
+ end_character: 10,
+ },
+ }),
+ '#12'
+ );
+ });
+
test('empty', () => {
assert.equal(computeDisplayLine({}), '');
});