Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
78dad51
Implement ITR coverage backfill response parsing
tonyredondo May 12, 2026
2fdb0fd
Apply ITR coverage backfill to internal coverage
tonyredondo May 12, 2026
1af3261
Arbitrate session code coverage sources
tonyredondo May 12, 2026
689113e
Backfill external line coverage reports
tonyredondo May 12, 2026
f6021d3
Enable internal coverage storage for ITR backfill
tonyredondo May 12, 2026
ffd835a
Bypass skippable cache for coverage backfill
tonyredondo May 12, 2026
49587da
Harden ITR coverage backfill safety
tonyredondo May 12, 2026
1fd9cdd
Persist coverage backfill state across processes
tonyredondo May 12, 2026
fb55108
Harden coverage backfill capability checks
tonyredondo May 12, 2026
56a9a6f
Surface coverage IPC delivery failures
tonyredondo May 12, 2026
4cb9ac6
Record coverage backfill error telemetry
tonyredondo May 12, 2026
d0e7ee4
Harden external XML backfill capability
tonyredondo May 12, 2026
3ab7708
Surface coverage IPC send exceptions
tonyredondo May 12, 2026
1246516
Validate skippable coverage backfill response
tonyredondo May 13, 2026
c04f29e
Harden ITR coverage backfill capability
tonyredondo May 13, 2026
699d4ae
Aggregate coverage IPC results by counts
tonyredondo May 13, 2026
5aa270e
Allow scoped skippable coverage candidates
tonyredondo May 13, 2026
15bc0a9
Allow VSTest assembly coverage backfill
tonyredondo May 13, 2026
43e12d6
Scope ITR coverage backfill by test bundle
tonyredondo May 13, 2026
140fc51
Fix ITR coverage backfill scoping regressions
tonyredondo May 13, 2026
448a3a1
Fix ITR coverage backfill reconciliation
tonyredondo May 13, 2026
db493ab
Fix remote coverage backfill activation
tonyredondo May 13, 2026
80b24fc
Exclude ITR coverage backfill env vars from config telemetry
tonyredondo May 13, 2026
93cb7ec
Harden coverage backfill CI paths
tonyredondo May 13, 2026
8400bb2
Stabilize coverage backfill smoke test
tonyredondo May 13, 2026
e6a6a55
Finalize coverage backfill CI cleanup
tonyredondo May 13, 2026
599678c
Keep coverage backfill keys internal
tonyredondo May 13, 2026
a2be81e
Add nullable context to CI Visibility internal keys
tonyredondo May 13, 2026
f8b8f5c
Invalidate coverage data from bitmap setters
tonyredondo May 13, 2026
f8503bd
Restore full skippable response logging
tonyredondo May 13, 2026
bbb11b1
Restore filtered skippable response logging
tonyredondo May 13, 2026
4070cac
Reduce scoped skippable snapshot allocations
tonyredondo May 13, 2026
2b22235
Use FileBitmap for Coverlet backfill checks
tonyredondo May 13, 2026
1972b50
Use bitmap OR operator for coverage backfill merge
tonyredondo May 14, 2026
19e6488
Avoid allocations in coverage backfill helpers
tonyredondo May 14, 2026
18726ae
Use StringUtil for skippable response parsing
tonyredondo May 14, 2026
985af5d
Remove skippable scope hash pragma
tonyredondo May 14, 2026
0269de2
Simplify skippable feature flow
tonyredondo May 14, 2026
7361d7e
Simplify Coverlet backfill enumeration
tonyredondo May 14, 2026
d136a74
Handle Coverlet collector XML backfill fallback
tonyredondo May 14, 2026
ad198a3
Fix Coverlet backfill nullable build
tonyredondo May 14, 2026
c30b95f
Update trimming descriptor for coverage backfill
tonyredondo May 14, 2026
1f33b65
Merge branch 'master' into feat/itr-code-coverage-backfill
tonyredondo May 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions tracer/src/Datadog.Trace.Tools.Runner/CiUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using Datadog.Trace.Ci;
using Datadog.Trace.Ci.CiEnvironment;
using Datadog.Trace.Ci.Configuration;
using Datadog.Trace.Ci.Coverage.Backfill;
using Datadog.Trace.Ci.Net;
using Datadog.Trace.Logging;
using Datadog.Trace.Util;
Expand Down Expand Up @@ -58,6 +59,8 @@ public static async Task<InitResults> InitializeCiCommandsAsync(

// We force Test optimization mode on child process
profilerEnvironmentVariables[Configuration.ConfigurationKeys.CIVisibility.Enabled] = "1";
profilerEnvironmentVariables[Configuration.ConfigurationKeys.CIVisibility.TestOptimizationRunId] = testOptimization.RunId;
profilerEnvironmentVariables[Configuration.ConfigurationKeys.CIVisibilityItrCoverageBackfillRunFolder] = CoverageBackfillDataStore.GetOrCreateRunFolder(testOptimization);

// We check the settings and merge with the command settings options
var agentless = testOptimizationSettings.Agentless;
Expand Down Expand Up @@ -113,6 +116,7 @@ public static async Task<InitResults> InitializeCiCommandsAsync(
}

// Initialize flags to enable code coverage and test skipping
var internalCodeCoverageReportingEnabled = testOptimizationSettings.CodeCoverageEnabled == true;
var codeCoverageEnabled = testOptimizationSettings.CodeCoverageEnabled == true || testOptimizationSettings.TestsSkippingEnabled == true;
var testSkippingEnabled = testOptimizationSettings.TestsSkippingEnabled == true;
var knownTestsEnabled = testOptimizationSettings.KnownTestsEnabled == true;
Expand Down Expand Up @@ -204,6 +208,7 @@ async Task UploadRepositoryChangesAsync()
itrSettings = await client.GetSettingsAsync(skipFrameworkInfo: true).ConfigureAwait(false);
}

internalCodeCoverageReportingEnabled = internalCodeCoverageReportingEnabled || itrSettings.CodeCoverage == true;
codeCoverageEnabled = codeCoverageEnabled || itrSettings.CodeCoverage == true || itrSettings.TestsSkipping == true;
testSkippingEnabled = itrSettings.TestsSkipping == true;
knownTestsEnabled = knownTestsEnabled || itrSettings.KnownTestsEnabled == true;
Expand Down Expand Up @@ -363,8 +368,8 @@ async Task UploadRepositoryChangesAsync()
Log.Warning("RunCiCommand: Code coverage is enabled but the command is not a 'dotnet test' nor 'dotnet vstest' nor 'vstest.console' command. Code coverage will not be collected.");
}

// Sets the code coverage path to store the json files for each module in case we are not skipping test (global coverage is reliable).
if (!testSkippingEnabled)
// Store Datadog global coverage when it is complete by construction, or when explicit reporting can be corrected by ITR backfill.
if (!testSkippingEnabled || internalCodeCoverageReportingEnabled)
{
var outputFolders = new[] { Environment.CurrentDirectory, Path.GetTempPath(), };
foreach (var folder in outputFolders)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,7 @@
<type fullname="System.OperatingSystem" />
<type fullname="System.OperationCanceledException" />
<type fullname="System.OutOfMemoryException" />
<type fullname="System.OverflowException" />
<type fullname="System.ParamArrayAttribute" />
<type fullname="System.PlatformID" />
<type fullname="System.PlatformNotSupportedException" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// <copyright file="CoverageBackfillApplicator.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>

#nullable enable

using System;
using Datadog.Trace.Ci.CiEnvironment;
using Datadog.Trace.Ci.Coverage.Models.Global;
using Datadog.Trace.Ci.Coverage.Util;

namespace Datadog.Trace.Ci.Coverage.Backfill;

/// <summary>
/// Applies backend skipped-test coverage to local coverage models while keeping local executable lines as the denominator.
/// </summary>
internal static class CoverageBackfillApplicator
{
/// <summary>
/// Applies backend skipped-test coverage to Datadog's internal global coverage model.
/// </summary>
/// <param name="globalCoverage">Local global coverage data collected from tests that actually ran.</param>
/// <param name="backfillData">Backend coverage data returned by the skippable-tests endpoint.</param>
/// <returns>Summary of the backfill operation.</returns>
public static CoverageBackfillResult ApplyToGlobalCoverage(GlobalCoverageInfo? globalCoverage, CoverageBackfillData? backfillData)
{
if (globalCoverage is null ||
backfillData is not { IsPresent: true, IsValid: true })
{
return new CoverageBackfillResult(applied: false, matchedFiles: 0, updatedFiles: 0);
}

var matchedFiles = 0;
var updatedFiles = 0;
foreach (var component in globalCoverage.Components)
{
foreach (var file in component.Files)
{
if (file.Path is null ||
file.ExecutableBitmap is null ||
!backfillData.ExecutedLinesByRelativePath.TryGetValue(NormalizeLocalPath(file.Path), out var backendExecutedBitmap))
{
continue;
}

matchedFiles++;
if (ApplyBackendBitmap(file, backendExecutedBitmap))
{
updatedFiles++;
}
}
}

return new CoverageBackfillResult(applied: true, matchedFiles, updatedFiles);
}

private static bool ApplyBackendBitmap(FileCoverageInfo file, byte[] backendExecutedBitmap)
{
if (file.ExecutableBitmap is null)
{
return false;
}

using var backendBitmap = new FileBitmap(backendExecutedBitmap);
using var executableBitmap = new FileBitmap(file.ExecutableBitmap);
using var maskedBackendBitmap = backendBitmap & executableBitmap;
if (!maskedBackendBitmap.HasActiveBits())
{
return false;
}

var before = file.ExecutedBitmap;
if (before is null)
{
file.AggregateExecutedBitmap(maskedBackendBitmap.GetInternalArrayOrToArrayAndDispose());
return true;
}

using var beforeBitmap = new FileBitmap(before);
using var mergedBitmap = maskedBackendBitmap | beforeBitmap;
var merged = mergedBitmap.GetInternalArrayOrToArrayAndDispose();
if (before.AsSpan().SequenceEqual(merged))
{
return false;
}

file.ExecutedBitmap = merged;
return true;
}

private static string NormalizeLocalPath(string path)
{
var relativePath = CIEnvironmentValues.Instance.MakeRelativePathFromSourceRoot(path, false);
return CoverageBackfillData.NormalizePath(relativePath);
}
}
Loading
Loading