Skip to content

Commit d07855a

Browse files
authored
Remove coverageGutters, make coverage relative to repo root, add repo root (#2683)
* Add repo root, and remove guttters * Fix output * fix strict * don't use jacoco format * repo root * report root * star or not * move * stars * stars * slash * normalize * paths finally
1 parent d5f7c87 commit d07855a

13 files changed

Lines changed: 178 additions & 321 deletions

build.ps1

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ param (
6565
)
6666

6767
$ErrorActionPreference = 'Stop'
68+
$ErrorView = 'NormalView'
6869
Get-Module Pester | Remove-Module
6970

7071
if ($Clean -and $PSVersionTable.PSVersion -lt [version]'5.1') {
@@ -105,6 +106,10 @@ if ($Clean) {
105106
}
106107

107108
function Format-NicelyMini ($value) {
109+
if ($null -eq $value) {
110+
return '$null'
111+
}
112+
108113
if ($value -is [bool]) {
109114
if ($value) {
110115
'$true'
@@ -148,7 +153,12 @@ if ($Clean) {
148153
foreach ($r in $section.PSObject.Properties.Name) {
149154
$option = $section.$r
150155
$default = Format-NicelyMini $option.Default
151-
$type = $option.Default.GetType() -as [string]
156+
if ("RepoRoot" -eq $r) {
157+
# RepoRoot is a special case, because it is not actually an option, but a property that returns the value of the option. This is done to make it easier to use in scripts, but it causes issues when generating help, because it does not have a default value. So we need to get the default value from the actual option.
158+
$default = Format-NicelyMini '<path of .git>'
159+
}
160+
# When the value is null this would throw if we checked the type of default value.
161+
$type = $option.GetType().BaseType.GenericTypeArguments[0] -as [string]
152162
" ${r}: $($option.Description)$eol Type: ${type}$eol Default value: ${default}$eol"
153163
}
154164
}

src/csharp/Pester/CodeCoverageConfiguration.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public class CodeCoverageConfiguration : ConfigurationSection
3131
private BoolOption _useBps;
3232
private BoolOption _singleHitBreakpoints;
3333
private DecimalOption _coveragePercentTarget;
34+
private StringOption _reportRoot;
3435

3536
public static CodeCoverageConfiguration Default { get { return new CodeCoverageConfiguration(); } }
3637

@@ -41,7 +42,7 @@ public static CodeCoverageConfiguration ShallowClone(CodeCoverageConfiguration c
4142
public CodeCoverageConfiguration() : base("Options to enable and configure Pester's code coverage feature.")
4243
{
4344
Enabled = new BoolOption("Enable CodeCoverage.", false);
44-
OutputFormat = new StringOption("Format to use for code coverage report. Possible values: JaCoCo, CoverageGutters, Cobertura", "JaCoCo");
45+
OutputFormat = new StringOption("Format to use for code coverage report. Possible values: JaCoCo, Cobertura", "JaCoCo");
4546
OutputPath = new StringOption("Path relative to the current directory where code coverage report is saved.", "coverage.xml");
4647
OutputEncoding = new StringOption("Encoding of the output file.", "UTF8");
4748
Path = new StringArrayOption("Directories or files to be used for code coverage, by default the Path(s) from general settings are used, unless overridden here.", new string[0]);
@@ -50,6 +51,7 @@ public CodeCoverageConfiguration() : base("Options to enable and configure Peste
5051
UseBreakpoints = new BoolOption("When false, use Profiler based tracer to do CodeCoverage instead of using breakpoints.", false);
5152
CoveragePercentTarget = new DecimalOption("Target percent of code coverage that you want to achieve, default 75%.", 75m);
5253
SingleHitBreakpoints = new BoolOption("Remove breakpoint when it is hit. This increases performance of breakpoint based CodeCoverage.", true);
54+
ReportRoot = new StringOption("Root path for the code coverage report. Uses Run.RepoRoot by default.", null);
5355
}
5456

5557
public CodeCoverageConfiguration(IDictionary configuration) : this()
@@ -66,6 +68,7 @@ public CodeCoverageConfiguration(IDictionary configuration) : this()
6668
configuration.AssignValueIfNotNull<bool>(nameof(UseBreakpoints), v => UseBreakpoints = v);
6769
configuration.AssignValueIfNotNull<decimal>(nameof(CoveragePercentTarget), v => CoveragePercentTarget = v);
6870
configuration.AssignValueIfNotNull<bool>(nameof(SingleHitBreakpoints), v => SingleHitBreakpoints = v);
71+
configuration.AssignObjectIfNotNull<string>(nameof(ReportRoot), v => ReportRoot = v);
6972
}
7073
}
7174

@@ -228,5 +231,21 @@ public BoolOption SingleHitBreakpoints
228231
}
229232
}
230233
}
234+
235+
public StringOption ReportRoot
236+
{
237+
get { return _reportRoot; }
238+
set
239+
{
240+
if (_reportRoot == null)
241+
{
242+
_reportRoot = value;
243+
}
244+
else
245+
{
246+
_reportRoot = new StringOption(_reportRoot, value?.Value);
247+
}
248+
}
249+
}
231250
}
232251
}

src/csharp/Pester/RunConfiguration.cs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections;
1+
using System.IO;
2+
using System.Collections;
23
using System.Management.Automation;
34

45
// those types implement Pester configuration in a way that allows it to show information about each item
@@ -33,6 +34,7 @@ public class RunConfiguration : ConfigurationSection
3334
private BoolOption _skipRun;
3435
private StringOption _skipRemainingOnFailure;
3536
private BoolOption _failOnNullOrEmptyForEach;
37+
private StringOption _repoRoot;
3638

3739
public static RunConfiguration Default { get { return new RunConfiguration(); } }
3840
public static RunConfiguration ShallowClone(RunConfiguration configuration)
@@ -54,7 +56,8 @@ public RunConfiguration(IDictionary configuration) : this()
5456
configuration.AssignValueIfNotNull<bool>(nameof(PassThru), v => PassThru = v);
5557
configuration.AssignValueIfNotNull<bool>(nameof(SkipRun), v => SkipRun = v);
5658
configuration.AssignObjectIfNotNull<string>(nameof(SkipRemainingOnFailure), v => SkipRemainingOnFailure = v);
57-
configuration.AssignValueIfNotNull<bool>(nameof(FailOnNullOrEmptyForEach ), v => FailOnNullOrEmptyForEach = v);
59+
configuration.AssignValueIfNotNull<bool>(nameof(FailOnNullOrEmptyForEach), v => FailOnNullOrEmptyForEach = v);
60+
configuration.AssignObjectIfNotNull<string>(nameof(RepoRoot), v => RepoRoot = v);
5861
}
5962
}
6063

@@ -70,7 +73,8 @@ public RunConfiguration(IDictionary configuration) : this()
7073
PassThru = new BoolOption("Return result object to the pipeline after finishing the test run.", false);
7174
SkipRun = new BoolOption("Runs the discovery phase but skips run. Use it with PassThru to get object populated with all tests.", false);
7275
SkipRemainingOnFailure = new StringOption("Skips remaining tests after failure for selected scope, options are None, Run, Container and Block.", "None");
73-
FailOnNullOrEmptyForEach = new BoolOption("Fails discovery when -ForEach is provided $null or @() in a block or test. Can be overridden for a specific Describe/Context/It using -AllowNullOrEmptyForEach.", true);
76+
FailOnNullOrEmptyForEach = new BoolOption("Fails discovery when -ForEach is provided $null or @() in a block or test. Can be overridden for a specific Describe/Context/It using -AllowNullOrEmptyForEach.", true);
77+
RepoRoot = new StringOption("Root directory of the repository. Found by searching for the .git directory recursively. When not found, the current working directory is used.", FindRepoRoot());
7478
}
7579

7680
public StringArrayOption Path
@@ -248,5 +252,38 @@ public BoolOption FailOnNullOrEmptyForEach
248252
}
249253
}
250254
}
255+
256+
public StringOption RepoRoot
257+
{
258+
get { return _repoRoot; }
259+
set
260+
{
261+
if (_repoRoot == null)
262+
{
263+
_repoRoot = value;
264+
}
265+
else
266+
{
267+
_repoRoot = new StringOption(_repoRoot, value?.Value);
268+
}
269+
}
270+
}
271+
272+
private static string FindRepoRoot()
273+
{
274+
var originalDir = Directory.GetCurrentDirectory();
275+
var currentDir = originalDir;
276+
while (!Directory.Exists(System.IO.Path.Combine(currentDir, ".git")))
277+
{
278+
var parentDir = Directory.GetParent(currentDir);
279+
if (parentDir == null)
280+
{
281+
return originalDir;
282+
}
283+
currentDir = parentDir.FullName;
284+
}
285+
return currentDir;
286+
287+
}
251288
}
252289
}

src/en-US/about_PesterConfiguration.help.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ SECTIONS AND OPTIONS
7373
Type: bool
7474
Default value: $true
7575

76+
RepoRoot: Root directory of the repository. Found by searching for the .git directory recursively. When not found, the current working directory is used.
77+
Type: string
78+
Default value: '<path of .git>'
79+
7680
Filter:
7781
Tag: Tags of Describe, Context or It to be run.
7882
Type: string[]
@@ -99,7 +103,7 @@ SECTIONS AND OPTIONS
99103
Type: bool
100104
Default value: $false
101105

102-
OutputFormat: Format to use for code coverage report. Possible values: JaCoCo, CoverageGutters, Cobertura
106+
OutputFormat: Format to use for code coverage report. Possible values: JaCoCo, Cobertura
103107
Type: string
104108
Default value: 'JaCoCo'
105109

@@ -135,6 +139,10 @@ SECTIONS AND OPTIONS
135139
Type: bool
136140
Default value: $true
137141

142+
ReportRoot: Root path for the code coverage report. Uses Run.RepoRoot by default.
143+
Type: string
144+
Default value: $null
145+
138146
TestResult:
139147
Enabled: Enable TestResult.
140148
Type: bool

src/functions/Coverage.Plugin.ps1

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,8 @@
146146
$configuration = $run.PluginConfiguration.Coverage
147147

148148
$coverageXmlReport = switch ($configuration.OutputFormat) {
149-
'JaCoCo' { [xml](Get-JaCoCoReportXml -CommandCoverage $breakpoints -TotalMilliseconds $totalMilliseconds -CoverageReport $coverageReport -Format 'JaCoCo') }
150-
'CoverageGutters' { [xml](Get-JaCoCoReportXml -CommandCoverage $breakpoints -TotalMilliseconds $totalMilliseconds -CoverageReport $coverageReport -Format 'CoverageGutters') }
151-
'Cobertura' { [xml](Get-CoberturaReportXml -CoverageReport $coverageReport -TotalMilliseconds $totalMilliseconds) }
149+
'JaCoCo' { [xml](Get-JaCoCoReportXml -CommandCoverage $breakpoints -TotalMilliseconds $totalMilliseconds -CoverageReport $coverageReport -ReportRoot (Get-ReportRoot)) }
150+
'Cobertura' { [xml](Get-CoberturaReportXml -CoverageReport $coverageReport -TotalMilliseconds $totalMilliseconds -ReportRoot (Get-ReportRoot)) }
152151
default { throw "CodeCoverage.CoverageFormat '$($configuration.OutputFormat)' is not valid, please review your configuration." }
153152
}
154153

@@ -216,7 +215,7 @@
216215
}
217216

218217
function Resolve-CodeCoverageConfiguration {
219-
$supportedFormats = 'JaCoCo', 'CoverageGutters', 'Cobertura'
218+
$supportedFormats = 'JaCoCo', 'Cobertura'
220219
if ($PesterPreference.CodeCoverage.OutputFormat.Value -notin $supportedFormats) {
221220
throw (Get-StringOptionErrorMessage -OptionPath 'CodeCoverage.OutputFormat' -SupportedValues $supportedFormats -Value $PesterPreference.CodeCoverage.OutputFormat.Value)
222221
}

0 commit comments

Comments
 (0)