Skip to content

Commit cfccd83

Browse files
authored
New parameter to control automatic assembly exclusion (#1392)
New parameter to control automatic assembly exclusion
1 parent 0c714f8 commit cfccd83

22 files changed

+195
-140
lines changed

Documentation/Changelog.md

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## Unreleased
88

9+
### Breaking changes
10+
- New parameter `ExcludeAssembliesWithoutSources` to control automatic assembly exclusion [1164](https://github.com/coverlet-coverage/coverlet/issues/1164). The parameter `InstrumentModulesWithoutLocalSources` has been removed. since it can be handled by setting `ExcludeAssembliesWithoutSources` to `None`.
11+
- The default heuristics for determining whether to instrument an assembly has been changed. In previous versions any missing source file was taken as a signal that it was a third-party project that shouldn't be instrumented, with exceptions for some common file name patterns for source generators. Now only assemblies where no source files at all can be found are excluded from instrumentation, and the code for detecting source generator files have been removed. To get back to the behaviour that at least one missing file is sufficient to exclude an assembly, set `ExcludeAssembliesWithoutSources` to `MissingAny`, or use assembly exclusion filters for more fine-grained control.
12+
913
## Release date 2022-10-29
1014
### Packages
1115
coverlet.msbuild 3.2.0

Documentation/GlobalTool.md

+23-23
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,31 @@ Cross platform .NET Core code coverage tool 3.0.0.0
1414
Usage: coverlet [arguments] [options]
1515

1616
Arguments:
17-
<ASSEMBLY|DIRECTORY> Path to the test assembly or application directory.
17+
<ASSEMBLY|DIRECTORY> Path to the test assembly or application directory.
1818

1919
Options:
20-
-h|--help Show help information
21-
-v|--version Show version information
22-
-t|--target Path to the test runner application.
23-
-a|--targetargs Arguments to be passed to the test runner.
24-
-o|--output Output of the generated coverage report
25-
-v|--verbosity Sets the verbosity level of the command. Allowed values are quiet, minimal, normal, detailed.
26-
-f|--format Format of the generated coverage report.
27-
--threshold Exits with error if the coverage % is below value.
28-
--threshold-type Coverage type to apply the threshold to.
29-
--threshold-stat Coverage statistic used to enforce the threshold value.
30-
--exclude Filter expressions to exclude specific modules and types.
31-
--include Filter expressions to include only specific modules and types.
32-
--exclude-by-file Glob patterns specifying source files to exclude.
33-
--include-directory Include directories containing additional assemblies to be instrumented.
34-
--exclude-by-attribute Attributes to exclude from code coverage.
35-
--include-test-assembly Specifies whether to report code coverage of the test assembly.
36-
--single-hit Specifies whether to limit code coverage hit reporting to a single hit for each location
37-
--skipautoprops Neither track nor record auto-implemented properties.
38-
--merge-with Path to existing coverage result to merge.
39-
--use-source-link Specifies whether to use SourceLink URIs in place of file system paths.
40-
--does-not-return-attribute Attributes that mark methods that do not return.
41-
--instrument-modules-without-local-sources Specifies whether modules should be instrumented even if the sources from the PDBs can't be found locally.
20+
-h|--help Show help information
21+
-v|--version Show version information
22+
-t|--target Path to the test runner application.
23+
-a|--targetargs Arguments to be passed to the test runner.
24+
-o|--output Output of the generated coverage report
25+
-v|--verbosity Sets the verbosity level of the command. Allowed values are quiet, minimal, normal, detailed.
26+
-f|--format Format of the generated coverage report.
27+
--threshold Exits with error if the coverage % is below value.
28+
--threshold-type Coverage type to apply the threshold to.
29+
--threshold-stat Coverage statistic used to enforce the threshold value.
30+
--exclude Filter expressions to exclude specific modules and types.
31+
--include Filter expressions to include only specific modules and types.
32+
--exclude-by-file Glob patterns specifying source files to exclude.
33+
--include-directory Include directories containing additional assemblies to be instrumented.
34+
--exclude-by-attribute Attributes to exclude from code coverage.
35+
--include-test-assembly Specifies whether to report code coverage of the test assembly.
36+
--single-hit Specifies whether to limit code coverage hit reporting to a single hit for each location
37+
--skipautoprops Neither track nor record auto-implemented properties.
38+
--merge-with Path to existing coverage result to merge.
39+
--use-source-link Specifies whether to use SourceLink URIs in place of file system paths.
40+
--does-not-return-attribute Attributes that mark methods that do not return.
41+
--exclude-assemblies-without-sources Specifies behaviour of heuristic to ignore assemblies with missing source documents.
4242
```
4343
4444
NB. For a [multiple value] options you have to specify values multiple times i.e.

Documentation/MSBuildIntegration.md

+16
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,19 @@ To generate deterministc report the parameter is:
228228
```
229229
/p:DeterministicReport=true
230230
```
231+
232+
## Exclude assemblies without sources from coverage
233+
234+
The heuristic coverlet uses to determine if an assembly is a third-party dependency is based on the matching of the assembly`s source documents and the corresponding source files.
235+
This parameter has three different values to control the automatic assembly exclusion.
236+
237+
| Parameter | Description |
238+
|-----------|-------------|
239+
| MissingAll | Includes the assembly if at least one document is matching. In case the `ExcludeAssembliesWithoutSources` parameter is not specified the default value is `MissingAll`. |
240+
| MissingAny | Includes the assembly only if all documents can be matched to corresponding source files. |
241+
| None | No assembly is excluded. |
242+
243+
Here is an example of how to specifiy the parameter:
244+
```
245+
/p:ExcludeAssembliesWithoutSources="MissingAny"
246+
```

Documentation/ReleasePlan.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ We release 3 components as NuGet packages:
2323

2424
| Package | Version |
2525
|:----------------------|:--------|
26-
|**coverlet.msbuild** | 3.1.2 |
27-
|**coverlet.console** | 3.1.2 |
28-
|**coverlet.collector** | 3.1.2 |
26+
|**coverlet.msbuild** | 3.2.0 |
27+
|**coverlet.console** | 3.2.0 |
28+
|**coverlet.collector** | 3.2.0 |
2929

3030

3131
| Release Date | coverlet.msbuild | coverlet.console | coverlet.collector| commit hash | notes |

Documentation/VSTestIntegration.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ These are a list of options that are supported by coverlet. These can be specifi
9797
| IncludeTestAssembly | Include coverage of the test assembly. |
9898
| SkipAutoProps | Neither track nor record auto-implemented properties. |
9999
| DoesNotReturnAttribute | Methods marked with these attributes are known not to return, statements following them will be excluded from coverage |
100-
| DeterministicReport | Generates deterministic report in context of deterministic build. Take a look at [documentation](DeterministicBuild.md) for further informations. |
101-
| InstrumentModulesWithoutLocalSources | Specifies whether modules should be instrumented even if the sources from the PDBs can't be found locally. |
100+
| DeterministicReport | Generates deterministic report in context of deterministic build. Take a look at [documentation](DeterministicBuild.md) for further informations.
101+
| ExcludeAssembliesWithoutSources | Specifies whether to exclude assemblies without source. Options are either MissingAll, MissingAny or None. Default is MissingAll.|
102102

103103
How to specify these options via runsettings?
104104

@@ -120,7 +120,7 @@ How to specify these options via runsettings?
120120
<IncludeTestAssembly>true</IncludeTestAssembly>
121121
<SkipAutoProps>true</SkipAutoProps>
122122
<DeterministicReport>false</DeterministicReport>
123-
<InstrumentModulesWithoutLocalSources>false</InstrumentModulesWithoutLocalSources>
123+
<ExcludeAssembliesWithoutSources>MissingAll,MissingAny,None</ExcludeAssembliesWithoutSources>
124124
</Configuration>
125125
</DataCollector>
126126
</DataCollectors>

src/coverlet.collector/DataCollection/CoverageWrapper.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger
3434
SkipAutoProps = settings.SkipAutoProps,
3535
DoesNotReturnAttributes = settings.DoesNotReturnAttributes,
3636
DeterministicReport = settings.DeterministicReport,
37-
InstrumentModulesWithoutLocalSources = settings.InstrumentModulesWithoutLocalSources
37+
ExcludeAssembliesWithoutSources = settings.ExcludeAssembliesWithoutSources
3838
};
3939

4040
return new Coverage(

src/coverlet.collector/DataCollection/CoverletSettings.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ internal class CoverletSettings
8282
public bool DeterministicReport { get; set; }
8383

8484
/// <summary>
85-
/// Instruments modules even if the sources from the PDBs can't be resolved.
85+
/// Switch for heuristic to automatically exclude assemblies without source.
8686
/// </summary>
87-
public bool InstrumentModulesWithoutLocalSources { get; set; }
87+
public string ExcludeAssembliesWithoutSources { get; set; }
8888

8989
public override string ToString()
9090
{
@@ -103,7 +103,7 @@ public override string ToString()
103103
builder.AppendFormat("SkipAutoProps: '{0}'", SkipAutoProps);
104104
builder.AppendFormat("DoesNotReturnAttributes: '{0}'", string.Join(",", DoesNotReturnAttributes ?? Enumerable.Empty<string>()));
105105
builder.AppendFormat("DeterministicReport: '{0}'", DeterministicReport);
106-
builder.AppendFormat("InstrumentModulesWithoutLocalSources: '{0}'", InstrumentModulesWithoutLocalSources);
106+
builder.AppendFormat("ExcludeAssembliesWithoutSources: '{0}'", ExcludeAssembliesWithoutSources);
107107

108108
return builder.ToString();
109109
}

src/coverlet.collector/DataCollection/CoverletSettingsParser.cs

+6-7
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public CoverletSettings Parse(XmlElement configurationElement, IEnumerable<strin
4848
coverletSettings.SkipAutoProps = ParseSkipAutoProps(configurationElement);
4949
coverletSettings.DoesNotReturnAttributes = ParseDoesNotReturnAttributes(configurationElement);
5050
coverletSettings.DeterministicReport = ParseDeterministicReport(configurationElement);
51-
coverletSettings.InstrumentModulesWithoutLocalSources = ParseInstrumentModulesWithoutLocalSources(configurationElement);
51+
coverletSettings.ExcludeAssembliesWithoutSources = ParseExcludeAssembliesWithoutSources(configurationElement);
5252
}
5353

5454
coverletSettings.ReportFormats = ParseReportFormats(configurationElement);
@@ -213,15 +213,14 @@ private static bool ParseDeterministicReport(XmlElement configurationElement)
213213
}
214214

215215
/// <summary>
216-
/// Parse InstrumentModulesWithoutLocalSources flag
216+
/// Parse ExcludeAssembliesWithoutSources flag
217217
/// </summary>
218218
/// <param name="configurationElement">Configuration element</param>
219-
/// <returns>InstrumentModulesWithoutLocalSources flag</returns>
220-
private static bool ParseInstrumentModulesWithoutLocalSources(XmlElement configurationElement)
219+
/// <returns>ExcludeAssembliesWithoutSources flag</returns>
220+
private static string ParseExcludeAssembliesWithoutSources(XmlElement configurationElement)
221221
{
222-
XmlElement instrumentModulesWithoutLocalSourcesElement = configurationElement[CoverletConstants.InstrumentModulesWithoutLocalSources];
223-
bool.TryParse(instrumentModulesWithoutLocalSourcesElement?.InnerText, out bool instrumentModulesWithoutLocalSources);
224-
return instrumentModulesWithoutLocalSources;
222+
XmlElement instrumentModulesWithoutLocalSourcesElement = configurationElement[CoverletConstants.ExcludeAssembliesWithoutSources];
223+
return instrumentModulesWithoutLocalSourcesElement?.InnerText;
225224
}
226225

227226
/// <summary>

src/coverlet.collector/Utilities/CoverletConstants.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,6 @@ internal static class CoverletConstants
2626
public const string SkipAutoProps = "SkipAutoProps";
2727
public const string DoesNotReturnAttributesElementName = "DoesNotReturnAttribute";
2828
public const string DeterministicReport = "DeterministicReport";
29-
public const string InstrumentModulesWithoutLocalSources = "InstrumentModulesWithoutLocalSources";
29+
public const string ExcludeAssembliesWithoutSources = "ExcludeAssembliesWithoutSources";
3030
}
3131
}

src/coverlet.console/Program.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ static int Main(string[] args)
7070
CommandOption mergeWith = app.Option("--merge-with", "Path to existing coverage result to merge.", CommandOptionType.SingleValue);
7171
CommandOption useSourceLink = app.Option("--use-source-link", "Specifies whether to use SourceLink URIs in place of file system paths.", CommandOptionType.NoValue);
7272
CommandOption doesNotReturnAttributes = app.Option("--does-not-return-attribute", "Attributes that mark methods that do not return.", CommandOptionType.MultipleValue);
73-
CommandOption instrumentModulesWithoutLocalSources = app.Option("--instrument-modules-without-local-sources", "Specifies whether modules should be instrumented even if the sources from the PDBs can't be found locally.", CommandOptionType.NoValue);
73+
CommandOption excludeAssembliesWithoutSources = app.Option("--exclude-assemblies-without-sources", "Specifies behaviour of heuristic to ignore assemblies with missing source documents.", CommandOptionType.SingleValue);
7474

7575
app.OnExecute(() =>
7676
{
@@ -99,7 +99,7 @@ static int Main(string[] args)
9999
UseSourceLink = useSourceLink.HasValue(),
100100
SkipAutoProps = skipAutoProp.HasValue(),
101101
DoesNotReturnAttributes = doesNotReturnAttributes.Values.ToArray(),
102-
InstrumentModulesWithoutLocalSources = instrumentModulesWithoutLocalSources.HasValue(),
102+
ExcludeAssembliesWithoutSources = excludeAssembliesWithoutSources.Value()
103103
};
104104

105105
ISourceRootTranslator sourceRootTranslator = serviceProvider.GetRequiredService<ISourceRootTranslator>();

src/coverlet.core/Abstractions/IInstrumentationHelper.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) Toni Solarin-Sodara
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

4+
using Coverlet.Core.Enums;
5+
46
namespace Coverlet.Core.Abstractions
57
{
68
internal interface IInstrumentationHelper
@@ -15,8 +17,8 @@ internal interface IInstrumentationHelper
1517
bool IsTypeExcluded(string module, string type, string[] excludeFilters);
1618
bool IsTypeIncluded(string module, string type, string[] includeFilters);
1719
void RestoreOriginalModule(string module, string identifier);
18-
bool EmbeddedPortablePdbHasLocalSource(string module, out string firstNotFoundDocument);
19-
bool PortablePdbHasLocalSource(string module, out string firstNotFoundDocument);
20+
bool EmbeddedPortablePdbHasLocalSource(string module, AssemblySearchType excludeAssembliesWithoutSources);
21+
bool PortablePdbHasLocalSource(string module, AssemblySearchType excludeAssembliesWithoutSources);
2022
bool IsLocalMethod(string method);
2123
void SetLogger(ILogger logger);
2224
}

src/coverlet.core/Coverage.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ internal class CoverageParameters
4444
[DataMember]
4545
public bool DeterministicReport { get; set; }
4646
[DataMember]
47-
public bool InstrumentModulesWithoutLocalSources { get; set; }
47+
public string ExcludeAssembliesWithoutSources { get; set; }
4848
}
4949

5050
internal class Coverage
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright (c) Toni Solarin-Sodara
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
namespace Coverlet.Core.Enums
5+
{
6+
internal enum AssemblySearchType
7+
{
8+
MissingAny,
9+
MissingAll,
10+
None
11+
}
12+
}

0 commit comments

Comments
 (0)