Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .azure-pipelines/util/analyze-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ steps:

- pwsh: 'Install-Module "platyPS", "PSScriptAnalyzer" -Force -Confirm:$false -Scope CurrentUser'
displayName: 'Install PowerShell Dependencies'

- task: PowerShell@2
displayName: 'Install latest modules'
inputs:
targetType: 'inline'
script: |
New-Item -ItemType Directory -Path "Az-Cmdlets-latest"
Invoke-WebRequest -Uri "https://azpspackage.blob.core.windows.net/release/Az-Cmdlets-latest.tar.gz" -OutFile "Az-Cmdlets-latest/Az-Cmdlets-latest.tar.gz" -MaximumRetryCount 2 -RetryIntervalSec 1
tar -xvzf "Az-Cmdlets-latest/Az-Cmdlets-latest.tar.gz" -C "Az-Cmdlets-latest"
. Az-Cmdlets-latest/InstallModule.ps1
pwsh: true

- task: DotNetCoreCLI@2
displayName: 'Generate Help'
Expand Down
2 changes: 1 addition & 1 deletion .ci-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
"src/{ModuleName}/**/*.md$"
],
"phases": [
"build:related-module",
"build:module",
"help:module"
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
.NOTES
File: CommandName.psm1
#>
. $PSScriptRoot\..\utils.ps1

enum RuleNames {
Invalid_Cmdlet
Expand Down Expand Up @@ -53,12 +54,15 @@ function Measure-CommandName {
$GetCommand = Get-Command $CommandName -ErrorAction SilentlyContinue
if ($null -eq $GetCommand) {
# CommandName is not valid.
$global:CommandParameterPair += @{
CommandName = $CommandName
ParameterName = "<is not valid>"
ModuleCmdletExNum = $ModuleCmdletExNum
# Redo import-module
if(!(Redo-ImportModule $CommandName)){
$global:CommandParameterPair += @{
CommandName = $CommandName
ParameterName = "<is not valid>"
ModuleCmdletExNum = $ModuleCmdletExNum
}
return $true
}
return $true
}
else {
if ($GetCommand.CommandType -eq "Alias") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
.NOTES
File: ParameterNameAndValue.psm1
#>
. $PSScriptRoot\..\utils.ps1

enum RuleNames {
Unknown_Parameter_Set
Expand Down Expand Up @@ -381,6 +382,12 @@ function Measure-ParameterNameAndValue {
[System.Management.Automation.Language.CommandElementAst]$CommandElementAst = $Ast
[System.Management.Automation.Language.CommandAst]$CommandAst = $CommandElementAst.Parent

# Skip all the statements with -ParameterName <Type>
if($Ast.Parent.Extent.Text -match "-\w+\s*<.*?>"){
Write-Debug "Skip $($Ast.Parent.Extent.Text)"
return $false
}

if ($global:SkipNextCommandElementAst) {
$global:SkipNextCommandElementAst = $false
return $false
Expand All @@ -398,7 +405,10 @@ function Measure-ParameterNameAndValue {

# Skip parameters for invaild cmdlet
if ($null -eq $GetCommand) {
return $false
# Redo import-module
if(!(Redo-ImportModule $CommandName)){
return $false
}
}
# Get command from alias
if ($GetCommand.CommandType -eq "Alias") {
Expand Down
83 changes: 55 additions & 28 deletions tools/StaticAnalysis/ExampleAnalyzer/utils.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
AnalysisOutput
Functions: Get-ExamplesDetailsFromMd
Get-NonExceptionRecord
Get-RecordsNotInAllowList
Measure-SectionMissingAndOutputScript
Measure-NotInWhiteList
Get-ScriptAnalyzerResult
Redo-ImportModule
#>

$SYNOPSIS_HEADING = "## SYNOPSIS"
Expand Down Expand Up @@ -176,6 +177,32 @@ function Get-NonExceptionRecord{
return $results
}

<#
.SYNOPSIS
Get AnalysisOutput entries not in the allow list.
#>
function Get-RecordsNotInAllowList{
param (
[AnalysisOutput[]]$records
)
return $records | Where-Object {
# Skip the unexpected error caused by using <xxx> to assign parameters
if($_.RuleName -eq "RedirectionNotSupported"){
return $false
}
# Skip the invaild cmdlet "<"
$CommandName = ($_.Description -split " ")[0]
if($CommandName -eq "<"){
return $false
}
# Skip NeedDeleting in Storage
if($_.RuleName -eq "NeedDeleting" -and $_.Module -eq "Storage.Management"){
return $false
}
return $true
}
}

<#
.SYNOPSIS
Tests whether the script is integral, outputs examples in ".md" to "TempScript.ps1"
Expand Down Expand Up @@ -370,7 +397,7 @@ function Measure-SectionMissingAndOutputScript {
ProblemID = 5051
Remediation = "Delete the prompt of example."
}
$results += $result
$results += $result
$newCode = $exampleCodes -replace "`n([A-Za-z \t\\:>])*(PS|[A-Za-z]:)(\w|[\\/\[\].\- ])*(>|&gt;)+( PS)*[ \t]*", "`n"
$newCode = $newCode -replace "(?<=[A-Za-z]\w+-[A-Za-z]\w+)\.ps1"
$exampleCodes = $newCode
Expand All @@ -392,7 +419,8 @@ function Measure-SectionMissingAndOutputScript {
}
}
}

# Except records in allow list
$results = Get-RecordsNotInAllowList $results
# Except the suppressed records
$results = Get-NonExceptionRecord $results

Expand All @@ -404,26 +432,6 @@ function Measure-SectionMissingAndOutputScript {
}
}

<#
.SYNOPSIS
Measure whether the AnalysisOutput entry is in white list.
#>
function Measure-InAllowList{
param (
[AnalysisOutput]$result
)
# Skip the unexpected error caused by using <xxx> to assign parameters
if($result.RuleName -eq "RedirectionNotSupported"){
return $false
}
# Skip the invaild cmdlet "<"
$CommandName = ($result.Description -split " ")[0]
if($CommandName -eq "<"){
return $false
}
return $true
}

<#
.SYNOPSIS
Invoke PSScriptAnalyzer with custom rules, return the error set.
Expand Down Expand Up @@ -486,15 +494,34 @@ function Get-ScriptAnalyzerResult {
Extent = $analysisResult.Extent.ToString().Trim() -replace "`"","`'" -replace "`n"," " -replace "`r"," "
ProblemID = 5200
Remediation = "Unexpected Error! Please check your example or contact the Azure Powershell Team. (Appeared in Line $($analysisResult.Line))"
}
}
# Measure whether the result is in the white list
if(Measure-InAllowList $result){
$results += $result
}
$results += $result
}
#Except the suppressed records
# Except records in allow list
$results = Get-RecordsNotInAllowList $results
# Except the suppressed records
$results = Get-NonExceptionRecord $results

return $results
}

<#
.SYNOPSIS
Retry import-module
#>
function Redo-ImportModule {
param (
[string]$CommandName
)
$modulePath = "$PSScriptRoot\..\..\..\..\artifacts\Debug\Az.*\Az.*.psd1"
Get-Item $modulePath | Import-Module -Global
$GetCommand = Get-Command $CommandName -ErrorAction SilentlyContinue
if ($null -eq $GetCommand) {
return $false
}
else{
Write-Debug "Succeed by retrying import-module"
return $true
}
}
7 changes: 6 additions & 1 deletion tools/StaticAnalysis/IssueChecker/IssueChecker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ private bool IsSingleExceptionFileHasCriticalIssue(string exceptionFilePath, str
}
var errorText = new StringBuilder();
errorText.AppendLine(recordList.First().PrintHeaders());
var warningText = new StringBuilder();
foreach (IReportRecord record in recordList)
{
if (record.Severity < 2)
Expand All @@ -117,13 +118,17 @@ private bool IsSingleExceptionFileHasCriticalIssue(string exceptionFilePath, str
}
else if (record.Severity == 2 && outputWarning)
{
errorText.AppendLine(record.FormatRecord());
warningText.AppendLine(record.FormatRecord());
}
}
if (hasError)
{
Console.WriteLine("{0} Errors", exceptionFilePath);
Console.WriteLine(errorText.ToString());
if(outputWarning && !String.IsNullOrEmpty(warningText.ToString())){
Console.WriteLine("Following are warning issues. It is recommended to correct them as well.");
Console.WriteLine(warningText.ToString());
}
}
}
return hasError;
Expand Down