CodeCheck.ps1 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #requires -version 5
  2. <#
  3. .SYNOPSIS
  4. This script runs a quick check for common errors, such as checking that Visual Studio solutions are up to date or that generated code has been committed to source.
  5. #>
  6. param(
  7. [switch]$ci,
  8. # Optional arguments that enable downloading an internal
  9. # runtime or runtime from a non-default location
  10. [string]$DotNetRuntimeSourceFeed,
  11. [string]$DotNetRuntimeSourceFeedKey
  12. )
  13. $ErrorActionPreference = 'Stop'
  14. Set-StrictMode -Version 1
  15. Import-Module -Scope Local -Force "$PSScriptRoot/common.psm1"
  16. $repoRoot = Resolve-Path "$PSScriptRoot/../.."
  17. [string[]] $errors = @()
  18. function LogError {
  19. param(
  20. [Parameter(Mandatory = $true, Position = 0)]
  21. [string]$message,
  22. [string]$FilePath,
  23. [string]$Code
  24. )
  25. if ($env:TF_BUILD) {
  26. $prefix = "##vso[task.logissue type=error"
  27. if ($FilePath) {
  28. $prefix = "${prefix};sourcepath=$FilePath"
  29. }
  30. if ($Code) {
  31. $prefix = "${prefix};code=$Code"
  32. }
  33. Write-Host "${prefix}]${message}"
  34. }
  35. $fullMessage = "error ${Code}: $message"
  36. if ($FilePath) {
  37. $fullMessage += " [$FilePath]"
  38. }
  39. Write-Host -f Red $fullMessage
  40. $script:errors += $fullMessage
  41. }
  42. try {
  43. if ($ci) {
  44. # Install dotnet.exe
  45. & $repoRoot/restore.cmd -ci -NoBuildNodeJS -DotNetRuntimeSourceFeed $DotNetRuntimeSourceFeed -DotNetRuntimeSourceFeedKey $DotNetRuntimeSourceFeedKey
  46. }
  47. . "$repoRoot/activate.ps1"
  48. #
  49. # Duplicate .csproj files can cause issues with a shared build output folder
  50. #
  51. $projectFileNames = New-Object 'System.Collections.Generic.HashSet[string]'
  52. # Ignore duplicates in submodules. These should be isolated from the rest of the build.
  53. # Ignore duplicates in the .ref folder. This is expected.
  54. Get-ChildItem -Recurse "$repoRoot/src/*.*proj" `
  55. | ? { $_.FullName -notmatch 'submodules' -and $_.FullName -notmatch 'node_modules' } `
  56. | ? { (Split-Path -Leaf (Split-Path -Parent $_)) -ne 'ref' } `
  57. | % {
  58. $fileName = [io.path]::GetFileNameWithoutExtension($_)
  59. if (-not ($projectFileNames.Add($fileName))) {
  60. LogError -code 'BUILD003' -filepath $_ `
  61. "Multiple project files named '$fileName' exist. Project files should have a unique name to avoid conflicts in build output."
  62. }
  63. }
  64. #
  65. # Versions.props and Version.Details.xml
  66. #
  67. Write-Host "Checking that Versions.props and Version.Details.xml match"
  68. [xml] $versionProps = Get-Content "$repoRoot/eng/Versions.props"
  69. [xml] $versionDetails = Get-Content "$repoRoot/eng/Version.Details.xml"
  70. $globalJson = Get-Content $repoRoot/global.json | ConvertFrom-Json
  71. $versionVars = New-Object 'System.Collections.Generic.HashSet[string]'
  72. foreach ($vars in $versionProps.SelectNodes("//PropertyGroup[`@Label=`"Automated`"]/*")) {
  73. $versionVars.Add($vars.Name) | Out-Null
  74. }
  75. foreach ($dep in $versionDetails.SelectNodes('//Dependency')) {
  76. Write-Verbose "Found $dep"
  77. $expectedVersion = $dep.Version
  78. if ($dep.Name -in $globalJson.'msbuild-sdks'.PSObject.Properties.Name) {
  79. $actualVersion = $globalJson.'msbuild-sdks'.($dep.Name)
  80. if ($expectedVersion -ne $actualVersion) {
  81. LogError `
  82. "MSBuild SDK version '$($dep.Name)' in global.json does not match the value in Version.Details.xml. Expected '$expectedVersion', actual '$actualVersion'" `
  83. -filepath "$repoRoot\global.json"
  84. }
  85. }
  86. else {
  87. $varName = $dep.Name -replace '\.',''
  88. $varName = $varName -replace '\-',''
  89. $varName = "${varName}PackageVersion"
  90. $versionVar = $versionProps.SelectSingleNode("//PropertyGroup[`@Label=`"Automated`"]/$varName")
  91. $actualVersion = $versionVar.InnerText
  92. $versionVars.Remove($varName) | Out-Null
  93. if (-not $versionVar) {
  94. LogError "Missing version variable '$varName' in the 'Automated' property group in $repoRoot/eng/Versions.props"
  95. continue
  96. }
  97. if ($expectedVersion -ne $actualVersion) {
  98. LogError `
  99. "Version variable '$varName' does not match the value in Version.Details.xml. Expected '$expectedVersion', actual '$actualVersion'" `
  100. -filepath "$repoRoot\eng\Versions.props"
  101. }
  102. }
  103. }
  104. foreach ($unexpectedVar in $versionVars) {
  105. LogError `
  106. "Version variable '$unexpectedVar' does not have a matching entry in Version.Details.xml. See https://github.com/aspnet/AspNetCore/blob/master/docs/ReferenceResolution.md for instructions on how to add a new dependency." `
  107. -filepath "$repoRoot\eng\Versions.props"
  108. }
  109. Write-Host "Checking that solutions are up to date"
  110. Get-ChildItem "$repoRoot/*.sln" -Recurse `
  111. | ? {
  112. # These .sln files are used by the templating engine.
  113. ($_.Name -ne "BlazorServerWeb_CSharp.sln")
  114. } `
  115. | % {
  116. Write-Host " Checking $(Split-Path -Leaf $_)"
  117. $slnDir = Split-Path -Parent $_
  118. $sln = $_
  119. & dotnet sln $_ list `
  120. | ? { $_ -like '*proj' } `
  121. | % {
  122. $proj = Join-Path $slnDir $_
  123. if (-not (Test-Path $proj)) {
  124. LogError "Missing project. Solution references a project which does not exist: $proj. [$sln] "
  125. }
  126. }
  127. }
  128. #
  129. # Generated code check
  130. #
  131. Write-Host "Re-running code generation"
  132. Write-Host "Re-generating project lists"
  133. Invoke-Block {
  134. & $PSScriptRoot\GenerateProjectList.ps1 -ci:$ci
  135. }
  136. Write-Host "Re-generating references assemblies"
  137. Invoke-Block {
  138. & $PSScriptRoot\GenerateReferenceAssemblies.ps1 -ci:$ci
  139. }
  140. Write-Host "Re-generating package baselines"
  141. Invoke-Block {
  142. & dotnet run -p "$repoRoot/eng/tools/BaselineGenerator/"
  143. }
  144. Write-Host "Run git diff to check for pending changes"
  145. # Redirect stderr to stdout because PowerShell does not consistently handle output to stderr
  146. $changedFiles = & cmd /c 'git --no-pager diff --ignore-space-at-eol --name-only 2>nul'
  147. # Temporary: Disable check for blazor js file and nuget.config (updated automatically for
  148. # internal builds)
  149. $changedFilesExclusions = @("src/Components/Web.JS/dist/Release/blazor.server.js", "NuGet.config")
  150. if ($changedFiles) {
  151. foreach ($file in $changedFiles) {
  152. if ($changedFilesExclusions -contains $file) {continue}
  153. $filePath = Resolve-Path "${repoRoot}/${file}"
  154. LogError "Generated code is not up to date in $file. You might need to regenerate the reference assemblies or project list (see docs/ReferenceAssemblies.md and docs/ReferenceResolution.md)" -filepath $filePath
  155. & git --no-pager diff --ignore-space-at-eol $filePath
  156. }
  157. }
  158. }
  159. finally {
  160. Write-Host ""
  161. Write-Host "Summary:"
  162. Write-Host ""
  163. Write-Host " $($errors.Length) error(s)"
  164. Write-Host ""
  165. foreach ($err in $errors) {
  166. Write-Host -f Red $err
  167. }
  168. if ($errors) {
  169. exit 1
  170. }
  171. }