diff --git a/README.md b/README.md
index 27dc096..390c985 100644
--- a/README.md
+++ b/README.md
@@ -78,6 +78,7 @@ The above command will automatically fail the build if the average code coverage
### Excluding From Coverage
+#### Attributes
You can ignore a method or an entire class from code coverage by creating and applying any of the following attributes:
* ExcludeFromCoverage
@@ -85,6 +86,16 @@ You can ignore a method or an entire class from code coverage by creating and ap
Coverlet just uses the type name, so the attributes can be created under any namespace of your choosing.
+#### File Path
+You can also ignore code coverage by specifing files using the `Exclude` property
+ - Use single or multiple paths (separate by comma)
+ - Use absolute or relative paths (relative to the project directory)
+ - Use file path or directory path with globbing (e.g `dir1/*.cs`)
+
+```bash
+dotnet test /p:CollectCoverage=true /p:Exclude=\"../dir1/class1.cs,../dir2/*.cs,../dir3/**/*.cs,\"
+```
+
## Roadmap
* Filter modules to be instrumented
diff --git a/build.proj b/build.proj
index 41b99ca..25cdcad 100644
--- a/build.proj
+++ b/build.proj
@@ -28,7 +28,7 @@
-
+
diff --git a/src/coverlet.core/Helpers/InstrumentationHelper.cs b/src/coverlet.core/Helpers/InstrumentationHelper.cs
index d3d5117..c36baca 100644
--- a/src/coverlet.core/Helpers/InstrumentationHelper.cs
+++ b/src/coverlet.core/Helpers/InstrumentationHelper.cs
@@ -113,19 +113,39 @@ namespace Coverlet.Core.Helpers
public static IEnumerable GetExcludedFiles(IEnumerable excludeRules,
string parentDir = null)
{
+ const string RELATIVE_KEY = nameof(RELATIVE_KEY);
parentDir = string.IsNullOrWhiteSpace(parentDir)? Directory.GetCurrentDirectory() : parentDir;
+
if (excludeRules == null || !excludeRules.Any()) return Enumerable.Empty();
- var matcher = new Matcher();
+
+ var matcherDict = new Dictionary(){ {RELATIVE_KEY, new Matcher()}};
foreach (var excludeRule in excludeRules)
{
- matcher.AddInclude(excludeRule);
+ if (Path.IsPathRooted(excludeRule)) {
+ var root = Path.GetPathRoot(excludeRule);
+ if (!matcherDict.ContainsKey(root)) {
+ matcherDict.Add(root, new Matcher());
+ }
+ matcherDict[root].AddInclude(excludeRule.Substring(root.Length));
+ } else {
+ matcherDict[RELATIVE_KEY].AddInclude(excludeRule);
+ }
+
}
-
- DirectoryInfo directoryInfo = new DirectoryInfo(parentDir);
- var fileMatchResult = matcher.Execute(new DirectoryInfoWrapper(directoryInfo));
- return fileMatchResult.Files
- .Select(f => Path.GetFullPath(Path.Combine(directoryInfo.ToString(), f.Path)));
+ var files = new List();
+ foreach(var entry in matcherDict)
+ {
+ var root = entry.Key;
+ var matcher = entry.Value;
+ var directoryInfo = new DirectoryInfo(root.Equals(RELATIVE_KEY) ? parentDir : root);
+ var fileMatchResult = matcher.Execute(new DirectoryInfoWrapper(directoryInfo));
+ var currentFiles = fileMatchResult.Files
+ .Select(f => Path.GetFullPath(Path.Combine(directoryInfo.ToString(), f.Path)));
+ files.AddRange(currentFiles);
+ }
+
+ return files.Distinct();
}
}
}