使 PSScriptAnalyzer 成为 PowerShell CI 管道中的一等公民
如您所知,如果您已阅读这个或这个,我是PSScriptAnalyzer保持一定编码标准的忠实粉丝。这在发布管道中尤其强大,因为这使我们能够强制执行该编码标准。
在我们的 CI 管道中,如果我们的代码违反PSScriptAnalyzer条规则,我们很容易使构建失败。
这很好,但是持续集成的主要目的是向开发人员提供有关其代码更改的快速反馈。这是关于及早发现问题及早解决问题。所以问题是:
我们如何让我们的 CI 工具发布
PSScriptAnalyzer结果以及我们需要纠正任何违规行为的信息?
所有 CI 工具都可以发布测试结果以使其高度可见,深入研究测试失败并进行一些报告。
由于我们谈论的是 PowerShell 管道,我们很可能已经在使用 Pester 来测试我们的 PowerShell 代码。
Pester 可以输出与 NUnit 相同的XML格式的结果,并且这些 NUnitXML文件可以被大多数 CI 工具使用和发布。
将这种 Pester 集成用作通用 CI 粘合剂并将我们的PSScriptAnalyzer检查作为 Pester 测试运行是很有意义的。
让我们看看可能的方法来做到这一点。
一个 Pester 测试检查 PSScriptAnalyzer 输出
这可能是从 Pester 调用PSScriptAnalyzer的最简单方法:
Describe 'PSScriptAnalyzer analysis' {
$ScriptAnalyzerResults = Invoke-ScriptAnalyzer -Path '.\Example.ps1' -Severity Warning
It 'Should not return any violation' {
$ScriptAnalyzerResults | Should BeNullOrEmpty
}
}
进入全屏模式 退出全屏模式
在这里,我们在一个测试中检查所有具有警告严重性的规则。
然后,我们依赖于这样一个事实,如果PSScriptAnalyzer返回一些东西,这意味着它们至少有一次违规,如果PSScriptAnalyzer什么也没返回,那一切都很好。
这里有两个问题:
-
我们在一个测试中评估一大堆规则,所以测试名称无法告诉我们违反了哪条规则
-
如果有不止一个违规,Pester 消息会给我们无用的信息
怎么没用?好吧,走着瞧 :
Invoke-Pester -Script '.\Example.Tests.ps1'
Executing all tests in .\Example.Tests.ps1
Executing script .\Example.Tests.ps1
Describing PSScriptAnalyzer analysis
[-] Should not return any violation 1.52s
Expected: value to be empty but it was {Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord}
at <ScriptBlock>, E:\Example.Tests.ps1: line 5
5: $ScriptAnalyzerResults | Should BeNullOrEmpty
Tests completed in 1.52s
Tests Passed: 0, Failed: 1, Skipped: 0, Pending: 0, Inconclusive: 0
进入全屏模式 退出全屏模式
Pester 失败消息为我们提供了PSScriptAnalyzer结果的对象类型,而不是它们的内容。
每个 PSScriptAnalyzer 规则进行一次 Pester 测试
这是通过 Pester 运行PSScriptAnalyzer检查的一种非常典型(并且更好)的方式。
Describe 'PSScriptAnalyzer analysis' {
$ScriptAnalyzerRules = Get-ScriptAnalyzerRule -Name "PSAvoid*"
Foreach ( $Rule in $ScriptAnalyzerRules ) {
It "Should not return any violation for the rule : $($Rule.RuleName)" {
Invoke-ScriptAnalyzer -Path ".\Example.ps1" -IncludeRule $Rule.RuleName |
Should BeNullOrEmpty
}
}
}
进入全屏模式 退出全屏模式
在这种情况下,第一步是获取我们想要评估的规则列表。在这里,我将规则列表更改为:名称以PSAvoid开头的所有规则。这只是为了表明我们可以按名称和严重性过滤规则。
然后,我们遍历这个规则列表,并让 Pester 测试一个一个地评估每个规则。正如我们在下面看到的,输出更有用:
[
](https://res.cloudinary.com/practicaldev/image/fetch/s--QbgxCnvG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mathieubuisson.github .io/images/2016-11-30-psscriptanalyzer-first-class-citizen-by-rule.png)
这肯定更好,但我们仍然遇到与以前相同的问题,因为该PSAvoidUsingWMICmdlet规则的违规行为不止一次。所以我们仍然没有得到文件名和行号。
我们可以使用嵌套循环:对于每个规则,我们将遍历每个文件。
这将更加细化并降低此特定问题的风险。但是,如果一个文件多次违反同一规则,我们仍然会遇到同样的问题。
所以,我决定采取不同的方法来解决这个问题:从PSScriptAnalyzer获取输出并将其转换为测试结果文件,使用与 Pester 和 NUnit 相同的XML模式。
将 PSScriptAnalyzer 输出转换为测试结果文件
为此,我编写了一个名为Export-NUnitXml的函数,该函数在](https://github.com/MathieuBuisson/PowerShell-DevOps/tree/master/Export-NUnitXml)这个模块中可用[。
以下是Export-NUnitXml的高级步骤:
-
以
PSScriptAnalyzer的输出为输入 -
为每个输入对象创建一个包含“测试用例”节点的
XML文档 -
将此
XML文档写入通过Path参数指定的文件
这是我们如何在构建脚本中使用它的示例(在本例中为Appveyor):
$ScriptAnalyzerRules = Get-ScriptAnalyzerRule -Severity Warning
$ScriptAnalyzerResult = Invoke-ScriptAnalyzer -Path '.\CustomPSScriptAnalyzerRules\Example.ps1' -IncludeRule $ScriptAnalyzerRules
If ( $ScriptAnalyzerResult ) {
$ScriptAnalyzerResultString = $ScriptAnalyzerResult | Out-String
Write-Warning $ScriptAnalyzerResultString
}
Import-Module '.\Export-NUnitXml\Export-NUnitXml.psm1' -Force
Export-NUnitXml -ScriptAnalyzerResult $ScriptAnalyzerResult -Path '.\ScriptAnalyzerResult.xml'
(New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", '.\ScriptAnalyzerResult.xml')
If ( $ScriptAnalyzerResult ) {
# Failing the build
Throw 'There was PSScriptAnalyzer violation(s). See test results for more information.'
}
进入全屏模式 退出全屏模式
这是 Appveyor 中的结果:
[
](https://res.cloudinary.com/practicaldev/image/fetch/s--76Cp1QcF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mathieubuisson.github。 io/images/2016-11-30-psscriptanalyzer-first-class-citizen-overview.png)
只需读取测试用例的名称,我们就可以获得基本信息:规则名称、文件名甚至行号。
此外,我们可以扩展任何失败的测试以获取更多信息。
例如,最后 2 个测试扩展如下:
[
](https://res.cloudinary.com/practicaldev/image/fetch/s--D7AMnc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://mathieubuisson.github .io/images/2016-11-30-psscriptanalyzer-first-class-citizen-details.png)
“ Stacktrace ” 部分提供了其他详细信息,例如规则严重性和实际的违规代码。另一个不错的地方是“错误消息”部分为我们提供了规则消息,它通常会提供可操作的建议来解决问题。
但是,如果
PSScriptAnalyzer什么都不返回怎么办?
Export-NUnitXml确实可以优雅地处理这种情况,因为它的ScriptAnalyzerResult参数接受$Null。在这种情况下,测试结果文件将仅包含 1 个测试用例,并且该测试将通过。
因此,现在,我们不仅可以快速反馈我们对编码标准的遵守情况,而且还可以获得有关如何改进的可行指导。
请记住,这种 NUnitXML格式在 CI/CD 工具世界中得到广泛支持,因此这在 TeamCity、Microsoft VSTS 和其他工具中也同样适用......
本帖原发于mathieubuisson.github.io
更多推荐

所有评论(0)