aspnetcore/eng/scripts/CodeCheck.ps1

202 lines
6.8 KiB
PowerShell

#requires -version 5
<#
.SYNOPSIS
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.
#>
param(
[switch]$ci
)
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 1
Import-Module -Scope Local -Force "$PSScriptRoot/common.psm1"
$repoRoot = Resolve-Path "$PSScriptRoot/../.."
[string[]] $errors = @()
function LogError {
param(
[Parameter(Mandatory = $true, Position = 0)]
[string]$message,
[string]$FilePath,
[string]$Code
)
if ($env:TF_BUILD) {
$prefix = "##vso[task.logissue type=error"
if ($FilePath) {
$prefix = "${prefix};sourcepath=$FilePath"
}
if ($Code) {
$prefix = "${prefix};code=$Code"
}
Write-Host "${prefix}]${message}"
}
$fullMessage = "error ${Code}: $message"
if ($FilePath) {
$fullMessage += " [$FilePath]"
}
Write-Host -f Red $fullMessage
$script:errors += $fullMessage
}
try {
if ($ci) {
# Install dotnet.exe
& $repoRoot/restore.cmd -ci -NoBuildNodeJS
}
. "$repoRoot/activate.ps1"
#
# Duplicate .csproj files can cause issues with a shared build output folder
#
$projectFileNames = New-Object 'System.Collections.Generic.HashSet[string]'
# Ignore duplicates in submodules. These should be isolated from the rest of the build.
# Ignore duplicates in the .ref folder. This is expected.
Get-ChildItem -Recurse "$repoRoot/src/*.*proj" `
| ? { $_.FullName -notmatch 'submodules' -and $_.FullName -notmatch 'node_modules' } `
| ? { (Split-Path -Leaf (Split-Path -Parent $_)) -ne 'ref' } `
| % {
$fileName = [io.path]::GetFileNameWithoutExtension($_)
if (-not ($projectFileNames.Add($fileName))) {
LogError -code 'BUILD003' -filepath $_ `
"Multiple project files named '$fileName' exist. Project files should have a unique name to avoid conflicts in build output."
}
}
#
# Versions.props and Version.Details.xml
#
Write-Host "Checking that Versions.props and Version.Details.xml match"
[xml] $versionProps = Get-Content "$repoRoot/eng/Versions.props"
[xml] $versionDetails = Get-Content "$repoRoot/eng/Version.Details.xml"
$globalJson = Get-Content $repoRoot/global.json | ConvertFrom-Json
$versionVars = New-Object 'System.Collections.Generic.HashSet[string]'
foreach ($vars in $versionProps.SelectNodes("//PropertyGroup[`@Label=`"Automated`"]/*")) {
$versionVars.Add($vars.Name) | Out-Null
}
foreach ($dep in $versionDetails.SelectNodes('//Dependency')) {
Write-Verbose "Found $dep"
$expectedVersion = $dep.Version
if ($dep.Name -in $globalJson.'msbuild-sdks'.PSObject.Properties.Name) {
$actualVersion = $globalJson.'msbuild-sdks'.($dep.Name)
if ($expectedVersion -ne $actualVersion) {
LogError `
"MSBuild SDK version '$($dep.Name)' in global.json does not match the value in Version.Details.xml. Expected '$expectedVersion', actual '$actualVersion'" `
-filepath "$repoRoot\global.json"
}
}
else {
$varName = $dep.Name -replace '\.',''
$varName = $varName -replace '\-',''
$varName = "${varName}PackageVersion"
$versionVar = $versionProps.SelectSingleNode("//PropertyGroup[`@Label=`"Automated`"]/$varName")
$actualVersion = $versionVar.InnerText
$versionVars.Remove($varName) | Out-Null
if (-not $versionVar) {
LogError "Missing version variable '$varName' in the 'Automated' property group in $repoRoot/eng/Versions.props"
continue
}
if ($expectedVersion -ne $actualVersion) {
LogError `
"Version variable '$varName' does not match the value in Version.Details.xml. Expected '$expectedVersion', actual '$actualVersion'" `
-filepath "$repoRoot\eng\Versions.props"
}
}
}
foreach ($unexpectedVar in $versionVars) {
LogError `
"Version variable '$unexpectedVar' does not have a matching entry in Version.Details.xml. See https://github.com/dotnet/aspnetcore/blob/master/docs/ReferenceResolution.md for instructions on how to add a new dependency." `
-filepath "$repoRoot\eng\Versions.props"
}
Write-Host "Checking that solutions are up to date"
Get-ChildItem "$repoRoot/*.sln" -Recurse `
| ? {
# These .sln files are used by the templating engine.
($_.Name -ne "BlazorServerWeb_CSharp.sln") -and
($_.Name -ne "BlazorWasm-CSharp.sln")
} `
| % {
Write-Host " Checking $(Split-Path -Leaf $_)"
$slnDir = Split-Path -Parent $_
$sln = $_
& dotnet sln $_ list `
| ? { $_ -like '*proj' } `
| % {
$proj = Join-Path $slnDir $_
if (-not (Test-Path $proj)) {
LogError "Missing project. Solution references a project which does not exist: $proj. [$sln] "
}
}
}
#
# Generated code check
#
Write-Host "Re-running code generation"
Write-Host "Re-generating project lists"
Invoke-Block {
& $PSScriptRoot\GenerateProjectList.ps1 -ci:$ci
}
Write-Host "Re-generating references assemblies"
Invoke-Block {
& $PSScriptRoot\GenerateReferenceAssemblies.ps1 -ci:$ci
}
Write-Host "Re-generating package baselines"
Invoke-Block {
& dotnet run -p "$repoRoot/eng/tools/BaselineGenerator/"
}
Write-Host "Run git diff to check for pending changes"
# Redirect stderr to stdout because PowerShell does not consistently handle output to stderr
$changedFiles = & cmd /c 'git --no-pager diff --ignore-space-change --name-only 2>nul'
# Temporary: Disable check for blazor js file
$changedFilesExclusion = "src/Components/Web.JS/dist/Release/blazor.server.js"
if ($changedFiles) {
foreach ($file in $changedFiles) {
if ($file -eq $changedFilesExclusion) {continue}
$filePath = Resolve-Path "${repoRoot}/${file}"
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
& git --no-pager diff --ignore-space-change $filePath
}
}
}
finally {
Write-Host ""
Write-Host "Summary:"
Write-Host ""
Write-Host " $($errors.Length) error(s)"
Write-Host ""
foreach ($err in $errors) {
Write-Host -f Red $err
}
if ($errors) {
exit 1
}
}