BEP includes boolean flag indicating incomplete output groups.
Expanding upon d2f93fd969 which includes partially-built output groups in BEP,
this change adds an 'incomplete' flag in BEP informing consumers that the output
group does not include all files intended to be built in that output group.
If a TargetComplete event an incomplete OutputGroup, the TargetComplete will
always have 'success = false'. It is possible that a TargetComplete will be
unsuccessful while all OutputGroups report 'incomplete = true'. One example
is if an output group has zero successful actions and produces no output files.
RELNOTES: In BEP, TargetComplete.output_group has a new field `incomplete`
indicating that the file_sets field is missing one or more declared artifacts
whose generating actions failed.
PiperOrigin-RevId: 362355435
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AspectCompleteEvent.java b/src/main/java/com/google/devtools/build/lib/analysis/AspectCompleteEvent.java
index 6d4c2fa..e1d598f 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/AspectCompleteEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/AspectCompleteEvent.java
@@ -180,6 +180,7 @@
builder.addOutputGroup(
OutputGroup.newBuilder()
.setName(outputGroup)
+ .setIncomplete(artifactsInGroup.isIncomplete())
.addFileSets(namer.apply(artifactsInGroup.getArtifacts().toNode()))));
}
return GenericBuildEvent.protoChaining(this).setCompleted(builder.build()).build();
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 1f5e6f6..acbbb5d 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
@@ -486,6 +486,7 @@
groups.add(
OutputGroup.newBuilder()
.setName(outputGroup)
+ .setIncomplete(artifactsInOutputGroup.isIncomplete())
.addFileSets(namer.apply(artifactsInOutputGroup.getArtifacts().toNode()))
.build());
});
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/TopLevelArtifactHelper.java b/src/main/java/com/google/devtools/build/lib/analysis/TopLevelArtifactHelper.java
index 3d8bac9..060d5e9 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/TopLevelArtifactHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/TopLevelArtifactHelper.java
@@ -50,10 +50,13 @@
@Immutable
public static final class ArtifactsInOutputGroup {
private final boolean important;
+ private final boolean incomplete;
private final NestedSet<Artifact> artifacts;
- private ArtifactsInOutputGroup(boolean important, NestedSet<Artifact> artifacts) {
+ private ArtifactsInOutputGroup(
+ boolean important, boolean incomplete, NestedSet<Artifact> artifacts) {
this.important = important;
+ this.incomplete = incomplete;
this.artifacts = checkNotNull(artifacts);
}
@@ -65,6 +68,10 @@
public boolean areImportant() {
return important;
}
+
+ public boolean isIncomplete() {
+ return incomplete;
+ }
}
/**
@@ -220,7 +227,7 @@
!outputGroup.startsWith(OutputGroupInfo.HIDDEN_OUTPUT_GROUP_PREFIX);
ArtifactsInOutputGroup artifacts =
- new ArtifactsInOutputGroup(isImportantGroup, results.build());
+ new ArtifactsInOutputGroup(isImportantGroup, /*incomplete=*/ false, results.build());
allOutputGroups.put(outputGroup, artifacts);
}
@@ -261,7 +268,8 @@
filteredArtifactsInOutputGroup = artifactsInOutputGroup;
} else {
filteredArtifactsInOutputGroup =
- new ArtifactsInOutputGroup(artifactsInOutputGroup.areImportant(), filteredArtifacts);
+ new ArtifactsInOutputGroup(
+ artifactsInOutputGroup.areImportant(), /*incomplete=*/ true, filteredArtifacts);
leavesDirty = true;
}
if (!filteredArtifactsInOutputGroup.getArtifacts().isEmpty()) {
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto b/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto
index 2e00138..75c6b78 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto
@@ -535,6 +535,10 @@
// List of file sets that belong to this output group as well.
repeated BuildEventId.NamedSetOfFilesId file_sets = 3;
+
+ // Indicates that one or more of the output group's files were not built
+ // successfully (the generating action failed).
+ bool incomplete = 4;
}
// Payload of the event indicating the completion of a target. The target is
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/SuccessfulArtifactFilterTest.java b/src/test/java/com/google/devtools/build/lib/analysis/SuccessfulArtifactFilterTest.java
index d6207d0..21276d5 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/SuccessfulArtifactFilterTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/SuccessfulArtifactFilterTest.java
@@ -120,8 +120,13 @@
allArtifactsToBuild.getAllArtifactsByOutputGroup();
SuccessfulArtifactFilter filter = new SuccessfulArtifactFilter(successfulArtifacts);
+ ImmutableMap<String, ArtifactsInOutputGroup> filteredOutputGroups =
+ filter.filterArtifactsInOutputGroup(outputGroups);
+ assertThat(filteredOutputGroups.get("g1").isIncomplete()).isTrue();
+ assertThat(filteredOutputGroups.get("g2").isIncomplete()).isTrue();
+ assertThat(filteredOutputGroups.get("g3").isIncomplete()).isTrue();
Map<String, ImmutableSet<Artifact>> groupArtifacts =
- extractArtifactsByOutputGroup(filter.filterArtifactsInOutputGroup(outputGroups));
+ extractArtifactsByOutputGroup(filteredOutputGroups);
assertThat(groupArtifacts.get("g1")).containsExactly(group1BuiltArtifact);
assertThat(groupArtifacts.get("g2")).containsExactly(group2BuiltArtifact);
assertThat(groupArtifacts.get("g3"))
@@ -152,6 +157,7 @@
SuccessfulArtifactFilter filter = new SuccessfulArtifactFilter(successfulArtifacts);
ImmutableMap<String, ArtifactsInOutputGroup> filteredOutputGroups =
filter.filterArtifactsInOutputGroup(outputGroups);
+ assertThat(filteredOutputGroups.get("g1").isIncomplete()).isTrue();
assertThat(filteredOutputGroups).containsKey("g1");
assertThat(filteredOutputGroups).doesNotContainKey("g2");
}
@@ -197,6 +203,7 @@
ArtifactsInOutputGroup unfilteredArtifactsInOutputGroup = outputGroups.get("out");
ArtifactsInOutputGroup filteredArtifactsInOutputGroup =
filter.filterArtifactsInOutputGroup(outputGroups).get("out");
+ assertThat(filteredArtifactsInOutputGroup.isIncomplete()).isFalse();
assertThat(filteredArtifactsInOutputGroup).isSameInstanceAs(unfilteredArtifactsInOutputGroup);
}
diff --git a/src/test/shell/integration/build_event_stream_test.sh b/src/test/shell/integration/build_event_stream_test.sh
index 05cf0e3..801e552 100755
--- a/src/test/shell/integration/build_event_stream_test.sh
+++ b/src/test/shell/integration/build_event_stream_test.sh
@@ -682,6 +682,7 @@
expect_log "\"name\":\"${name}_outputs\""
expect_log "\"name\":\"outputgroups/my_lib-${name}.out\""
done
+ expect_log "\"name\":\"foo_outputs\".*\"incomplete\":true"
# Verify that a URI is produced for foo's successful action's output but not
# its failed action's output.
expect_log "\"name\":\"outputgroups/my_lib-foo.out\",\"uri\":"
@@ -796,6 +797,7 @@
expect_log "\"name\":\"good-aspect-out\""
expect_log "\"name\":\"mixed-aspect-out\""
expect_not_log "\"name\":\"bad-aspect-out\""
+ expect_log "\"name\":\"mixed-aspect-out\".*\"incomplete\":true"
expect_log "\"name\":\"semifailingpkg/out1.txt.aspect.good\",\"uri\":"
expect_log "\"name\":\"semifailingpkg/out2.txt.aspect.good\",\"uri\":"
expect_log "\"name\":\"semifailingpkg/out1.txt.aspect.mixed\",\"uri\":"