| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- #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,
- # Optional arguments that enable downloading an internal
- # runtime or runtime from a non-default location
- [Alias('DotNetRuntimeSourceFeed')]
- [string]$RuntimeSourceFeed,
- [Alias('DotNetRuntimeSourceFeedKey')]
- [string]$RuntimeSourceFeedKey
- )
- $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]$LineNumber, # Ignored if -FilePath not specified.
- [string]$Code
- )
- if ($env:TF_BUILD) {
- $prefix = "##vso[task.logissue type=error"
- if ($FilePath) {
- $prefix = "${prefix};sourcepath=$FilePath"
- if ($LineNumber) {
- $prefix = "${prefix};linenumber=$LineNumber"
- }
- }
- if ($Code) {
- $prefix = "${prefix};code=$Code"
- }
- Write-Host "${prefix}]${message}"
- }
- $fullMessage = "error ${Code}: $message"
- if ($FilePath) {
- $fullMessage += " [$FilePath"
- if ($LineNumber) {
- $fullMessage += ":$LineNumber"
- }
- $fullMessage += "]"
- }
- Write-Host -f Red $fullMessage
- $script:errors += $fullMessage
- }
- try {
- if ($ci) {
- # Install dotnet.exe
- if ($RuntimeSourceFeed -or $RuntimeSourceFeedKey) {
- & $repoRoot/restore.cmd -ci -nobl -noBuildNodeJS -RuntimeSourceFeed $RuntimeSourceFeed `
- -RuntimeSourceFeedKey $RuntimeSourceFeedKey
- } else {
- & $repoRoot/restore.cmd -ci -nobl -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" |
- Where-Object {
- $_.FullName -NotLike '*\submodules\*' -and $_.FullName -NotLike '*\node_modules\*' -and
- $_.FullName -NotLike '*\bin\*' -and $_.FullName -NotLike '*\src\ProjectTemplates\*\content\*'
- } |
- Where-Object { (Split-Path -Leaf (Split-Path -Parent $_)) -ne 'ref' } |
- ForEach-Object {
- $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.")
- }
- }
- #
- # Check for unexpected (not from dotnet-public-npm) npm resolutions in lock files.
- #
- $registry = 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/'
- Get-ChildItem src\package-lock.json -Recurse |
- ForEach-Object FullName |
- Where-Object {$_ -NotLike '*\node_modules\*'} |
- ForEach-Object {
- # -List to limit complaints to one per file.
- Select-String '^ resolved ' $_ | Select-String -List -NotMatch $registry
- } |
- ForEach-Object {
- LogError -filePath "${_.Path}" -lineNumber $_.LineNumber `
- "Packages in package-lock.json file resolved from wrong registry. All dependencies must be resolved from $registry"
- }
- #
- # 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 -filepath "$repoRoot\global.json" `
- ("MSBuild SDK version '$($dep.Name)' in global.json does not match the value in " +
- "Version.Details.xml. Expected '$expectedVersion', actual '$actualVersion'")
- }
- }
- else {
- $varName = $dep.Name -replace '\.',''
- $varName = $varName -replace '\-',''
- $varName = "${varName}Version"
- $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 -filepath "$repoRoot\eng\Versions.props" `
- ("Version variable '$varName' does not match the value in Version.Details.xml. " +
- "Expected '$expectedVersion', actual '$actualVersion'")
- }
- }
- }
- foreach ($unexpectedVar in $versionVars) {
- LogError -Filepath "$repoRoot\eng\Versions.props" `
- ("Version variable '$unexpectedVar' does not have a matching entry in Version.Details.xml. " +
- "See https://github.com/dotnet/aspnetcore/blob/main/docs/ReferenceResolution.md for instructions " +
- "on how to add a new dependency.")
- }
- # ComponentsWebAssembly-CSharp.sln is used by the templating engine; MessagePack.sln is irrelevant (in submodule).
- $solution = Get-ChildItem "$repoRoot/AspNetCore.sln"
- $solutionFile = Split-Path -Leaf $solution
- Write-Host "Checking that $solutionFile is up to date"
- # $solutionProjects will store relative paths i.e. the exact solution and solution filter content.
- $solutionProjects = New-Object 'System.Collections.Generic.HashSet[string]'
- # Where-Object needed to ignore heading `dotnet sln` outputs
- & dotnet sln $solution list | Where-Object { $_ -like '*proj' } | ForEach-Object {
- $proj = Join-Path $repoRoot $_
- if (-not ($solutionProjects.Add($_))) {
- LogError "Duplicate project. $solutionFile references a project more than once: $proj."
- }
- if (-not (Test-Path $proj)) {
- LogError "Missing project. $solutionFile references a project which does not exist: $proj."
- }
- }
- Write-Host "Checking solution filters"
- Get-ChildItem -Recurse "$repoRoot\*.slnf" | ForEach-Object {
- $solutionFilter = $_
- $json = Get-Content -Raw -Path $solutionFilter |ConvertFrom-Json
- $json.solution.projects | ForEach-Object {
- if (!$solutionProjects.Contains($_)) {
- LogError "$solutionFilter references a project not in $solutionFile`: $_"
- }
- }
- }
- #
- # 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 package baselines"
- Invoke-Block {
- & dotnet run --project "$repoRoot/eng/tools/BaselineGenerator/"
- }
- Write-Host "Running 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 and nuget.config (updated automatically for
- # internal builds)
- $changedFilesExclusions = @("src/Components/Web.JS/dist/Release/blazor.server.js", "src/Components/Web.JS/dist/Release/blazor.web.js", "NuGet.config")
- if ($changedFiles) {
- foreach ($file in $changedFiles) {
- if ($changedFilesExclusions -contains $file) {continue}
- $filePath = Resolve-Path "${repoRoot}/${file}"
- LogError -filepath $filePath `
- ("Generated code is not up to date in $file. You might need to regenerate the reference " +
- "assemblies or project list (see docs/ReferenceResolution.md)")
- & git --no-pager diff --ignore-space-change $filePath
- }
- }
- $targetBranch = $env:SYSTEM_PULLREQUEST_TARGETBRANCH
- if (![string]::IsNullOrEmpty($targetBranch)) {
- if ($targetBranch.StartsWith('refs/heads/')) {
- $targetBranch = $targetBranch.Replace('refs/heads/','')
- }
- # Retrieve the set of changed files compared to main
- Write-Host "Checking for changes to API baseline files $targetBranch"
- $changedFilesFromTarget = git --no-pager diff origin/$targetBranch --ignore-space-change --name-only --diff-filter=ar
- $changedAPIBaselines = [System.Collections.Generic.List[string]]::new()
- if ($changedFilesFromTarget) {
- foreach ($file in $changedFilesFromTarget) {
- # Check for changes in Shipped in all branches
- if ($file -like '*PublicAPI.Shipped.txt') {
- if (!$file.Contains('DevServer/src/PublicAPI.Shipped.txt')) {
- $changedAPIBaselines.Add($file)
- }
- }
- # Check for changes in Unshipped in servicing branches
- if ($targetBranch -like 'release*' -and $targetBranch -notlike '*preview*' -and $targetBranch -notlike '*rc1*' -and $targetBranch -notlike '*rc2*' -and $file -like '*PublicAPI.Unshipped.txt') {
- $changedAPIBaselines.Add($file)
- }
- }
- }
- Write-Host "Found changes in $($changedAPIBaselines.count) API baseline files"
- if ($changedAPIBaselines.count -gt 0) {
- LogError ("Detected modification to baseline API files. PublicAPI.Shipped.txt files should only " +
- "be updated after a major release, and PublicAPI.Unshipped.txt files should not " +
- "be updated in release branches. See /docs/APIBaselines.md for more information.")
- LogError "Modified API baseline files:"
- foreach ($file in $changedAPIBaselines) {
- LogError $file
- }
- }
- }
- }
- 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
- }
- }
|