Skip to content

Commit 2a60e0f

Browse files
authored
[CI Example Analyzer] Support analysis for any PowerShell script (#19191)
* support analyze any powershell script * fix a bug * update * change clean script to not clean
1 parent d5455f6 commit 2a60e0f

File tree

2 files changed

+108
-53
lines changed

2 files changed

+108
-53
lines changed

tools/StaticAnalysis/ExampleAnalyzer/Measure-MarkdownOrScript.ps1

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,19 @@
44
.PARAMETER MarkdownPaths
55
Markdown searching paths. Empty for current path. Supports wildcard.
66
.PARAMETER ScriptPath
7-
PowerShell script searching path.
7+
PowerShell script searching paths. Empty for current path. Supports wildcard.
88
.PARAMETER RulePaths
99
PSScriptAnalyzer custom rules paths. Empty for current path. Supports wildcard.
10-
.PARAMETER CodeMapPath
11-
Code map path bound with the PowerShell script.
1210
.PARAMETER Recurse
13-
To search markdowns recursively in the folders.
11+
To search files recursively in the folders.
1412
.PARAMETER IncludeDefaultRules
1513
To analyze default rules provided by PSScriptAnalyzer.
1614
.PARAMETER OutputFolder
1715
Folder path storing output files.
1816
.PARAMETER SkipAnalyzing
1917
To skip analyzing step. Only extracting example codes from markdowns to the temp script.
20-
.PARAMETER CleanScripts
21-
To clean the temp script.
18+
.PARAMETER NotCleanScripts
19+
Do not clean the temp script.
2220
.NOTES
2321
File Name: Measure-MarkdownOrScript.ps1
2422
#>
@@ -32,17 +30,14 @@ param (
3230
[string[]]$MarkdownPaths,
3331
[Parameter(Mandatory, ParameterSetName = "Script")]
3432
[AllowEmptyString()]
35-
[string[]]$ScriptPath,
33+
[string[]]$ScriptPaths,
3634
[string[]]$RulePaths,
37-
[Parameter(Mandatory, ParameterSetName = "Script")]
38-
[string]$CodeMapPath,
39-
[Parameter(ParameterSetName = "Markdown")]
4035
[switch]$Recurse,
4136
[switch]$IncludeDefaultRules,
4237
[string]$OutputFolder = "$PSScriptRoot\..\..\..\artifacts\StaticAnalysisResults\ExampleAnalysis",
4338
[Parameter(ParameterSetName = "Markdown")]
4439
[switch]$SkipAnalyzing,
45-
[switch]$CleanScripts
40+
[switch]$NotCleanScripts
4641
)
4742

4843
. $PSScriptRoot\utils.ps1
@@ -51,17 +46,24 @@ $analysisResultsTable = @()
5146
$codeMap = @()
5247
$totalLine = 1
5348

49+
$tempScript = "TempScript.ps1"
50+
$tempScriptMap = "TempScript.Map.csv"
51+
$TempScriptPath = "$OutputFolder\$tempScript"
52+
$TempScriptMapPath = "$OutputFolder\$tempScriptMap"
53+
54+
# Clean caches, remove files in "output" folder
55+
Remove-Item $TempScriptPath -ErrorAction SilentlyContinue
56+
Remove-Item $TempScriptMapPath -ErrorAction SilentlyContinue
57+
Remove-Item $PSScriptRoot\..\..\..\artifacts\StaticAnalysisResults\ExampleIssues.csv -ErrorAction SilentlyContinue
58+
Remove-Item $OutputFolder -ErrorAction SilentlyContinue
59+
# Create output folder and temp script
60+
$null = New-Item -ItemType Directory -Path $OutputFolder -ErrorAction SilentlyContinue
61+
$null = New-Item -ItemType File $TempScriptPath
62+
5463
# Find examples in "help\*.md", output ".ps1"
5564
if ($PSCmdlet.ParameterSetName -eq "Markdown") {
56-
# Clean caches, remove files in "output" folder
57-
Remove-Item $OutputFolder\TempScript.ps1 -ErrorAction SilentlyContinue
58-
Remove-Item $OutputFolder\TempCodeMap.csv -ErrorAction SilentlyContinue
59-
Remove-Item $PSScriptRoot\..\..\..\artifacts\StaticAnalysisResults\ExampleIssues.csv -ErrorAction SilentlyContinue
60-
Remove-Item $OutputFolder -ErrorAction SilentlyContinue
61-
$null = New-Item -ItemType Directory -Path $OutputFolder -ErrorAction SilentlyContinue
62-
$null = New-Item -ItemType File $OutputFolder\TempScript.ps1
63-
# When the input $MarkdownPaths is the path of txt file
64-
if ($MarkdownPaths -cmatch ".*\.txt") {
65+
# When the input $MarkdownPaths is the path of txt file contained markdown paths
66+
if ((Test-Path $MarkdownPaths -PathType Leaf) -and $MarkdownPaths.EndsWith(".txt")) {
6567
$MarkdownPath = Get-Content $MarkdownPaths
6668
}
6769
# When the input $MarkdownPaths is the path of a folder
@@ -83,27 +85,29 @@ if ($PSCmdlet.ParameterSetName -eq "Markdown") {
8385
}
8486
$cmdlet = $_.BaseName
8587
$result = Measure-SectionMissingAndOutputScript $module $cmdlet $_.FullName `
86-
-OutputFolder $OutputFolder `
88+
-TempScriptPath $TempScriptPath `
8789
-TotalLine $totalLine
8890
$analysisResultsTable += $result.Errors
8991
$codeMap += $result.CodeMap
9092
$totalLine = $result.TotalLine
9193
}
9294
}
93-
$codeMap| Export-Csv "$OutputFolder\TempCodeMap.csv" -NoTypeInformation
94-
if (!$SkipAnalyzing.IsPresent) {
95-
$ScriptPath = "$OutputFolder\TempScript.ps1"
96-
$CodeMapPath = "$OutputFolder\TempCodeMap.csv"
95+
if(!$NotCleanScripts.IsPresent){
96+
$codeMap| Export-Csv $TempScriptMapPath -NoTypeInformation
9797
}
9898
}
9999

100100
# Analyze scripts
101101
if ($PSCmdlet.ParameterSetName -eq "Script" -or !$SkipAnalyzing.IsPresent) {
102-
# Read code map from file
103-
$codeMap = Import-Csv $CodeMapPath
102+
if ($PSCmdlet.ParameterSetName -eq "Script"){
103+
$codeMap = Merge-Scripts -ScriptPaths $ScriptPaths -Recurse:$Recurse.IsPresent -TempScriptPath $TempScriptPath
104+
if(!$NotCleanScripts.IsPresent){
105+
$codeMap| Export-Csv $TempScriptMapPath -NoTypeInformation
106+
}
107+
}
104108
# Read and analyze ".ps1" in \ScriptsByExample
105109
Write-Output "Analyzing file ..."
106-
$analysisResultsTable += Get-ScriptAnalyzerResult (Get-Item -Path $ScriptPath) $RulePaths -IncludeDefaultRules:$IncludeDefaultRules.IsPresent $codeMap -ErrorAction Continue
110+
$analysisResultsTable += Get-ScriptAnalyzerResult -ScriptPath $TempScriptPath -RulePaths $RulePaths -IncludeDefaultRules:$IncludeDefaultRules.IsPresent -CodeMap $codeMap -ErrorAction Continue
107111

108112
# Summarize analysis results, output in Result.csv
109113
if($analysisResultsTable){
@@ -112,6 +116,7 @@ if ($PSCmdlet.ParameterSetName -eq "Script" -or !$SkipAnalyzing.IsPresent) {
112116
}
113117

114118
# Clean caches
115-
if ($CleanScripts.IsPresent) {
116-
Remove-Item $ScriptPath -Exclude *.csv -Recurse -ErrorAction Continue
119+
if (!$NotCleanScripts.IsPresent) {
120+
Remove-Item $TempScriptPath -ErrorAction Continue
121+
Remove-Item $OutputFolder -ErrorAction SilentlyContinue
117122
}

tools/StaticAnalysis/ExampleAnalyzer/utils.ps1

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
Get-NonExceptionRecord
1212
Get-RecordsNotInAllowList
1313
Measure-SectionMissingAndOutputScript
14+
Merge-Contents
15+
Merge-Scripts
1416
Get-ScriptAnalyzerResult
1517
Set-AnalysisOutput
1618
Set-ExampleProperties
@@ -234,7 +236,7 @@ function Measure-SectionMissingAndOutputScript {
234236
[string]$Module,
235237
[string]$Cmdlet,
236238
[string]$MarkdownPath,
237-
[string]$OutputFolder,
239+
[string]$TempScriptPath,
238240
[int]$TotalLine
239241
)
240242
$missingSeverity = 1
@@ -357,27 +359,11 @@ function Measure-SectionMissingAndOutputScript {
357359
}
358360
}
359361

360-
361362
# Output example codes to "TempScript.ps1"
362363
if ($missingExampleCode -eq 0) {
363-
$cmdletExamplesScriptPath = "$OutputFolder\TempScript.ps1"
364-
$line = $exampleCodes.Count
365364
if($line -ne 0){
366-
$functionHead = "function $Module-$Cmdlet-$exampleNumber{"
367-
Add-Content -Path (Get-Item $cmdletExamplesScriptPath).FullName -Value $functionHead
368-
Add-Content -Path (Get-Item $cmdletExamplesScriptPath).FullName -Value $exampleCodes
369-
$functionTail = "}"
370-
Add-Content -Path (Get-Item $cmdletExamplesScriptPath).FullName -Value $functionTail
371-
for($i = 0; $i -le $line + 1; $i++){
372-
$codeMap += @{
373-
TotalLine = $TotalLine + $i
374-
Module = $Module
375-
Cmdlet = $Cmdlet
376-
Example = $exampleNumber
377-
Line = $i
378-
}
379-
}
380-
$TotalLine = $TotalLine + $line + 2
365+
($tempCodeMap, $TotalLine) = Merge-Contents -Content $exampleCodes -Module $Module -Cmdlet $Cmdlet -Example $exampleNumber -TotalLine $TotalLine -TempScriptPath $TempScriptPath
366+
$codeMap += $tempCodeMap
381367
}
382368
}
383369
}
@@ -394,6 +380,68 @@ function Measure-SectionMissingAndOutputScript {
394380
}
395381
}
396382

383+
<#
384+
.SYNOPSIS
385+
Merge the example codes or scripts into one PowerShell script and generate the code map.
386+
#>
387+
function Merge-Contents {
388+
param(
389+
[string[]]$Contents,
390+
[string]$Module,
391+
[string]$Cmdlet,
392+
[int]$Example,
393+
[int]$TotalLine,
394+
[string]$TempScriptPath
395+
)
396+
$codeMap =@()
397+
$line = $Contents.Count
398+
$functionHead = "function $Module"
399+
if($null -ne $Cmdlet){
400+
$functionHead += "-$Cmdlet"
401+
}
402+
if($null -ne $exampleNumber){
403+
$functionHead += "-$exampleNumber"
404+
}
405+
$functionHead += "{"
406+
Add-Content -Path (Get-Item $TempScriptPath).FullName -Value $functionHead
407+
Add-Content -Path (Get-Item $TempScriptPath).FullName -Value $Contents
408+
Add-Content -Path (Get-Item $TempScriptPath).FullName -Value "}"
409+
for($i = 0; $i -le $line + 1; $i++){
410+
$codeMap += @{
411+
TotalLine = $TotalLine + $i
412+
Module = $Module
413+
Cmdlet = $Cmdlet
414+
Example = $Example
415+
Line = $i
416+
}
417+
}
418+
$TotalLine = $TotalLine + $line + 2
419+
return ($codeMap, $TotalLine)
420+
}
421+
422+
<#
423+
.SYNOPSIS
424+
Merge PowerShell scripts into one and generate the code map.
425+
#>
426+
function Merge-Scripts {
427+
param(
428+
[string]$ScriptPaths,
429+
[switch]$Recurse,
430+
[string]$TempScriptPath
431+
)
432+
$TotalLine = 1
433+
$codeMap = @()
434+
foreach($_ in Get-ChildItem $ScriptPaths -Recurse:$Recurse.IsPresent){
435+
if((Test-Path $_ -PathType Leaf) -and $_.FullName.EndsWith(".ps1")){
436+
$fileName = (Get-Item -Path $_.FullName).Name
437+
$scriptContent = Get-Content $_
438+
($tempCodeMap, $TotalLine) = Merge-Contents -Content $scriptContent -Module $fileName -TotalLine $TotalLine -TempScriptPath $TempScriptPath
439+
$codeMap += $tempCodeMap
440+
}
441+
}
442+
return $codeMap
443+
}
444+
397445
<#
398446
.SYNOPSIS
399447
Set properties for an AnalysisOutput object.
@@ -429,12 +477,14 @@ function Set-AnalysisOutput {
429477
<#
430478
.SYNOPSIS
431479
Invoke PSScriptAnalyzer with custom rules, return the error set.
480+
.PARAMETER RulePath
481+
PSScriptAnalyzer custom rules path. Supports wildcard.
432482
#>
433483
function Get-ScriptAnalyzerResult {
434484
param (
435485
[string]$ScriptPath,
436-
[Parameter(Mandatory, HelpMessage = "PSScriptAnalyzer custom rules path. Supports wildcard.")]
437-
[string[]]$RulePath,
486+
[Parameter(Mandatory)]
487+
[string[]]$RulePaths,
438488
[switch]$IncludeDefaultRules,
439489
[Object[]]$CodeMap
440490
)
@@ -444,11 +494,11 @@ function Get-ScriptAnalyzerResult {
444494
}
445495

446496
# Invoke PSScriptAnalyzer : input scriptblock, output error set in $result with property: RuleName, Message, Extent
447-
if ($null -eq $RulePath) {
497+
if ($null -eq $RulePaths) {
448498
$analysisResults = Invoke-ScriptAnalyzer -Path $ScriptPath -IncludeDefaultRules:$IncludeDefaultRules.IsPresent
449499
}
450500
else {
451-
$analysisResults = Invoke-ScriptAnalyzer -Path $ScriptPath -CustomRulePath $RulePath -IncludeDefaultRules:$IncludeDefaultRules.IsPresent
501+
$analysisResults = Invoke-ScriptAnalyzer -Path $ScriptPath -CustomRulePath $RulePaths -IncludeDefaultRules:$IncludeDefaultRules.IsPresent
452502
}
453503
$errors = @()
454504
foreach($analysisResult in $analysisResults){

0 commit comments

Comments
 (0)