Skip to content

Commit

Permalink
Add support for deterministic build for msbuild driver (coverlet-cove…
Browse files Browse the repository at this point in the history
…rage#796)

Add support for deterministic build for msbuild driver
  • Loading branch information
MarcoRossignoli authored Apr 8, 2020
1 parent e9dcf4c commit 39d83be
Show file tree
Hide file tree
Showing 32 changed files with 487 additions and 87 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,6 @@ __pycache__/

# OSX
.DS_Store

# DeterministicSourcePaths workaround generated file DeterministicBuild.targets
.AssemblyAttributes
23 changes: 23 additions & 0 deletions DeterministicBuild.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!-- This target must be imported into Directory.Build.targets -->
<!-- Workaround. Remove once we're on 3.1.300+
https://github.com/dotnet/sourcelink/issues/572 -->
<Project>
<PropertyGroup>
<TargetFrameworkMonikerAssemblyAttributesPath>$([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)'))</TargetFrameworkMonikerAssemblyAttributesPath>
</PropertyGroup>
<ItemGroup>
<EmbeddedFiles Include="$(GeneratedAssemblyInfoFile)"/>
</ItemGroup>
<ItemGroup>
<SourceRoot Include="$(NuGetPackageRoot)" />
</ItemGroup>

<Target Name="CoverletGetPathMap"
DependsOnTargets="InitializeSourceRootMappedPaths"
Returns="@(_LocalTopLevelSourceRoot)"
Condition="'$(DeterministicSourcePaths)' == 'true'">
<ItemGroup>
<_LocalTopLevelSourceRoot Include="@(SourceRoot)" Condition="'%(SourceRoot.NestedRoot)' == ''"/>
</ItemGroup>
</Target>
</Project>
5 changes: 5 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
</RestoreSources>
</PropertyGroup>

<PropertyGroup Condition="'$(TF_BUILD)' == 'true'">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
<Deterministic>true</Deterministic>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Nerdbank.GitVersioning" Version="3.0.28" PrivateAssets="all" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="all" />
Expand Down
3 changes: 3 additions & 0 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@
<PackageReference Update="xunit.runner.visualstudio" Version="2.4.1"/>
<PackageReference Update="Tmds.ExecFunction" Version="0.3.0" />
</ItemGroup>

<!-- Deterministic build workaround -->
<Import Project="$(RepoRoot)\DeterministicBuild.targets" />
</Project>
8 changes: 8 additions & 0 deletions coverlet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
eng\azure-pipelines-nightly.yml = eng\azure-pipelines-nightly.yml
eng\azure-pipelines.yml = eng\azure-pipelines.yml
eng\build.yml = eng\build.yml
DeterministicBuild.targets = DeterministicBuild.targets
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
global.json = global.json
Expand All @@ -47,6 +48,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.core.tests.samples
EndProject
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}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{9A8B19D4-4A24-4217-AEFE-159B68F029A1}"
ProjectSection(SolutionItems) = preProject
test\Directory.Build.props = test\Directory.Build.props
test\Directory.Build.targets = test\Directory.Build.targets
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -128,6 +135,7 @@ Global
{F6FE7678-C662-43D3-AC6A-64F6AC5A5935} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
{5FF404AD-7C0B-465A-A1E9-558CDC642B0C} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
{F8199E19-FA9A-4559-9101-CAD7028121B4} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
{9A8B19D4-4A24-4217-AEFE-159B68F029A1} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9CA57C02-97B0-4C38-A027-EA61E8741F10}
Expand Down
2 changes: 1 addition & 1 deletion eng/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ steps:

- task: UseDotNet@2
inputs:
version: 3.1.200
version: 3.1.201
displayName: Install .NET Core SDK

- script: dotnet restore
Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"sdk": {
"version": "3.1.*"
"version": "3.1.201"
}
}
10 changes: 6 additions & 4 deletions src/coverlet.collector/DataCollection/CoverageManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ internal class CoverageManager

public IReporter[] Reporters { get; }

public CoverageManager(CoverletSettings settings, TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, ICoverageWrapper coverageWrapper)
public CoverageManager(CoverletSettings settings, TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, ICoverageWrapper coverageWrapper,
IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator)
: this(settings,
settings.ReportFormats.Select(format =>
{
Expand All @@ -38,18 +39,19 @@ public CoverageManager(CoverletSettings settings, TestPlatformEqtTrace eqtTrace,
}
}).Where(r => r != null).ToArray(),
new CoverletLogger(eqtTrace, logger),
coverageWrapper)
coverageWrapper, instrumentationHelper, fileSystem, sourceRootTranslator)
{
}

public CoverageManager(CoverletSettings settings, IReporter[] reporters, ILogger logger, ICoverageWrapper coverageWrapper)
public CoverageManager(CoverletSettings settings, IReporter[] reporters, ILogger logger, ICoverageWrapper coverageWrapper,
IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator)
{
// Store input vars
Reporters = reporters;
_coverageWrapper = coverageWrapper;

// Coverage object
_coverage = _coverageWrapper.CreateCoverage(settings, logger);
_coverage = _coverageWrapper.CreateCoverage(settings, logger, instrumentationHelper, fileSystem, sourceRootTranslator);
}

/// <summary>
Expand Down
7 changes: 4 additions & 3 deletions src/coverlet.collector/DataCollection/CoverageWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal class CoverageWrapper : ICoverageWrapper
/// <param name="settings">Coverlet settings</param>
/// <param name="coverletLogger">Coverlet logger</param>
/// <returns>Coverage object</returns>
public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger)
public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator)
{
return new Coverage(
settings.TestModule,
Expand All @@ -30,8 +30,9 @@ public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger
settings.MergeWith,
settings.UseSourceLink,
coverletLogger,
DependencyInjection.Current.GetService<IInstrumentationHelper>(),
DependencyInjection.Current.GetService<IFileSystem>());
instrumentationHelper,
fileSystem,
sourceRootTranslator);
}

/// <summary>
Expand Down
28 changes: 18 additions & 10 deletions src/coverlet.collector/DataCollection/CoverletCoverageCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,28 @@ namespace Coverlet.Collector.DataCollection
public class CoverletCoverageCollector : DataCollector
{
private readonly TestPlatformEqtTrace _eqtTrace;
private readonly ICoverageWrapper _coverageWrapper;
private readonly ICountDownEventFactory _countDownEventFactory;
private readonly Func<TestPlatformEqtTrace, TestPlatformLogger, string, IServiceCollection> _serviceCollectionFactory;

private DataCollectionEvents _events;
private TestPlatformLogger _logger;
private XmlElement _configurationElement;
private DataCollectionSink _dataSink;
private DataCollectionContext _dataCollectionContext;
private CoverageManager _coverageManager;
private ICoverageWrapper _coverageWrapper;
private ICountDownEventFactory _countDownEventFactory;
private IServiceProvider _serviceProvider;

public CoverletCoverageCollector() : this(new TestPlatformEqtTrace(), new CoverageWrapper(), new CollectorCountdownEventFactory())
public CoverletCoverageCollector() : this(new TestPlatformEqtTrace(), new CoverageWrapper(), new CollectorCountdownEventFactory(), GetDefaultServiceCollection)
{
}

internal CoverletCoverageCollector(TestPlatformEqtTrace eqtTrace, ICoverageWrapper coverageWrapper, ICountDownEventFactory countDownEventFactory) : base()
internal CoverletCoverageCollector(TestPlatformEqtTrace eqtTrace, ICoverageWrapper coverageWrapper, ICountDownEventFactory countDownEventFactory, Func<TestPlatformEqtTrace, TestPlatformLogger, string, IServiceCollection> serviceCollectionFactory) : base()
{
_eqtTrace = eqtTrace;
_coverageWrapper = coverageWrapper;
_countDownEventFactory = countDownEventFactory;
_serviceCollectionFactory = serviceCollectionFactory;
}

private void AttachDebugger()
Expand Down Expand Up @@ -79,7 +83,6 @@ public override void Initialize(
_dataSink = dataSink;
_dataCollectionContext = environmentContext.SessionDataCollectionContext;
_logger = new TestPlatformLogger(logger, _dataCollectionContext);
DependencyInjection.Set(GetServiceProvider(_eqtTrace, _logger));

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

// Build services container
_serviceProvider = _serviceCollectionFactory(_eqtTrace, _logger, coverletSettings.TestModule).BuildServiceProvider();

// Get coverage and attachment managers
_coverageManager = new CoverageManager(coverletSettings, _eqtTrace, _logger, _coverageWrapper);
_coverageManager = new CoverageManager(coverletSettings, _eqtTrace, _logger, _coverageWrapper,
_serviceProvider.GetRequiredService<IInstrumentationHelper>(), _serviceProvider.GetRequiredService<IFileSystem>(),
_serviceProvider.GetRequiredService<ISourceRootTranslator>());

// Instrument modules
_coverageManager.InstrumentModules();
Expand Down Expand Up @@ -209,18 +217,18 @@ private static IEnumerable<string> GetPropertyValueWrapper(SessionStartEventArgs
return sessionStartEventArgs.GetPropertyValue<IEnumerable<string>>(CoverletConstants.TestSourcesPropertyName);
}

private static IServiceProvider GetServiceProvider(TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger)
private static IServiceCollection GetDefaultServiceCollection(TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, string testModule)
{
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<IRetryHelper, RetryHelper>();
serviceCollection.AddTransient<IProcessExitHandler, ProcessExitHandler>();
serviceCollection.AddTransient<IFileSystem, FileSystem>();
serviceCollection.AddTransient<ILogger, CoverletLogger>(_ => new CoverletLogger(eqtTrace, logger));

// We need to keep singleton/static semantics
serviceCollection.AddSingleton<IInstrumentationHelper, InstrumentationHelper>();

return serviceCollection.BuildServiceProvider();
// We cache resolutions
serviceCollection.AddSingleton<ISourceRootTranslator, SourceRootTranslator>(serviceProvider => new SourceRootTranslator(testModule, serviceProvider.GetRequiredService<ILogger>(), serviceProvider.GetRequiredService<IFileSystem>()));
return serviceCollection;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ internal interface ICoverageWrapper
/// </summary>
/// <param name="settings">Coverlet settings</param>
/// <param name="coverletLogger">Coverlet logger</param>
/// <param name="instrumentationHelper">Coverlet instrumentationHelper</param>
/// <param name="fileSystem">Coverlet fileSystem</param>
/// <param name="sourceRootTranslator">Coverlet sourceRootTranslator</param>
/// <returns>Coverage object</returns>
Coverage CreateCoverage(CoverletSettings settings, ILogger logger);
Coverage CreateCoverage(CoverletSettings settings, ILogger logger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator);

/// <summary>
/// Gets the coverage result from provided coverage object
Expand Down
8 changes: 5 additions & 3 deletions src/coverlet.console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ static int Main(string[] args)
serviceCollection.AddTransient<IProcessExitHandler, ProcessExitHandler>();
serviceCollection.AddTransient<IFileSystem, FileSystem>();
serviceCollection.AddTransient<ILogger, ConsoleLogger>();

// We need to keep singleton/static semantics
serviceCollection.AddSingleton<IInstrumentationHelper, InstrumentationHelper>();
serviceCollection.AddSingleton<ISourceRootTranslator, SourceRootTranslator>(serviceProvider => new SourceRootTranslator(serviceProvider.GetRequiredService<ILogger>(), serviceProvider.GetRequiredService<IFileSystem>()));

DependencyInjection.Set(serviceCollection.BuildServiceProvider());

var logger = (ConsoleLogger) DependencyInjection.Current.GetService<ILogger>();
var logger = (ConsoleLogger)DependencyInjection.Current.GetService<ILogger>();
var fileSystem = DependencyInjection.Current.GetService<IFileSystem>();
var sourceTranslator = DependencyInjection.Current.GetService<ISourceRootTranslator>();

var app = new CommandLineApplication();
app.Name = "coverlet";
Expand Down Expand Up @@ -86,7 +87,8 @@ static int Main(string[] args)
useSourceLink.HasValue(),
logger,
DependencyInjection.Current.GetService<IInstrumentationHelper>(),
fileSystem);
fileSystem,
sourceTranslator);
coverage.PrepareModules();

Process process = new Process();
Expand Down
2 changes: 2 additions & 0 deletions src/coverlet.core/Abstracts/IFileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@ internal interface IFileSystem
Stream NewFileStream(string path, FileMode mode);

Stream NewFileStream(string path, FileMode mode, FileAccess access);

string[] ReadAllLines(string path);
}
}
7 changes: 7 additions & 0 deletions src/coverlet.core/Abstracts/ISourceRootTranslator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Coverlet.Core.Abstracts
{
internal interface ISourceRootTranslator
{
string ResolveFilePath(string originalFileName);
}
}
8 changes: 6 additions & 2 deletions src/coverlet.core/Coverage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ internal class Coverage
private ILogger _logger;
private IInstrumentationHelper _instrumentationHelper;
private IFileSystem _fileSystem;
private ISourceRootTranslator _sourceRootTranslator;
private List<InstrumenterResult> _results;

public string Identifier
Expand All @@ -45,7 +46,8 @@ public Coverage(string module,
bool useSourceLink,
ILogger logger,
IInstrumentationHelper instrumentationHelper,
IFileSystem fileSystem)
IFileSystem fileSystem,
ISourceRootTranslator sourceRootTranslator)
{
_module = module;
_includeFilters = includeFilters;
Expand All @@ -60,6 +62,7 @@ public Coverage(string module,
_logger = logger;
_instrumentationHelper = instrumentationHelper;
_fileSystem = fileSystem;
_sourceRootTranslator = sourceRootTranslator;

_identifier = Guid.NewGuid().ToString();
_results = new List<InstrumenterResult>();
Expand Down Expand Up @@ -97,7 +100,8 @@ public CoveragePrepareResult PrepareModules()
continue;
}

var instrumenter = new Instrumenter(module, _identifier, _excludeFilters, _includeFilters, _excludedSourceFiles, _excludeAttributes, _singleHit, _logger, _instrumentationHelper, _fileSystem);
var instrumenter = new Instrumenter(module, _identifier, _excludeFilters, _includeFilters, _excludedSourceFiles, _excludeAttributes, _singleHit, _logger, _instrumentationHelper, _fileSystem, _sourceRootTranslator);

if (instrumenter.CanInstrument())
{
_instrumentationHelper.BackupOriginalModule(module, _identifier);
Expand Down
5 changes: 5 additions & 0 deletions src/coverlet.core/Helpers/FileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,10 @@ public virtual Stream NewFileStream(string path, FileMode mode, FileAccess acces
{
return new FileStream(path, mode, access);
}

public string[] ReadAllLines(string path)
{
return File.ReadAllLines(path);
}
}
}
Loading

0 comments on commit 39d83be

Please sign in to comment.