eng/scripts/CodeChecks.ps1 (185 lines of code) (raw):

#requires -version 5 [CmdletBinding()] param ( [Parameter(Position=0)] [string] $ServiceDirectory, [Parameter()] [string] $ProjectDirectory, [Parameter()] [string] $SDKType = "all", [Parameter()] [switch] $SpellCheckPublicApiSurface ) Write-Host "Service Directory $ServiceDirectory" Write-Host "Project Directory $ProjectDirectory" Write-Host "SDK Type $SDKType" $ErrorActionPreference = 'Stop' $Env:NODE_OPTIONS = "--max-old-space-size=8192" Set-StrictMode -Version 1 . (Join-Path $PSScriptRoot\..\common\scripts common.ps1) [string[]] $errors = @() # All errors should be logged using this function, as it tracks the errors in # the $errors array, which is used in the finally block of the script to determine # the return code. function LogError([string]$message) { if ($env:TF_BUILD) { Write-Host ("##vso[task.logissue type=error]$message" -replace "`n","%0D%0A") } Write-Host -f Red "error: $message" $script:errors += $message } function Invoke-Block([scriptblock]$cmd) { $cmd | Out-String | Write-Verbose & $cmd # Need to check both of these cases for errors as they represent different items # - $?: did the powershell script block throw an error # - $lastexitcode: did a windows command executed by the script block end in error if ((-not $?) -or ($lastexitcode -ne 0)) { if ($error -ne $null) { LogError $error[0] } throw "Command failed to execute: $cmd" } } try { Write-Host "Restore ./node_modules" Invoke-Block { & npm ci --prefix $RepoRoot } if ($ProjectDirectory -and -not $ServiceDirectory) { if ($ProjectDirectory -match "sdk[\\/](?<projectdir>.*)[\\/]src") { $ServiceDirectory = $Matches['projectdir'] } } if (-not $ProjectDirectory) { Write-Host "Force .NET Welcome experience" Invoke-Block { & dotnet msbuild -version } Write-Host "`nChecking that solutions are up to date" Join-Path "$PSScriptRoot/../../sdk" $ServiceDirectory ` | Resolve-Path ` | % { Get-ChildItem $_ -Filter "Azure.*.sln" -Recurse } ` | % { Write-Host "Checking $(Split-Path -Leaf $_)" $slnDir = Split-Path -Parent $_ $sln = $_ & dotnet sln $_ list ` | ? { $_ -ne 'Project(s)' -and $_ -ne '----------' } ` | % { $proj = Join-Path $slnDir $_ if (-not (Test-Path $proj)) { LogError "Missing project. Solution references a project which does not exist: $proj. [$sln] " } } } $debugLogging = $env:SYSTEM_DEBUG -eq "true" $logsFolder = $env:BUILD_ARTIFACTSTAGINGDIRECTORY $diagnosticArguments = ($debugLogging -and $logsFolder) ? "/binarylogger:$logsFolder/generatecode.binlog" : "" Write-Host "Re-generating clients" Invoke-Block { & dotnet msbuild $PSScriptRoot\..\service.proj /restore /t:GenerateCode /p:SDKType=$SDKType /p:ServiceDirectory=$ServiceDirectory $diagnosticArguments /p:ProjectListOverrideFile="" } } Write-Host "Re-generating snippets" Invoke-Block { & $PSScriptRoot\Update-Snippets.ps1 -ServiceDirectory $ServiceDirectory } Write-Host "Re-generating listings" Invoke-Block { & $PSScriptRoot\Export-API.ps1 -ServiceDirectory $ServiceDirectory -SDKType $SDKType -SpellCheckPublicApiSurface:$SpellCheckPublicApiSurface } Write-Host "Validating installation instructions" Join-Path "$PSScriptRoot/../../sdk" $ServiceDirectory ` | Resolve-Path ` | % { Get-ChildItem $_ -Filter "README.md" -Recurse } ` | % { $readmePath = $_ $readmeContent = Get-Content $readmePath if ($readmeContent -Match "Install-Package") { LogError "README files should use dotnet CLI for installation instructions. '$readmePath'" } if ($readmeContent -Match "dotnet add .*--version") { LogError "Specific versions should not be specified in the installation instructions in '$readmePath'. For beta versions, include the --prerelease flag." } if ($readmeContent -Match "dotnet add") { $changelogPath = Join-Path $(Split-Path -Parent $readmePath) "CHANGELOG.md" $hasGa = $false $hasRelease = $false if (Test-Path $changelogPath) { $changeLogEntries = Get-ChangeLogEntries -ChangeLogLocation $changelogPath foreach ($key in $changeLogEntries.Keys) { $entry = $changeLogEntries[$key] if ($entry.ReleaseStatus -ne "(Unreleased)") { $hasRelease = $true if ($entry.ReleaseVersion -notmatch "beta" -and $entry.ReleaseVersion -notmatch "preview") { $hasGa = $true break } } } } if ($hasGa) { if (-Not ($readmeContent -Match "dotnet add (?!.*--prerelease)")) { LogError ` "No GA installation instructions found in '$readmePath' but there was a GA entry in the Changelog '$changelogPath'. ` Ensure that there are installation instructions that do not contain the --prerelease flag. You may also include ` instructions for installing a beta that does include the --prerelease flag." } } elseif ($hasRelease) { if (-Not ($readmeContent -Match "dotnet add .*--prerelease$")) { LogError ` "No beta installation instructions found in '$readmePath' but there was a beta entry in the Changelog '$changelogPath'. ` Ensure that there are installation instructions that contain the --prerelease flag." } } } } if (-not $ProjectDirectory) { Write-Host "git diff" # prevent warning related to EOL differences which triggers an exception for some reason & git -c core.safecrlf=false diff --ignore-space-at-eol --exit-code if ($LastExitCode -ne 0) { $status = git status -s | Out-String $status = $status -replace "`n","`n " LogError ` "Generated code is not up to date.` You may need to rebase on the latest main, ` run 'eng\scripts\Update-Snippets.ps1 $ServiceDirectory' if you modified sample snippets or other *.md files (https://github.com/Azure/azure-sdk-for-net/blob/main/CONTRIBUTING.md#updating-sample-snippets), ` run 'eng\scripts\Export-API.ps1 $ServiceDirectory' if you changed public APIs (https://github.com/Azure/azure-sdk-for-net/blob/main/CONTRIBUTING.md#public-api-additions). ` run 'dotnet build /t:GenerateCode' to update the generated code and samples.` ` To reproduce this error locally, run 'eng\scripts\CodeChecks.ps1 -ServiceDirectory $ServiceDirectory'." } } } finally { Write-Host "" Write-Host "Summary:" Write-Host "" Write-Host " $($errors.Length) error(s)" Write-Host "" foreach ($err in $errors) { Write-Host -f Red "error : $err" } if ($errors) { exit 1 } }