Skip to content

Commit a7c8b8a

Browse files
authored
Tool changes (#103)
1 parent 67af3a6 commit a7c8b8a

File tree

63 files changed

+1448
-821
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1448
-821
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System.ComponentModel.Composition;
2+
using System.IO;
3+
using FineCodeCoverage.Core.Utilities;
4+
using FineCodeCoverage.Engine.Model;
5+
6+
namespace FineCodeCoverage.Engine.Coverlet
7+
{
8+
internal interface ICoverletConsoleCustomPathExecutor : ICoverletConsoleExecutor { }
9+
10+
[Export(typeof(ICoverletConsoleCustomPathExecutor))]
11+
internal class CoverletConsoleCustomPathExecutor : ICoverletConsoleCustomPathExecutor
12+
{
13+
public ExecuteRequest GetRequest(ICoverageProject coverageProject,string coverletSettings)
14+
{
15+
var coverletConsoleCustomPath = coverageProject.Settings.CoverletConsoleCustomPath;
16+
if (string.IsNullOrWhiteSpace(coverletConsoleCustomPath))
17+
{
18+
return null;
19+
}
20+
if (File.Exists(coverletConsoleCustomPath) && Path.GetExtension(coverletConsoleCustomPath) == ".exe")
21+
{
22+
return new ExecuteRequest
23+
{
24+
FilePath = coverletConsoleCustomPath,
25+
Arguments = coverletSettings,
26+
WorkingDirectory = coverageProject.ProjectOutputFolder
27+
};
28+
}
29+
return null;
30+
}
31+
}
32+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System.ComponentModel.Composition;
2+
using FineCodeCoverage.Core.Utilities;
3+
using FineCodeCoverage.Engine.Model;
4+
5+
namespace FineCodeCoverage.Engine.Coverlet
6+
{
7+
internal interface ICoverletConsoleDotnetToolsGlobalExecutor : ICoverletConsoleExecutor
8+
{
9+
10+
}
11+
12+
[Export(typeof(ICoverletConsoleDotnetToolsGlobalExecutor))]
13+
internal class CoverletConsoleDotnetToolsGlobalExecutor : ICoverletConsoleDotnetToolsGlobalExecutor
14+
{
15+
private readonly IDotNetToolListCoverlet dotNetToolListCoverlet;
16+
17+
[ImportingConstructor]
18+
public CoverletConsoleDotnetToolsGlobalExecutor(IDotNetToolListCoverlet dotNetToolListCoverlet)
19+
{
20+
this.dotNetToolListCoverlet = dotNetToolListCoverlet;
21+
}
22+
public ExecuteRequest GetRequest(ICoverageProject coverageProject, string coverletSettings)
23+
{
24+
if (coverageProject.Settings.CoverletConsoleGlobal)
25+
{
26+
var details = dotNetToolListCoverlet.Global();
27+
if(details == null)
28+
{
29+
return null;
30+
}
31+
return new ExecuteRequest
32+
{
33+
FilePath = details.Command,
34+
Arguments = coverletSettings,
35+
WorkingDirectory = coverageProject.ProjectOutputFolder
36+
};
37+
}
38+
return null;
39+
40+
}
41+
}
42+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System.ComponentModel.Composition;
2+
using FineCodeCoverage.Core.Utilities;
3+
using FineCodeCoverage.Engine.Model;
4+
5+
namespace FineCodeCoverage.Engine.Coverlet
6+
{
7+
internal interface ICoverletConsoleDotnetToolsLocalExecutor : ICoverletConsoleExecutor { }
8+
9+
[Export(typeof(ICoverletConsoleDotnetToolsLocalExecutor))]
10+
internal class CoverletConsoleDotnetToolsLocalExecutor : ICoverletConsoleDotnetToolsLocalExecutor
11+
{
12+
private readonly IDotNetToolListCoverlet dotnetToolListCoverlet;
13+
private readonly IDotNetConfigFinder dotNetConfigFinder;
14+
15+
[ImportingConstructor]
16+
public CoverletConsoleDotnetToolsLocalExecutor(IDotNetToolListCoverlet dotnetToolListCoverlet, IDotNetConfigFinder dotNetConfigFinder)
17+
{
18+
this.dotnetToolListCoverlet = dotnetToolListCoverlet;
19+
this.dotNetConfigFinder = dotNetConfigFinder;
20+
}
21+
public ExecuteRequest GetRequest(ICoverageProject coverageProject, string coverletSettings)
22+
{
23+
if (coverageProject.Settings.CoverletConsoleLocal)
24+
{
25+
foreach(var configContainingDirectory in dotNetConfigFinder.GetConfigDirectories(coverageProject.ProjectOutputFolder))
26+
{
27+
var coverletToolDetails = dotnetToolListCoverlet.Local(configContainingDirectory);
28+
if(coverletToolDetails != null)
29+
{
30+
return new ExecuteRequest
31+
{
32+
FilePath = "dotnet",
33+
Arguments = coverletToolDetails.Command + " " + coverletSettings,
34+
WorkingDirectory = configContainingDirectory
35+
};
36+
}
37+
}
38+
39+
return null;
40+
}
41+
return null;
42+
}
43+
}
44+
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel.Composition;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
using FineCodeCoverage.Core.Utilities;
7+
using FineCodeCoverage.Engine.Model;
8+
9+
namespace FineCodeCoverage.Engine.Coverlet
10+
{
11+
[Export(typeof(ICoverletConsoleUtil))]
12+
internal class CoverletConsoleUtil : ICoverletConsoleUtil
13+
{
14+
private readonly IProcessUtil processUtil;
15+
private readonly ILogger logger;
16+
private readonly IFCCCoverletConsoleExecutor fccExecutor;
17+
private readonly List<ICoverletConsoleExecutor> executors;
18+
19+
[ImportingConstructor]
20+
public CoverletConsoleUtil(
21+
IProcessUtil processUtil,
22+
ILogger logger,
23+
[Import(typeof(ICoverletConsoleDotnetToolsGlobalExecutor))]
24+
ICoverletConsoleExecutor globalExecutor,
25+
[Import(typeof(ICoverletConsoleCustomPathExecutor))]
26+
ICoverletConsoleExecutor customPathExecutor,
27+
[Import(typeof(ICoverletConsoleDotnetToolsLocalExecutor))]
28+
ICoverletConsoleExecutor localExecutor,
29+
IFCCCoverletConsoleExecutor fccExecutor
30+
)
31+
{
32+
this.processUtil = processUtil;
33+
this.logger = logger;
34+
35+
executors = new List<ICoverletConsoleExecutor>
36+
{
37+
localExecutor,
38+
customPathExecutor,
39+
globalExecutor,
40+
fccExecutor
41+
};
42+
43+
this.fccExecutor = fccExecutor;
44+
}
45+
public void Initialize(string appDataFolder)
46+
{
47+
fccExecutor.Initialize(appDataFolder);
48+
}
49+
50+
// for now FCCCoverletConsoleExeProvider can return null for exe path
51+
52+
internal ExecuteRequest GetExecuteRequest(ICoverageProject project, string coverletSettings)
53+
{
54+
foreach(var exeProvider in executors)
55+
{
56+
var executeRequest = exeProvider.GetRequest(project, coverletSettings);
57+
if(executeRequest != null)
58+
{
59+
return executeRequest;
60+
}
61+
}
62+
return null;//todo change to throw when using zip file
63+
}
64+
65+
internal List<string> GetCoverletSettings(ICoverageProject project)
66+
{
67+
var coverletSettings = new List<string>();
68+
69+
coverletSettings.Add($@"""{project.TestDllFile}""");
70+
71+
coverletSettings.Add($@"--format ""cobertura""");
72+
73+
foreach (var value in (project.Settings.Exclude ?? new string[0]).Where(x => !string.IsNullOrWhiteSpace(x)))
74+
{
75+
coverletSettings.Add($@"--exclude ""{value.Replace("\"", "\\\"").Trim(' ', '\'')}""");
76+
}
77+
78+
foreach (var referencedProjectExcludedFromCodeCoverage in project.ExcludedReferencedProjects)
79+
{
80+
coverletSettings.Add($@"--exclude ""[{referencedProjectExcludedFromCodeCoverage}]*""");
81+
}
82+
83+
foreach (var value in (project.Settings.Include ?? new string[0]).Where(x => !string.IsNullOrWhiteSpace(x)))
84+
{
85+
coverletSettings.Add($@"--include ""{value.Replace("\"", "\\\"").Trim(' ', '\'')}""");
86+
}
87+
88+
foreach (var value in (project.Settings.ExcludeByFile ?? new string[0]).Where(x => !string.IsNullOrWhiteSpace(x)))
89+
{
90+
coverletSettings.Add($@"--exclude-by-file ""{value.Replace("\"", "\\\"").Trim(' ', '\'')}""");
91+
}
92+
93+
foreach (var value in (project.Settings.ExcludeByAttribute ?? new string[0]).Where(x => !string.IsNullOrWhiteSpace(x)))
94+
{
95+
coverletSettings.Add($@"--exclude-by-attribute ""{value.Replace("\"", "\\\"").Trim(' ', '\'', '[', ']')}""");
96+
}
97+
98+
if (project.Settings.IncludeTestAssembly)
99+
{
100+
coverletSettings.Add("--include-test-assembly");
101+
}
102+
103+
coverletSettings.Add($@"--target ""dotnet""");
104+
105+
coverletSettings.Add($@"--threshold-type line");
106+
107+
coverletSettings.Add($@"--threshold-stat total");
108+
109+
coverletSettings.Add($@"--threshold 0");
110+
111+
coverletSettings.Add($@"--output ""{ project.CoverageOutputFile }""");
112+
113+
var runSettings = !string.IsNullOrWhiteSpace(project.RunSettingsFile) ? $@"--settings """"{project.RunSettingsFile}""""" : default;
114+
coverletSettings.Add($@"--targetargs ""test """"{project.TestDllFile}"""" --nologo --blame {runSettings} --results-directory """"{project.CoverageOutputFolder}"""" --diag """"{project.CoverageOutputFolder}/diagnostics.log"""" """);
115+
116+
return coverletSettings;
117+
}
118+
119+
public async Task<bool> RunAsync(ICoverageProject project, bool throwError = false)
120+
{
121+
var title = $"Coverlet Run ({project.ProjectName})";
122+
123+
var coverletSettings = GetCoverletSettings(project);
124+
125+
logger.Log($"{title} Arguments {Environment.NewLine}{string.Join($"{Environment.NewLine}", coverletSettings)}");
126+
127+
var result = await processUtil
128+
.ExecuteAsync(GetExecuteRequest(project, string.Join(" ", coverletSettings)));
129+
130+
131+
if (result != null)
132+
{
133+
/*
134+
0 - Success.
135+
1 - If any test fails.
136+
2 - Coverage percentage is below threshold.
137+
3 - Test fails and also coverage percentage is below threshold.
138+
*/
139+
if (result.ExitCode > 3)
140+
{
141+
if (throwError)
142+
{
143+
throw new Exception(result.Output);
144+
}
145+
146+
logger.Log($"{title} Error", result.Output);
147+
return false;
148+
}
149+
150+
logger.Log(title, result.Output);
151+
152+
return true;
153+
}
154+
return false;
155+
}
156+
}
157+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System;
2+
using System.ComponentModel.Composition;
3+
using System.Linq;
4+
using FineCodeCoverage.Core.Utilities;
5+
6+
namespace FineCodeCoverage.Engine.Coverlet
7+
{
8+
[Export(typeof(IDotNetToolListCoverlet))]
9+
internal class DotNetToolListCoverlet : IDotNetToolListCoverlet
10+
{
11+
private const string CoverletPackageId = "coverlet.console";
12+
private readonly ILogger logger;
13+
private readonly IDotNetToolListExecutor executor;
14+
private readonly IDotNetToolListParser parser;
15+
16+
[ImportingConstructor]
17+
public DotNetToolListCoverlet(ILogger logger, IDotNetToolListExecutor executor, IDotNetToolListParser parser)
18+
{
19+
this.logger = logger;
20+
this.executor = executor;
21+
this.parser = parser;
22+
}
23+
24+
private CoverletToolDetails ExecuteAndParse(Func<IDotNetToolListExecutor,DotNetToolListExecutionResult> execution )
25+
{
26+
var result = execution(executor);
27+
if(result.ExitCode != 0)
28+
{
29+
var title = $"Dotnet tool list Coverlet";
30+
logger.Log($"{title} Error", result.Output);
31+
return null;
32+
}
33+
34+
var tools = parser.Parse(result.Output);
35+
var coverletConsoleTool = tools.FirstOrDefault(tool => tool.PackageId == CoverletPackageId);
36+
if(coverletConsoleTool == null)
37+
{
38+
return null;
39+
}
40+
41+
return new CoverletToolDetails
42+
{
43+
Version = coverletConsoleTool.Version,
44+
Command = coverletConsoleTool.Commands
45+
};
46+
}
47+
48+
public CoverletToolDetails Global()
49+
{
50+
return ExecuteAndParse(executor => executor.Global());
51+
}
52+
53+
public CoverletToolDetails Local(string directory)
54+
{
55+
return ExecuteAndParse(executor => executor.Local(directory));
56+
}
57+
58+
public CoverletToolDetails GlobalToolsPath(string directory)
59+
{
60+
return ExecuteAndParse(executor => executor.GlobalToolsPath(directory));
61+
}
62+
63+
}
64+
}

0 commit comments

Comments
 (0)