Allow Reporter to take events with a "showOnce" tag to suppress handling of
duplicate events.

PiperOrigin-RevId: 240172573
diff --git a/src/main/java/com/google/devtools/build/lib/events/Reporter.java b/src/main/java/com/google/devtools/build/lib/events/Reporter.java
index 376773f..1e0bf85 100644
--- a/src/main/java/com/google/devtools/build/lib/events/Reporter.java
+++ b/src/main/java/com/google/devtools/build/lib/events/Reporter.java
@@ -18,6 +18,7 @@
 import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.util.io.OutErr;
 import java.io.PrintStream;
+import java.util.HashSet;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 /**
@@ -56,6 +57,13 @@
   private EventHandler ansiAllowingHandler;
   private EventHandler ansiStrippingHandler;
   private boolean ansiAllowingHandlerRegistered;
+  private final HashSet<String> eventsShown = new HashSet<>();
+
+  /**
+   * The tag that indicates to the reporter to suppress this event if it's a duplicate of another
+   * event with this tag.
+   */
+  public static final String SHOW_ONCE_TAG = "showOnce";
 
   public Reporter(EventBus eventBus) {
     this.eventBus = eventBus;
@@ -121,6 +129,13 @@
       return;
     }
 
+    if (SHOW_ONCE_TAG.equals(e.getTag())) {
+      if (eventsShown.contains(e.toString())) {
+        return;
+      }
+      eventsShown.add(e.toString());
+    }
+
     for (EventHandler handler : eventHandlers) {
       handler.handle(e);
     }
diff --git a/src/test/java/com/google/devtools/build/lib/events/ReporterTest.java b/src/test/java/com/google/devtools/build/lib/events/ReporterTest.java
index 63e8751..aea3f7b 100644
--- a/src/test/java/com/google/devtools/build/lib/events/ReporterTest.java
+++ b/src/test/java/com/google/devtools/build/lib/events/ReporterTest.java
@@ -14,6 +14,7 @@
 package com.google.devtools.build.lib.events;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.devtools.build.lib.events.Reporter.SHOW_ONCE_TAG;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.eventbus.EventBus;
@@ -71,6 +72,23 @@
   }
 
   @Test
+  public void reporterIgnoresDuplicateEventsWithShowOnce() {
+    ImmutableList<Event> duplicates =
+        ImmutableList.of(
+            Event.warn("ShowMeOnce").withTag(SHOW_ONCE_TAG),
+            Event.warn("ShowMeOnce").withTag(SHOW_ONCE_TAG),
+            Event.warn("ShowMeOnce").withTag(SHOW_ONCE_TAG),
+            Event.warn("ShowMeOnce").withTag(SHOW_ONCE_TAG));
+    EventCollector collector = new EventCollector();
+    reporter.addHandler(collector);
+    for (Event e : duplicates) {
+      reporter.handle(e);
+    }
+    ImmutableList<Event> got = ImmutableList.copyOf(collector);
+    assertThat(got).containsExactly(Event.warn("ShowMeOnce").withTag(SHOW_ONCE_TAG));
+  }
+
+  @Test
   public void reporterCopyConstructorCopiesHandlersList() {
     reporter.addHandler(outAppender);
     reporter.addHandler(outAppender);