Skip to content

Commit 39d83be

Browse files
Add support for deterministic build for msbuild driver (#796)
Add support for deterministic build for msbuild driver
1 parent e9dcf4c commit 39d83be

32 files changed

+487
-87
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,3 +298,6 @@ __pycache__/
298298

299299
# OSX
300300
.DS_Store
301+
302+
# DeterministicSourcePaths workaround generated file DeterministicBuild.targets
303+
.AssemblyAttributes

DeterministicBuild.targets

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!-- This target must be imported into Directory.Build.targets -->
2+
<!-- Workaround. Remove once we're on 3.1.300+
3+
https://github.com/dotnet/sourcelink/issues/572 -->
4+
<Project>
5+
<PropertyGroup>
6+
<TargetFrameworkMonikerAssemblyAttributesPath>$([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)'))</TargetFrameworkMonikerAssemblyAttributesPath>
7+
</PropertyGroup>
8+
<ItemGroup>
9+
<EmbeddedFiles Include="$(GeneratedAssemblyInfoFile)"/>
10+
</ItemGroup>
11+
<ItemGroup>
12+
<SourceRoot Include="$(NuGetPackageRoot)" />
13+
</ItemGroup>
14+
15+
<Target Name="CoverletGetPathMap"
16+
DependsOnTargets="InitializeSourceRootMappedPaths"
17+
Returns="@(_LocalTopLevelSourceRoot)"
18+
Condition="'$(DeterministicSourcePaths)' == 'true'">
19+
<ItemGroup>
20+
<_LocalTopLevelSourceRoot Include="@(SourceRoot)" Condition="'%(SourceRoot.NestedRoot)' == ''"/>
21+
</ItemGroup>
22+
</Target>
23+
</Project>

Directory.Build.props

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
</RestoreSources>
1616
</PropertyGroup>
1717

18+
<PropertyGroup Condition="'$(TF_BUILD)' == 'true'">
19+
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
20+
<Deterministic>true</Deterministic>
21+
</PropertyGroup>
22+
1823
<ItemGroup>
1924
<PackageReference Include="Nerdbank.GitVersioning" Version="3.0.28" PrivateAssets="all" />
2025
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="all" />

Directory.Build.targets

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,7 @@
2626
<PackageReference Update="xunit.runner.visualstudio" Version="2.4.1"/>
2727
<PackageReference Update="Tmds.ExecFunction" Version="0.3.0" />
2828
</ItemGroup>
29+
30+
<!-- Deterministic build workaround -->
31+
<Import Project="$(RepoRoot)\DeterministicBuild.targets" />
2932
</Project>

coverlet.sln

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
3131
eng\azure-pipelines-nightly.yml = eng\azure-pipelines-nightly.yml
3232
eng\azure-pipelines.yml = eng\azure-pipelines.yml
3333
eng\build.yml = eng\build.yml
34+
DeterministicBuild.targets = DeterministicBuild.targets
3435
Directory.Build.props = Directory.Build.props
3536
Directory.Build.targets = Directory.Build.targets
3637
global.json = global.json
@@ -47,6 +48,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.core.tests.samples
4748
EndProject
4849
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.tests.xunit.extensions", "test\coverlet.tests.xunit.extensions\coverlet.tests.xunit.extensions.csproj", "{F8199E19-FA9A-4559-9101-CAD7028121B4}"
4950
EndProject
51+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{9A8B19D4-4A24-4217-AEFE-159B68F029A1}"
52+
ProjectSection(SolutionItems) = preProject
53+
test\Directory.Build.props = test\Directory.Build.props
54+
test\Directory.Build.targets = test\Directory.Build.targets
55+
EndProjectSection
56+
EndProject
5057
Global
5158
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5259
Debug|Any CPU = Debug|Any CPU
@@ -128,6 +135,7 @@ Global
128135
{F6FE7678-C662-43D3-AC6A-64F6AC5A5935} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
129136
{5FF404AD-7C0B-465A-A1E9-558CDC642B0C} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
130137
{F8199E19-FA9A-4559-9101-CAD7028121B4} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
138+
{9A8B19D4-4A24-4217-AEFE-159B68F029A1} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
131139
EndGlobalSection
132140
GlobalSection(ExtensibilityGlobals) = postSolution
133141
SolutionGuid = {9CA57C02-97B0-4C38-A027-EA61E8741F10}

eng/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ steps:
66

77
- task: UseDotNet@2
88
inputs:
9-
version: 3.1.200
9+
version: 3.1.201
1010
displayName: Install .NET Core SDK
1111

1212
- script: dotnet restore

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"sdk": {
3-
"version": "3.1.*"
3+
"version": "3.1.201"
44
}
55
}

src/coverlet.collector/DataCollection/CoverageManager.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ internal class CoverageManager
2222

2323
public IReporter[] Reporters { get; }
2424

25-
public CoverageManager(CoverletSettings settings, TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, ICoverageWrapper coverageWrapper)
25+
public CoverageManager(CoverletSettings settings, TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, ICoverageWrapper coverageWrapper,
26+
IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator)
2627
: this(settings,
2728
settings.ReportFormats.Select(format =>
2829
{
@@ -38,18 +39,19 @@ public CoverageManager(CoverletSettings settings, TestPlatformEqtTrace eqtTrace,
3839
}
3940
}).Where(r => r != null).ToArray(),
4041
new CoverletLogger(eqtTrace, logger),
41-
coverageWrapper)
42+
coverageWrapper, instrumentationHelper, fileSystem, sourceRootTranslator)
4243
{
4344
}
4445

45-
public CoverageManager(CoverletSettings settings, IReporter[] reporters, ILogger logger, ICoverageWrapper coverageWrapper)
46+
public CoverageManager(CoverletSettings settings, IReporter[] reporters, ILogger logger, ICoverageWrapper coverageWrapper,
47+
IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator)
4648
{
4749
// Store input vars
4850
Reporters = reporters;
4951
_coverageWrapper = coverageWrapper;
5052

5153
// Coverage object
52-
_coverage = _coverageWrapper.CreateCoverage(settings, logger);
54+
_coverage = _coverageWrapper.CreateCoverage(settings, logger, instrumentationHelper, fileSystem, sourceRootTranslator);
5355
}
5456

5557
/// <summary>

src/coverlet.collector/DataCollection/CoverageWrapper.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ internal class CoverageWrapper : ICoverageWrapper
1616
/// <param name="settings">Coverlet settings</param>
1717
/// <param name="coverletLogger">Coverlet logger</param>
1818
/// <returns>Coverage object</returns>
19-
public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger)
19+
public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator)
2020
{
2121
return new Coverage(
2222
settings.TestModule,
@@ -30,8 +30,9 @@ public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger
3030
settings.MergeWith,
3131
settings.UseSourceLink,
3232
coverletLogger,
33-
DependencyInjection.Current.GetService<IInstrumentationHelper>(),
34-
DependencyInjection.Current.GetService<IFileSystem>());
33+
instrumentationHelper,
34+
fileSystem,
35+
sourceRootTranslator);
3536
}
3637

3738
/// <summary>

src/coverlet.collector/DataCollection/CoverletCoverageCollector.cs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,28 @@ namespace Coverlet.Collector.DataCollection
2121
public class CoverletCoverageCollector : DataCollector
2222
{
2323
private readonly TestPlatformEqtTrace _eqtTrace;
24+
private readonly ICoverageWrapper _coverageWrapper;
25+
private readonly ICountDownEventFactory _countDownEventFactory;
26+
private readonly Func<TestPlatformEqtTrace, TestPlatformLogger, string, IServiceCollection> _serviceCollectionFactory;
27+
2428
private DataCollectionEvents _events;
2529
private TestPlatformLogger _logger;
2630
private XmlElement _configurationElement;
2731
private DataCollectionSink _dataSink;
2832
private DataCollectionContext _dataCollectionContext;
2933
private CoverageManager _coverageManager;
30-
private ICoverageWrapper _coverageWrapper;
31-
private ICountDownEventFactory _countDownEventFactory;
34+
private IServiceProvider _serviceProvider;
3235

33-
public CoverletCoverageCollector() : this(new TestPlatformEqtTrace(), new CoverageWrapper(), new CollectorCountdownEventFactory())
36+
public CoverletCoverageCollector() : this(new TestPlatformEqtTrace(), new CoverageWrapper(), new CollectorCountdownEventFactory(), GetDefaultServiceCollection)
3437
{
3538
}
3639

37-
internal CoverletCoverageCollector(TestPlatformEqtTrace eqtTrace, ICoverageWrapper coverageWrapper, ICountDownEventFactory countDownEventFactory) : base()
40+
internal CoverletCoverageCollector(TestPlatformEqtTrace eqtTrace, ICoverageWrapper coverageWrapper, ICountDownEventFactory countDownEventFactory, Func<TestPlatformEqtTrace, TestPlatformLogger, string, IServiceCollection> serviceCollectionFactory) : base()
3841
{
3942
_eqtTrace = eqtTrace;
4043
_coverageWrapper = coverageWrapper;
4144
_countDownEventFactory = countDownEventFactory;
45+
_serviceCollectionFactory = serviceCollectionFactory;
4246
}
4347

4448
private void AttachDebugger()
@@ -79,7 +83,6 @@ public override void Initialize(
7983
_dataSink = dataSink;
8084
_dataCollectionContext = environmentContext.SessionDataCollectionContext;
8185
_logger = new TestPlatformLogger(logger, _dataCollectionContext);
82-
DependencyInjection.Set(GetServiceProvider(_eqtTrace, _logger));
8386

8487
// Register events
8588
_events.SessionStart += OnSessionStart;
@@ -125,8 +128,13 @@ private void OnSessionStart(object sender, SessionStartEventArgs sessionStartEve
125128
var coverletSettingsParser = new CoverletSettingsParser(_eqtTrace);
126129
CoverletSettings coverletSettings = coverletSettingsParser.Parse(_configurationElement, testModules);
127130

131+
// Build services container
132+
_serviceProvider = _serviceCollectionFactory(_eqtTrace, _logger, coverletSettings.TestModule).BuildServiceProvider();
133+
128134
// Get coverage and attachment managers
129-
_coverageManager = new CoverageManager(coverletSettings, _eqtTrace, _logger, _coverageWrapper);
135+
_coverageManager = new CoverageManager(coverletSettings, _eqtTrace, _logger, _coverageWrapper,
136+
_serviceProvider.GetRequiredService<IInstrumentationHelper>(), _serviceProvider.GetRequiredService<IFileSystem>(),
137+
_serviceProvider.GetRequiredService<ISourceRootTranslator>());
130138

131139
// Instrument modules
132140
_coverageManager.InstrumentModules();
@@ -209,18 +217,18 @@ private static IEnumerable<string> GetPropertyValueWrapper(SessionStartEventArgs
209217
return sessionStartEventArgs.GetPropertyValue<IEnumerable<string>>(CoverletConstants.TestSourcesPropertyName);
210218
}
211219

212-
private static IServiceProvider GetServiceProvider(TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger)
220+
private static IServiceCollection GetDefaultServiceCollection(TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, string testModule)
213221
{
214222
IServiceCollection serviceCollection = new ServiceCollection();
215223
serviceCollection.AddTransient<IRetryHelper, RetryHelper>();
216224
serviceCollection.AddTransient<IProcessExitHandler, ProcessExitHandler>();
217225
serviceCollection.AddTransient<IFileSystem, FileSystem>();
218226
serviceCollection.AddTransient<ILogger, CoverletLogger>(_ => new CoverletLogger(eqtTrace, logger));
219-
220227
// We need to keep singleton/static semantics
221228
serviceCollection.AddSingleton<IInstrumentationHelper, InstrumentationHelper>();
222-
223-
return serviceCollection.BuildServiceProvider();
229+
// We cache resolutions
230+
serviceCollection.AddSingleton<ISourceRootTranslator, SourceRootTranslator>(serviceProvider => new SourceRootTranslator(testModule, serviceProvider.GetRequiredService<ILogger>(), serviceProvider.GetRequiredService<IFileSystem>()));
231+
return serviceCollection;
224232
}
225233
}
226234
}

src/coverlet.collector/Utilities/Interfaces/ICoverageWrapper.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@ internal interface ICoverageWrapper
1515
/// </summary>
1616
/// <param name="settings">Coverlet settings</param>
1717
/// <param name="coverletLogger">Coverlet logger</param>
18+
/// <param name="instrumentationHelper">Coverlet instrumentationHelper</param>
19+
/// <param name="fileSystem">Coverlet fileSystem</param>
20+
/// <param name="sourceRootTranslator">Coverlet sourceRootTranslator</param>
1821
/// <returns>Coverage object</returns>
19-
Coverage CreateCoverage(CoverletSettings settings, ILogger logger);
22+
Coverage CreateCoverage(CoverletSettings settings, ILogger logger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator);
2023

2124
/// <summary>
2225
/// Gets the coverage result from provided coverage object

src/coverlet.console/Program.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,15 @@ static int Main(string[] args)
2626
serviceCollection.AddTransient<IProcessExitHandler, ProcessExitHandler>();
2727
serviceCollection.AddTransient<IFileSystem, FileSystem>();
2828
serviceCollection.AddTransient<ILogger, ConsoleLogger>();
29-
3029
// We need to keep singleton/static semantics
3130
serviceCollection.AddSingleton<IInstrumentationHelper, InstrumentationHelper>();
31+
serviceCollection.AddSingleton<ISourceRootTranslator, SourceRootTranslator>(serviceProvider => new SourceRootTranslator(serviceProvider.GetRequiredService<ILogger>(), serviceProvider.GetRequiredService<IFileSystem>()));
3232

3333
DependencyInjection.Set(serviceCollection.BuildServiceProvider());
3434

35-
var logger = (ConsoleLogger) DependencyInjection.Current.GetService<ILogger>();
35+
var logger = (ConsoleLogger)DependencyInjection.Current.GetService<ILogger>();
3636
var fileSystem = DependencyInjection.Current.GetService<IFileSystem>();
37+
var sourceTranslator = DependencyInjection.Current.GetService<ISourceRootTranslator>();
3738

3839
var app = new CommandLineApplication();
3940
app.Name = "coverlet";
@@ -86,7 +87,8 @@ static int Main(string[] args)
8687
useSourceLink.HasValue(),
8788
logger,
8889
DependencyInjection.Current.GetService<IInstrumentationHelper>(),
89-
fileSystem);
90+
fileSystem,
91+
sourceTranslator);
9092
coverage.PrepareModules();
9193

9294
Process process = new Process();

src/coverlet.core/Abstracts/IFileSystem.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,7 @@ internal interface IFileSystem
1919
Stream NewFileStream(string path, FileMode mode);
2020

2121
Stream NewFileStream(string path, FileMode mode, FileAccess access);
22+
23+
string[] ReadAllLines(string path);
2224
}
2325
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Coverlet.Core.Abstracts
2+
{
3+
internal interface ISourceRootTranslator
4+
{
5+
string ResolveFilePath(string originalFileName);
6+
}
7+
}

src/coverlet.core/Coverage.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ internal class Coverage
2626
private ILogger _logger;
2727
private IInstrumentationHelper _instrumentationHelper;
2828
private IFileSystem _fileSystem;
29+
private ISourceRootTranslator _sourceRootTranslator;
2930
private List<InstrumenterResult> _results;
3031

3132
public string Identifier
@@ -45,7 +46,8 @@ public Coverage(string module,
4546
bool useSourceLink,
4647
ILogger logger,
4748
IInstrumentationHelper instrumentationHelper,
48-
IFileSystem fileSystem)
49+
IFileSystem fileSystem,
50+
ISourceRootTranslator sourceRootTranslator)
4951
{
5052
_module = module;
5153
_includeFilters = includeFilters;
@@ -60,6 +62,7 @@ public Coverage(string module,
6062
_logger = logger;
6163
_instrumentationHelper = instrumentationHelper;
6264
_fileSystem = fileSystem;
65+
_sourceRootTranslator = sourceRootTranslator;
6366

6467
_identifier = Guid.NewGuid().ToString();
6568
_results = new List<InstrumenterResult>();
@@ -97,7 +100,8 @@ public CoveragePrepareResult PrepareModules()
97100
continue;
98101
}
99102

100-
var instrumenter = new Instrumenter(module, _identifier, _excludeFilters, _includeFilters, _excludedSourceFiles, _excludeAttributes, _singleHit, _logger, _instrumentationHelper, _fileSystem);
103+
var instrumenter = new Instrumenter(module, _identifier, _excludeFilters, _includeFilters, _excludedSourceFiles, _excludeAttributes, _singleHit, _logger, _instrumentationHelper, _fileSystem, _sourceRootTranslator);
104+
101105
if (instrumenter.CanInstrument())
102106
{
103107
_instrumentationHelper.BackupOriginalModule(module, _identifier);

src/coverlet.core/Helpers/FileSystem.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,10 @@ public virtual Stream NewFileStream(string path, FileMode mode, FileAccess acces
4848
{
4949
return new FileStream(path, mode, access);
5050
}
51+
52+
public string[] ReadAllLines(string path)
53+
{
54+
return File.ReadAllLines(path);
55+
}
5156
}
5257
}

0 commit comments

Comments
 (0)