Skip to content

Commit

Permalink
[2] Announce combined coverage report on the BES
Browse files Browse the repository at this point in the history
This allows BES consumers to access this file without guessing its path and existence, as well as when the actual coverage generation action runs locally.

Also removes an unused `CoverageReport` event that appears to have become obsolete.

RELNOTES: The combined coverage report produced via `--combined_report=lcov` is now announced on the BES via the new `CoverageReport` event.
  • Loading branch information
fmeum committed May 3, 2024
1 parent b8af8f9 commit 62f5e78
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 11 deletions.
6 changes: 6 additions & 0 deletions site/en/remote/bep-glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,12 @@ workspace as if Bazel had been run locally.
}
```

## CoverageReport {:#coveragereport}

If [`--combined_report`] is used with the `coverage` command, a `CoverageReport`
event is sent at the end of the build indicating the files of the combined
coverage report.

## Fetch {:#fetch}

Indicates that a Fetch operation occurred as a part of the command execution.
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/google/devtools/build/lib/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ java_library(
"//src/main/java/com/google/devtools/build/lib/analysis:test/coverage_action_finished_event",
"//src/main/java/com/google/devtools/build/lib/analysis:test/coverage_artifacts_known_event",
"//src/main/java/com/google/devtools/build/lib/analysis:test/coverage_report_action_factory",
"//src/main/java/com/google/devtools/build/lib/analysis:test/coverage_report_event",
"//src/main/java/com/google/devtools/build/lib/analysis:top_level_artifact_context",
"//src/main/java/com/google/devtools/build/lib/analysis:transitive_info_collection",
"//src/main/java/com/google/devtools/build/lib/analysis:view_creation_failed_exception",
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/com/google/devtools/build/lib/analysis/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -2751,6 +2751,18 @@ java_library(
],
)

java_library(
name = "test/coverage_report_event",
srcs = ["test/CoverageReportEvent.java"],
deps = [
"//src/main/java/com/google/devtools/build/lib/actions:artifacts",
"//src/main/java/com/google/devtools/build/lib/buildeventstream",
"//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
"//third_party:flogger",
"//third_party:guava",
],
)

java_library(
name = "test/execution_info",
srcs = ["test/ExecutionInfo.java"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
import com.google.devtools.build.lib.skyframe.SkyframeAnalysisResult;
import com.google.devtools.build.lib.skyframe.SkyframeBuildView;
import com.google.devtools.build.lib.skyframe.SkyframeBuildView.BuildDriverKeyTestContext;
import com.google.devtools.build.lib.skyframe.SkyframeBuildView.CoverageReportActionsWrapperSupplier;
import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
import com.google.devtools.build.lib.skyframe.TargetPatternPhaseValue;
import com.google.devtools.build.lib.util.AbruptExitException;
Expand Down Expand Up @@ -156,7 +157,8 @@ public class BuildView {

private final ConfiguredRuleClassProvider ruleClassProvider;

@Nullable private ImmutableSet<Artifact> memoizedCoverageArtifacts;
@Nullable
private CoverageReportActionsWrapperSupplier.CoverageArtifacts memoizedCoverageArtifacts;

/** A factory class to create the coverage report action. May be null. */
@Nullable private final CoverageReportActionFactory coverageReportActionFactory;
Expand Down Expand Up @@ -552,7 +554,8 @@ private AnalysisResult createResult(
// Coverage
artifactsToBuild.addAll(
memoizedGetCoverageArtifactsHelper(
configuredTargets, allTargetsToTest, eventHandler, eventBus, loadingResult));
configuredTargets, allTargetsToTest, eventHandler, eventBus, loadingResult)
.allCoverageArtifacts());

// TODO(cparsons): If extra actions are ever removed, this filtering step can probably be
// removed as well: the only concern would be action conflicts involving coverage artifacts,
Expand Down Expand Up @@ -846,7 +849,7 @@ private static void pollInterruptedStatus() throws InterruptedException {
}
}

private ImmutableSet<Artifact> memoizedGetCoverageArtifactsHelper(
private CoverageReportActionsWrapperSupplier.CoverageArtifacts memoizedGetCoverageArtifactsHelper(
Set<ConfiguredTarget> configuredTargets,
Set<ConfiguredTarget> allTargetsToTest,
EventHandler eventHandler,
Expand All @@ -856,11 +859,13 @@ private ImmutableSet<Artifact> memoizedGetCoverageArtifactsHelper(
if (memoizedCoverageArtifacts != null) {
return memoizedCoverageArtifacts;
}
ImmutableSet.Builder<Artifact> resultBuilder = ImmutableSet.builder();
ImmutableSet.Builder<Artifact> allCoverageArtifacts = ImmutableSet.builder();
ImmutableSet.Builder<Artifact> coverageReportArtifacts = ImmutableSet.builder();
// Coverage
NestedSet<Artifact> baselineCoverageArtifacts = getBaselineCoverageArtifacts(configuredTargets);
resultBuilder.addAll(baselineCoverageArtifacts.toList());
allCoverageArtifacts.addAll(baselineCoverageArtifacts.toList());

Artifact coverageReport = null;
if (coverageReportActionFactory != null) {
CoverageReportActionsWrapper actionsWrapper =
coverageReportActionFactory.createCoverageReportActionsWrapper(
Expand All @@ -875,10 +880,13 @@ private ImmutableSet<Artifact> memoizedGetCoverageArtifactsHelper(
loadingResult.getWorkspaceName());
if (actionsWrapper != null) {
skyframeExecutor.injectCoverageReportData(actionsWrapper.getActions());
actionsWrapper.getCoverageOutputs().forEach(resultBuilder::add);
actionsWrapper.getCoverageOutputs().forEach(allCoverageArtifacts::add);
actionsWrapper.getCoverageOutputs().forEach(coverageReportArtifacts::add);
}
}
memoizedCoverageArtifacts = resultBuilder.build();
memoizedCoverageArtifacts =
new CoverageReportActionsWrapperSupplier.CoverageArtifacts(
allCoverageArtifacts.build(), coverageReportArtifacts.build());
return memoizedCoverageArtifacts;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright 2023 The Bazel Authors. All rights reserved.
//
// 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.devtools.build.lib.analysis.test;

import static com.google.common.collect.ImmutableList.toImmutableList;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.GoogleLogger;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.buildeventstream.BuildEvent;
import com.google.devtools.build.lib.buildeventstream.BuildEventContext;
import com.google.devtools.build.lib.buildeventstream.BuildEventIdUtil;
import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId;
import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.CoverageReport;
import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.File;
import com.google.devtools.build.lib.buildeventstream.GenericBuildEvent;
import java.util.Collection;

/** Inform BEP consumers that the coverage report is available. */
public class CoverageReportEvent implements BuildEvent {
private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();

private final ImmutableSet<Artifact> coverageReport;

public CoverageReportEvent(ImmutableSet<Artifact> coverageReport) {
this.coverageReport = coverageReport;
}

@Override
public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext context)
throws InterruptedException {
ImmutableList.Builder<File> reportFiles = ImmutableList.builder();
for (Artifact artifact : coverageReport) {
String uri = context.pathConverter().apply(artifact.getPath());
if (uri != null) {
reportFiles.add(File.newBuilder().setUri(uri).build());
} else {
logger.atInfo().log("Dropped unfinished upload: %s", artifact.getPath());
}
}
return GenericBuildEvent.protoChaining(this)
.setCoverageReport(CoverageReport.newBuilder().addAllCoverageReport(reportFiles.build()))
.build();
}

@Override
public BuildEventId getEventId() {
return BuildEventIdUtil.coverageReport();
}

@Override
public Collection<BuildEventId> getChildrenEvents() {
return ImmutableList.of();
}

@Override
public Collection<LocalFile> referencedLocalFiles() {
return coverageReport.stream()
.map(
artifact ->
new LocalFile(
artifact.getPath(),
LocalFile.LocalFileType.COVERAGE_OUTPUT,
artifact,
/* artifactMetadata= */ null))
.collect(toImmutableList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@ public static BuildEventId coverageActionsFinished() {
.build();
}

public static BuildEventId coverageReport() {
return BuildEventId.newBuilder()
.setCoverageReport(BuildEventId.CoverageReportId.getDefaultInstance())
.build();
}

public static BuildEventId aspectConfigured(Label label, String aspect) {
BuildEventId.TargetConfiguredId configuredId =
BuildEventId.TargetConfiguredId.newBuilder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,9 @@ message BuildEventId {
// Identifier of an event providing the ExecRequest of a run command.
message ExecRequestId {}

// Identifier of an event providing the coverage report.
message CoverageReportId {}

oneof id {
UnknownBuildEventId unknown = 1;
ProgressId progress = 2;
Expand Down Expand Up @@ -284,6 +287,7 @@ message BuildEventId {
ConvenienceSymlinksIdentifiedId convenience_symlinks_identified = 25;
CoverageActionsFinishedId coverage_actions_finished = 27;
ExecRequestId exec_request = 28;
CoverageReportId coverage_report = 30;
}
}

Expand Down Expand Up @@ -1354,6 +1358,11 @@ message EnvironmentVariable {
bytes value = 2;
}

// Event that contains the combined coverage report files.
message CoverageReport {
repeated File coverage_report = 1;
}

// Message describing a build event. Events will have an identifier that
// is unique within a given build invocation; they also announce follow-up
// events as children. More details, which are specific to the kind of event
Expand Down Expand Up @@ -1390,5 +1399,6 @@ message BuildEvent {
BuildMetadata build_metadata = 26;
ConvenienceSymlinksIdentified convenience_symlinks_identified = 27;
ExecRequestConstructed exec_request = 29;
CoverageReport coverage_report = 31;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
import com.google.devtools.build.lib.analysis.test.CoverageActionFinishedEvent;
import com.google.devtools.build.lib.analysis.test.CoverageReportEvent;
import com.google.devtools.build.lib.analysis.test.TestProvider;
import com.google.devtools.build.lib.bugreport.BugReporter;
import com.google.devtools.build.lib.buildtool.buildevent.ExecutionProgressReceiverAvailableEvent;
Expand Down Expand Up @@ -242,6 +243,8 @@ public void buildArtifacts(
bugReporter);
if (detailedExitCode != null) {
detailedExitCodes.add(detailedExitCode);
} else {
skyframeExecutor.getEventBus().post(new CoverageReportEvent(coverageReportArtifacts));
}
}
} finally {
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/google/devtools/build/lib/skyframe/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ java_library(
"//src/main/java/com/google/devtools/build/lib/analysis:test/analysis_failure_propagation_exception",
"//src/main/java/com/google/devtools/build/lib/analysis:test/coverage_action_finished_event",
"//src/main/java/com/google/devtools/build/lib/analysis:test/coverage_artifacts_known_event",
"//src/main/java/com/google/devtools/build/lib/analysis:test/coverage_report_event",
"//src/main/java/com/google/devtools/build/lib/analysis:toolchain_collection",
"//src/main/java/com/google/devtools/build/lib/analysis:toolchain_context",
"//src/main/java/com/google/devtools/build/lib/analysis:top_level_artifact_context",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
import com.google.devtools.build.lib.analysis.test.AnalysisFailurePropagationException;
import com.google.devtools.build.lib.analysis.test.CoverageActionFinishedEvent;
import com.google.devtools.build.lib.analysis.test.CoverageArtifactsKnownEvent;
import com.google.devtools.build.lib.analysis.test.CoverageReportEvent;
import com.google.devtools.build.lib.bugreport.BugReport;
import com.google.devtools.build.lib.bugreport.BugReporter;
import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildMetrics.BuildGraphMetrics;
Expand Down Expand Up @@ -760,13 +761,14 @@ public SkyframeAnalysisResult analyzeAndExecuteTargets(
// combined report that matters.
// When --nokeep_going and there's an earlier error, we should skip this and fail fast.
if ((!mainEvaluationResult.hasError() && !hasExclusiveTestsError) || keepGoing) {
ImmutableSet<Artifact> coverageArtifacts =
var coverageArtifacts =
coverageReportActionsWrapperSupplier.getCoverageArtifacts(
buildResultListener.getAnalyzedTargets(), buildResultListener.getAnalyzedTests());
eventBus.post(CoverageArtifactsKnownEvent.create(coverageArtifacts));
eventBus.post(
CoverageArtifactsKnownEvent.create(coverageArtifacts.allCoverageArtifacts()));
additionalArtifactsResult =
skyframeExecutor.evaluateSkyKeys(
eventHandler, Artifact.keys(coverageArtifacts), keepGoing);
eventHandler, Artifact.keys(coverageArtifacts.allCoverageArtifacts()), keepGoing);
eventBus.post(new CoverageActionFinishedEvent());
if (additionalArtifactsResult.hasError()) {
detailedExitCodes.add(
Expand All @@ -780,6 +782,8 @@ public SkyframeAnalysisResult analyzeAndExecuteTargets(
bugReporter,
/* includeExecutionPhase= */ true)
.executionDetailedExitCode());
} else {
eventBus.post(new CoverageReportEvent(coverageArtifacts.coverageReportArtifacts()));
}
}
} finally {
Expand Down Expand Up @@ -1481,7 +1485,11 @@ public void reset() {
/** Provides the list of coverage artifacts to be built. */
@FunctionalInterface
public interface CoverageReportActionsWrapperSupplier {
ImmutableSet<Artifact> getCoverageArtifacts(
record CoverageArtifacts(
ImmutableSet<Artifact> allCoverageArtifacts,
ImmutableSet<Artifact> coverageReportArtifacts) {}

CoverageArtifacts getCoverageArtifacts(
Set<ConfiguredTarget> configuredTargets, Set<ConfiguredTarget> allTargetsToTest)
throws InterruptedException;
}
Expand Down

0 comments on commit 62f5e78

Please sign in to comment.