Skip to content

Commit

Permalink
Add function 'Get-PSCodeHealthSetting' to get the settings (metrics t…
Browse files Browse the repository at this point in the history
…hreasholds, etc...)
  • Loading branch information
MathieuBuisson committed May 7, 2017
1 parent c00d761 commit 05ad384
Show file tree
Hide file tree
Showing 18 changed files with 170 additions and 73 deletions.
2 changes: 1 addition & 1 deletion PSCodeHealth/PSCodeHealth.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ FormatsToProcess = @('PSCodeHealth.Format.ps1xml')
# NestedModules = @()

# Functions to export from this module
FunctionsToExport = @('Invoke-PSCodeHealth')
FunctionsToExport = @('Invoke-PSCodeHealth','Get-PSCodeHealthSetting')

# Cmdlets to export from this module
# CmdletsToExport = '*'
Expand Down
2 changes: 1 addition & 1 deletion PSCodeHealth/Private/Get-FunctionLinesOfCode.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Function Get-FunctionLinesOfCode {
[CmdletBinding()]
[OutputType([System.Int32])]
Param (
[Parameter(Position=0, Mandatory=$True)]
[Parameter(Position=0, Mandatory)]
[System.Management.Automation.Language.FunctionDefinitionAst]$FunctionDefinition
)

Expand Down
2 changes: 1 addition & 1 deletion PSCodeHealth/Private/Get-FunctionScriptAnalyzerResult.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Function Get-FunctionScriptAnalyzerResult {
[CmdletBinding()]
[OutputType([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord])]
Param (
[Parameter(Position=0, Mandatory=$True)]
[Parameter(Position=0, Mandatory)]
[System.Management.Automation.Language.FunctionDefinitionAst]$FunctionDefinition
)

Expand Down
2 changes: 1 addition & 1 deletion PSCodeHealth/Private/Get-FunctionTestCoverage.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Function Get-FunctionTestCoverage {
[CmdletBinding()]
[OutputType([System.Double])]
Param (
[Parameter(Position=0, Mandatory=$True)]
[Parameter(Position=0, Mandatory)]
[System.Management.Automation.Language.FunctionDefinitionAst]$FunctionDefinition,

[Parameter(Position=1, Mandatory=$False)]
Expand Down
2 changes: 1 addition & 1 deletion PSCodeHealth/Private/Measure-FunctionComplexity.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Function Measure-FunctionComplexity {
[CmdletBinding()]
[OutputType([System.Int32])]
Param (
[Parameter(Position=0, Mandatory=$True)]
[Parameter(Position=0, Mandatory)]
[System.Management.Automation.Language.FunctionDefinitionAst]$FunctionDefinition
)
# Default complexity value for code which contains no branching statement (1 code path)
Expand Down
2 changes: 1 addition & 1 deletion PSCodeHealth/Private/Measure-FunctionForCodePath.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Function Measure-FunctionForCodePath {
[CmdletBinding()]
[OutputType([System.Int32])]
Param (
[Parameter(Position=0, Mandatory=$True)]
[Parameter(Position=0, Mandatory)]
[System.Management.Automation.Language.FunctionDefinitionAst]$FunctionDefinition
)

Expand Down
2 changes: 1 addition & 1 deletion PSCodeHealth/Private/Measure-FunctionIfCodePath.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Function Measure-FunctionIfCodePath {
[CmdletBinding()]
[OutputType([System.Int32])]
Param (
[Parameter(Position=0, Mandatory=$True)]
[Parameter(Position=0, Mandatory)]
[System.Management.Automation.Language.FunctionDefinitionAst]$FunctionDefinition
)

Expand Down
2 changes: 1 addition & 1 deletion PSCodeHealth/Private/Measure-FunctionLogicalOpCodePath.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Function Measure-FunctionLogicalOpCodePath {
[CmdletBinding()]
[OutputType([System.Int32])]
Param (
[Parameter(Position=0, Mandatory=$True)]
[Parameter(Position=0, Mandatory)]
[System.Management.Automation.Language.FunctionDefinitionAst]$FunctionDefinition
)

Expand Down
2 changes: 1 addition & 1 deletion PSCodeHealth/Private/Measure-FunctionMaxNestingDepth.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Function Measure-FunctionMaxNestingDepth {
[CmdletBinding()]
[OutputType([System.Int32])]
Param (
[Parameter(Position=0, Mandatory=$True)]
[Parameter(Position=0, Mandatory)]
[System.Management.Automation.Language.FunctionDefinitionAst]$FunctionDefinition
)

Expand Down
2 changes: 1 addition & 1 deletion PSCodeHealth/Private/Measure-FunctionSwitchCodePath.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Function Measure-FunctionSwitchCodePath {
[CmdletBinding()]
[OutputType([System.Int32])]
Param (
[Parameter(Position=0, Mandatory=$True)]
[Parameter(Position=0, Mandatory)]
[System.Management.Automation.Language.FunctionDefinitionAst]$FunctionDefinition
)

Expand Down
2 changes: 1 addition & 1 deletion PSCodeHealth/Private/Measure-FunctionTrapCatchCodePath.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Function Measure-FunctionTrapCatchCodePath {
[CmdletBinding()]
[OutputType([System.Int32])]
Param (
[Parameter(Position=0, Mandatory=$True)]
[Parameter(Position=0, Mandatory)]
[System.Management.Automation.Language.FunctionDefinitionAst]$FunctionDefinition
)

Expand Down
2 changes: 1 addition & 1 deletion PSCodeHealth/Private/Measure-FunctionWhileCodePath.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Function Measure-FunctionWhileCodePath {
[CmdletBinding()]
[OutputType([System.Int32])]
Param (
[Parameter(Position=0, Mandatory=$True)]
[Parameter(Position=0, Mandatory)]
[System.Management.Automation.Language.FunctionDefinitionAst]$FunctionDefinition
)

Expand Down
2 changes: 1 addition & 1 deletion PSCodeHealth/Private/Test-FunctionHelpCoverage.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Function Test-FunctionHelpCoverage {
[CmdletBinding()]
[OutputType([System.Boolean])]
Param (
[Parameter(Position=0, Mandatory=$True)]
[Parameter(Position=0, Mandatory)]
[System.Management.Automation.Language.FunctionDefinitionAst]$FunctionDefinition
)

Expand Down
2 changes: 1 addition & 1 deletion PSCodeHealth/Private/Write-VerboseOutput.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Function Write-VerboseOutput {
#>
[CmdletBinding()]
Param(
[Parameter(Position=0, Mandatory=$True)]
[Parameter(Position=0, Mandatory)]
[string]$Message
)

Expand Down
106 changes: 47 additions & 59 deletions PSCodeHealth/Public/Get-PSCodeHealthSetting.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,78 +14,66 @@ Function Get-PSCodeHealthSetting {
To specify the path of a file containing user-defined settings (metrics thresholds, etc...) in JSON format.
Any setting specified in this file override the default, and settings not specified in this file will use the default from PSCodeHealthSettings.json.
.PARAMETER SettingsGroup
To filter the output settings to only the settings located in the specified group.
There 2 settings group in PSCodeHealthSettings.json, so there are 2 possible values for this parameter : 'FunctionHealthRecordMetricsRules' and 'OverallHealthReportMetricsRules'.
If not specified, all the settings are output.
.OUTPUTS
System.Management.Automation.PSCustomObject
#>
[CmdletBinding()]
[OutputType([PSCustomObject])]
[OutputType([PSCustomObject[]])]
Param(
[Parameter(Mandatory=$False,Position=0)]
[PSCustomObject]$CustomSettingsPath
)

# Checking if $CustomSettings contains something
$ContainsSettings = $CustomSettings | Get-Member -MemberType Properties
If ( -not($ContainsSettings) ) {
Write-VerboseOutput -Message 'Custom settings do not contain any data, the resulting settings will be the defaults.'
return $DefaultSettings
}
[ValidateScript({ Test-Path -Path $_ -PathType Leaf })]
[string]$CustomSettingsPath,

$ContainsFunctionHealthRecordSettings = 'FunctionHealthRecordMetricsRules' -in $ContainsSettings.Name
$ContainsOverallHealthReportSettings = 'OverallHealthReportMetricsRules' -in $ContainsSettings.Name
[Parameter(Mandatory=$False,Position=1)]
[ValidateSet('FunctionHealthRecordMetricsRules','OverallHealthReportMetricsRules')]
[string]$SettingsGroup,

If ( -not($ContainsFunctionHealthRecordSettings) -and -not($ContainsOverallHealthReportSettings) ) {
Write-Warning -Message 'Custom settings do not contain any of the settings groups expected by PSCodeHealth.'
return $DefaultSettings
}

If ( $ContainsFunctionHealthRecordSettings) {
$CustomFunctionSettings = $CustomSettings.FunctionHealthRecordMetricsRules | Where-Object { $_ }
[Parameter(Mandatory=$False,Position=2)]
[ValidateSet('LinesOfCode','ScriptAnalyzerFindings','TestCoverage','Complexity','MaximumNestingDepth','LinesOfCodeTotal',
'LinesOfCodeAverage','ScriptAnalyzerFindingsTotal','ScriptAnalyzerErrors','ScriptAnalyzerWarnings',
'ScriptAnalyzerInformation','ScriptAnalyzerFindingsAverage','NumberOfFailedTests','TestsPassRate',
'CommandsMissedTotal','ComplexityAverage','NestingDepthAverage')]
[string]$MetricName
)

# Casting to a list in case we need to add elements to it
$DefaultFunctionSettings = ($DefaultSettings.FunctionHealthRecordMetricsRules | Where-Object { $_ }) -as [System.Collections.ArrayList]

Foreach ( $CustomFunctionSetting in $CustomFunctionSettings ) {
$MetricName = ($CustomFunctionSetting | Get-Member -MemberType Properties).Name
Write-VerboseOutput -Message "Processing custom settings for metric : $MetricName"
$DefaultSettingsPath = "$PSScriptRoot\..\PSCodeHealthSettings.json"
$DefaultSettings = ConvertFrom-Json (Get-Content -Path $DefaultSettingsPath -Raw)

$DefaultFunctionSetting = $DefaultFunctionSettings | Where-Object { $_.$($MetricName) }
If ( $DefaultFunctionSetting ) {
Write-VerboseOutput -Message "The setting '$MetricName' is present in the default settings, overriding it."
$DefaultFunctionSetting.$($MetricName) = $CustomFunctionSetting.$($MetricName)
}
Else {
Write-VerboseOutput -Message "The setting '$MetricName' is absent from the default settings, adding it."
$Null = $DefaultFunctionSettings.Add($CustomFunctionSetting)
}
If ( $PSBoundParameters.ContainsKey('CustomSettingsPath') ) {
Try {
$CustomSettings = ConvertFrom-Json (Get-Content -Path $CustomSettingsPath -Raw) -ErrorAction Stop
}
Catch {
Throw "An error occurred when attempting to convert JSON data from the file $CustomSettingsPath to an object. Please verify that the content of this file is in valid JSON format."
}
}

If ( $ContainsOverallHealthReportSettings ) {
$CustomOverallSettings = $CustomSettings.OverallHealthReportMetricsRules | Where-Object { $_ }

# Casting to a list in case we need to add elements to it
$DefaultOverallSettings = ($DefaultSettings.OverallHealthReportMetricsRules | Where-Object { $_ }) -as [System.Collections.ArrayList]

Foreach ( $CustomOverallSetting in $CustomOverallSettings ) {
$MetricName = ($CustomOverallSetting | Get-Member -MemberType Properties).Name
Write-VerboseOutput -Message "Processing custom settings for metric : $MetricName"

$DefaultOverallSetting = $DefaultOverallSettings | Where-Object { $_.$($MetricName) }
If ( $DefaultOverallSetting ) {
Write-VerboseOutput -Message "The setting '$MetricName' is present in the default settings, overriding it."
$DefaultOverallSetting.$($MetricName) = $CustomOverallSetting.$($MetricName)
}
Else {
Write-VerboseOutput -Message "The setting '$MetricName' is absent from the default settings, adding it."
$Null = $DefaultOverallSettings.Add($CustomOverallSetting)
}

If ( $CustomSettings ) {
$SettingsInEffect = Merge-PSCodeHealthSetting -DefaultSettings $DefaultSettings -CustomSettings $CustomSettings
}
Else {
$SettingsInEffect = $DefaultSettings
}
If ( $PSBoundParameters.ContainsKey('SettingsGroup') ) {
$OutputSettings = $SettingsInEffect.$($PSBoundParameters.SettingsGroup)
If ( $PSBoundParameters.ContainsKey('MetricName') ) {
$OutputSettings = $OutputSettings.$($PSBoundParameters.MetricName)
}
}
$MergedSettingsProperties = [ordered]@{
FunctionHealthRecordMetricsRules = $DefaultFunctionSettings
OverallHealthReportMetricsRules = $DefaultOverallSettings
Else {
$OutputSettings = $SettingsInEffect
If ( $PSBoundParameters.ContainsKey('MetricName') ) {
$SettingsGroupNames = ($OutputSettings | Get-Member -MemberType Properties).Name

# There can be more than 1 object because a few metrics are available in both settings groups
$MetricObjects = $SettingsGroupNames | ForEach-Object { $OutputSettings.$($_) } | Where-Object { $_.$($PSBoundParameters.MetricName) }
$OutputSettings = $MetricObjects | ForEach-Object { $_.$($MetricName) }
}
}
$MergedSettings = New-Object -TypeName PSCustomObject -Property $MergedSettingsProperties
return $MergedSettings
return $OutputSettings
}
1 change: 1 addition & 0 deletions Tests/Unit/Private/Merge-PSCodeHealthSetting.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -127,5 +127,6 @@ Describe 'Merge-PSCodeHealthSetting' {
$Result.OverallHealthReportMetricsRules.DummyMetric2.FailThreshold | Should Be 8
}
}
Remove-Variable -Name 'DefaultSettings' -Force -ErrorAction SilentlyContinue
}
}
94 changes: 94 additions & 0 deletions Tests/Unit/Public/Get-PSCodeHealthSetting.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
$ModuleName = 'PSCodeHealth'
Import-Module "$PSScriptRoot\..\..\..\$ModuleName\$($ModuleName).psd1" -Force

Describe 'Get-PSCodeHealthSetting' {
InModuleScope $ModuleName {

$DefaultSettings = ConvertFrom-Json (Get-Content -Path "$PSScriptRoot\..\..\..\PSCodeHealth\PSCodeHealthSettings.json" -Raw)

Context 'The file specified via the CustomSettingsPath parameter does not contain valid JSON' {

$InvalidJsonPath = "$PSScriptRoot\..\TestData\InvalidSettings.json"

It 'Should throw "An error occurred when attempting to convert JSON data"' {
{ Get-PSCodeHealthSetting -CustomSettingsPath $InvalidJsonPath } |
Should Throw "An error occurred when attempting to convert JSON data "
}
}
Context 'The file specified via the CustomSettingsPath parameter does not contain any data' {

$EmptyJsonPath = "$PSScriptRoot\..\TestData\Empty.json"
$Result = Get-PSCodeHealthSetting -CustomSettingsPath $EmptyJsonPath

It 'Should return an object of the type [PSCustomObject]' {
$Result | Should BeOfType [PSCustomObject]
}
It 'Resulting settings are the same as the defaults for metric "LinesOfCode"' {
$Result.FunctionHealthRecordMetricsRules.LinesOfCode.WarningThreshold | Should Be 20
$Result.FunctionHealthRecordMetricsRules.LinesOfCode.FailThreshold | Should Be 40
}
It 'Resulting settings are the same as the defaults for metric "TestCoverage"' {
$Result.FunctionHealthRecordMetricsRules.TestCoverage.WarningThreshold | Should Be 80
$Result.FunctionHealthRecordMetricsRules.TestCoverage.FailThreshold | Should Be 70
}
It 'Resulting settings are the same as the defaults for metric "Complexity"' {
$Result.FunctionHealthRecordMetricsRules.Complexity.WarningThreshold | Should Be 15
$Result.FunctionHealthRecordMetricsRules.Complexity.FailThreshold | Should Be 30
}
It 'Resulting settings are the same as the defaults for metric "MaximumNestingDepth"' {
$Result.FunctionHealthRecordMetricsRules.MaximumNestingDepth.WarningThreshold | Should Be 4
$Result.FunctionHealthRecordMetricsRules.MaximumNestingDepth.FailThreshold | Should Be 8
}
It 'Resulting settings are the same as the defaults for metric "TestsPassRate"' {
$Result.OverallHealthReportMetricsRules.TestsPassRate.WarningThreshold | Should Be 99
$Result.OverallHealthReportMetricsRules.TestsPassRate.FailThreshold | Should Be 97
}
It 'Resulting settings are the same as the defaults for metric "LinesOfCodeTotal"' {
$Result.OverallHealthReportMetricsRules.LinesOfCodeTotal.WarningThreshold | Should Be 1000
$Result.OverallHealthReportMetricsRules.LinesOfCodeTotal.FailThreshold | Should Be 2000
}
}
Context 'The custom settings file contains 2 metrics in both settings groups' {

$MetricsInBothGroups = "$PSScriptRoot\..\TestData\2SettingsGroups4Metrics.json"
$Result = Get-PSCodeHealthSetting -CustomSettingsPath $MetricsInBothGroups

It 'Should return an object of the type [PSCustomObject]' {
$Result | Should BeOfType [PSCustomObject]
}
It 'Resulting settings are the same as the defaults for metric "LinesOfCode"' {
$Result.FunctionHealthRecordMetricsRules.LinesOfCode.WarningThreshold | Should Be 20
$Result.FunctionHealthRecordMetricsRules.LinesOfCode.FailThreshold | Should Be 40
}
It 'Resulting settings are the same as the defaults for metric "TestCoverage"' {
$Result.FunctionHealthRecordMetricsRules.TestCoverage.WarningThreshold | Should Be 80
$Result.FunctionHealthRecordMetricsRules.TestCoverage.FailThreshold | Should Be 70
}
It 'Resulting settings override the defaults for metric "Complexity"' {
$Result.FunctionHealthRecordMetricsRules.Complexity.WarningThreshold | Should Be 17
$Result.FunctionHealthRecordMetricsRules.Complexity.FailThreshold | Should Be 33
}
It 'Resulting settings override the defaults for metric "MaximumNestingDepth"' {
$Result.FunctionHealthRecordMetricsRules.MaximumNestingDepth.WarningThreshold | Should Be 6
$Result.FunctionHealthRecordMetricsRules.MaximumNestingDepth.FailThreshold | Should Be 12
}
It 'Resulting settings are the same as the defaults for metric "TestsPassRate"' {
$Result.OverallHealthReportMetricsRules.TestsPassRate.WarningThreshold | Should Be 99
$Result.OverallHealthReportMetricsRules.TestsPassRate.FailThreshold | Should Be 97
}
It 'Resulting settings are the same as the defaults for metric "CommandsMissedTotal"' {
$Result.OverallHealthReportMetricsRules.CommandsMissedTotal.WarningThreshold | Should Be 20
$Result.OverallHealthReportMetricsRules.CommandsMissedTotal.FailThreshold | Should Be 40
}
It 'Resulting settings override the defaults for metric "LinesOfCodeTotal"' {
$Result.OverallHealthReportMetricsRules.LinesOfCodeTotal.WarningThreshold | Should Be 1500
$Result.OverallHealthReportMetricsRules.LinesOfCodeTotal.FailThreshold | Should Be 3000
}
It 'Resulting settings override the defaults for metric "LinesOfCodeAverage"' {
$Result.OverallHealthReportMetricsRules.LinesOfCodeAverage.WarningThreshold | Should Be 21
$Result.OverallHealthReportMetricsRules.LinesOfCodeAverage.FailThreshold | Should Be 42
}
}
Remove-Variable -Name 'DefaultSettings' -Force -ErrorAction SilentlyContinue
}
}
14 changes: 14 additions & 0 deletions Tests/Unit/TestData/InvalidSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"LinesOfCodeTotal": {
"WarningThreshold": 1500,
"FailThreshold": 3000
}
}
{
"LinesOfCodeAverage": {
"WarningThreshold": 21,
"FailThreshold": 42
}
}
]

0 comments on commit 05ad384

Please sign in to comment.