Deterministic build is supported only by msbuild
(/p:CollectCoverage=true
) and collectors
(--collect:"XPlat Code Coverage"
) drivers.
Deterministic builds are important as they enable verification that the resulting binary was built from the specified source and provides traceability.
For more information on how to enable deterministic build I recommend you to take a look at @clairernovotny's guide https://github.com/clairernovotny/DeterministicBuilds
From coverage perspective deterministic build put some challenge because usually coverage tools need access to source file metadata (ie. local path) during instrumentation and report generation.
These files are reported inside pdb
files, where are stored debugging information needed by debuggers and also by tools that needs to work with "build" metadata information, for example generated dll
modules and source files
used.
In local (non-CI) builds metadata emitted to pdbs are not "deterministic", that means that for instance source files path are reported with full path.
If for instance we build same project on different machine we'll have different paths emitted inside pdbs, so builds are "non deterministic" because same project build won't generates same artifacts.
As explained above, to improve the level of security of generated artifacts (suppose for instance DLLs inside the nuget package), we need to apply some signature (signing with certificate) and validate before usage to avoid possible security issues like tampering.
Finally thanks to deterministic CI builds (with the ContinuousIntegrationBuild
property set to true
) plus signature we can validate artifacts and be sure that binary was build from a specific sources (because there is no hard-coded variables metadata like paths from different build machines).
At the moment deterministic build works thanks to Roslyn compiler that emits deterministic metadata if DeterministicSourcePaths
is enabled. Take a look here for more information https://github.com/dotnet/sourcelink/tree/master/docs#deterministicsourcepaths.
To allow coverlet to correctly do his work we need to provide information to translate deterministic path to real local path for every project referenced by tests project.
The current workaround is to add on top of your repo a Directory.Build.targets
with inside a simple snippet with custom target
that supports coverlet resolution algorithm.
<!-- 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>
If you already have a Directory.Build.targets
file on your repo root you can simply copy DeterministicBuild.targets
you can find on coverlet repo root next to yours and import it in your targets file.
This target will be used by coverlet to generate on build phase a file on output folder with mapping translation informations, the file is named CoverletSourceRootsMapping
.
You can follow our step-by-step sample
Feel free to file an issue in case of troubles!
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。