Report completion of a target together with failed actions

Report the completion of all targets together with the root causes on the build
event stream. To do so, have TargetCompleteEvent and ActionExecutedEvent be
instances of BuildEvent; however, ignore an ActionExecutedEvent in the
BuildEventStreamer if the execution was successful.

By this change we get, for the first time, a build event stream that is naturally
closed, i.e., without Aborted events closing up lose ends. Add a test asserting
this property.

--
Change-Id: Ie90dd52ee80deb0fdabdce1da551935522880a1a
Reviewed-on: https://bazel-review.googlesource.com/#/c/6279
MOS_MIGRATED_REVID=137273002
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/TargetCompleteEvent.java b/src/main/java/com/google/devtools/build/lib/analysis/TargetCompleteEvent.java
index 6fea59f..ae1327d 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/TargetCompleteEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/TargetCompleteEvent.java
@@ -14,18 +14,22 @@
 
 package com.google.devtools.build.lib.analysis;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.buildeventstream.BuildEvent;
+import com.google.devtools.build.lib.buildeventstream.BuildEventId;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
+import com.google.devtools.build.lib.buildeventstream.GenericBuildEvent;
 import com.google.devtools.build.lib.causes.Cause;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.skyframe.SkyValue;
+import java.util.Collection;
 
-/**
- * This event is fired as soon as a target is either built or fails.
- */
-public final class TargetCompleteEvent implements SkyValue {
+/** This event is fired as soon as a target is either built or fails. */
+public final class TargetCompleteEvent implements SkyValue, BuildEvent {
 
   private final ConfiguredTarget target;
   private final NestedSet<Cause> rootCauses;
@@ -69,4 +73,25 @@
   public Iterable<Cause> getRootCauses() {
     return rootCauses;
   }
+
+  @Override
+  public BuildEventId getEventId() {
+    return BuildEventId.targetCompleted(getTarget().getLabel());
+  }
+
+  @Override
+  public Collection<BuildEventId> getChildrenEvents() {
+    ImmutableList.Builder childrenBuilder = ImmutableList.builder();
+    for (Cause cause : getRootCauses()) {
+      childrenBuilder.add(BuildEventId.fromCause(cause));
+    }
+    return childrenBuilder.build();
+  }
+
+  @Override
+  public BuildEventStreamProtos.BuildEvent asStreamProto() {
+    BuildEventStreamProtos.TargetComplete complete =
+        BuildEventStreamProtos.TargetComplete.newBuilder().setSuccess(!failed()).build();
+    return GenericBuildEvent.protoChaining(this).setCompleted(complete).build();
+  }
 }