/ .pipelines / verifyDepsJsonLibraryVersions.ps1
verifyDepsJsonLibraryVersions.ps1
 1  [CmdletBinding()]
 2  Param(
 3      [Parameter(Mandatory = $True, Position = 1)]
 4      [string]$targetDir
 5  )
 6  
 7  # This script will check every deps.json file in the target directory to see if for each dll mentioned,
 8  #all the deps.json files that mention it will mention the same version.
 9  # The main goal is to catch when different versions for the same module might be copied to the same directory
10  #at build time and might create flaky builds that get the wrong version of the dll sometimes.
11  
12  # A dictionary of dictionaries of lists to save which files reference each version of each dll.
13  # Logic is DllName > fileVersion > list with deps.json files that reference it.
14  # If for a specific dll there's more than one referenced file version, we have build collisions.
15  $referencedFileVersionsPerDll = @{}
16  $totalFailures = 0
17  
18  Get-ChildItem $targetDir -Recurse -Filter *.deps.json -Exclude *UITest*,MouseJump.Common.UnitTests*,*.FuzzTests* | ForEach-Object {
19      # Temporarily exclude All UI-Test, Fuzzer-Test projects because of Appium.WebDriver dependencies
20      $depsJsonFullFileName = $_.FullName
21  
22      if ($depsJsonFullFileName -like "*CmdPal*" -or $depsJsonFullFileName -like "*CommandPalette*") {
23          return
24      }
25  
26      $depsJsonFileName = $_.Name
27      $depsJson = Get-Content $depsJsonFullFileName | ConvertFrom-Json
28  
29      # We're doing a breadth first search to look for every runtime object.
30      $iterateThroughEveryField = New-Object System.Collections.Generic.Queue[System.Object]
31      $iterateThroughEveryField.Enqueue($depsJson)
32  
33      while($iterateThroughEveryField.Count -gt 0)
34      {
35          $currentObject = $iterateThroughEveryField.Dequeue();
36          $currentObject.PSObject.Properties | ForEach-Object {
37              if($_.Name -ne 'SyncRoot') {
38                  # Skip SyncRoot to avoid looping in array objects.
39                  # Care only about objects, not value types.
40                  $iterateThroughEveryField.Enqueue($_.Value)
41                  if($_.Name -eq 'runtime')
42                  {
43                      # Cycle through each dll.
44                      $_.Value.PSObject.Properties | ForEach-Object {
45                          if($_.Name.EndsWith('.dll')) {
46                              $dllName = Split-Path $_.Name -leaf
47                              if([bool]($_.Value.PSObject.Properties.name -match 'fileVersion')) {
48                                  $dllFileVersion = $_.Value.fileVersion
49                                  if (([string]::IsNullOrEmpty($dllFileVersion) -or ($dllFileVersion -eq '0.0.0.0')) -and $dllName.StartsWith('PowerToys.'))` {
50                                      # After VS 17.11 update some of PowerToys dlls have no fileVersion in deps.json even though the 
51                                      # version is correctly set. This is a workaround to skip our dlls as we are confident that all of
52                                      # our dlls share the same version across the dependencies.
53  									# After VS 17.13 these error versions started appearing as 0.0.0.0 so we've added that case to the condition as well.
54                                      continue
55                                  }
56  
57                                  # Add the entry to the dictionary of dictionary of lists
58                                  if(-Not $referencedFileVersionsPerDll.ContainsKey($dllName)) {
59                                      $referencedFileVersionsPerDll[$dllName] = @{ $dllFileVersion = New-Object System.Collections.Generic.List[System.String] }
60                                  } elseif(-Not $referencedFileVersionsPerDll[$dllName].ContainsKey($dllFileVersion)) {
61                                      $referencedFileVersionsPerDll[$dllName][$dllFileVersion] = New-Object System.Collections.Generic.List[System.String]
62                                  }
63                                  $referencedFileVersionsPerDll[$dllName][$dllFileVersion].Add($depsJsonFileName)
64                              }
65                          }
66                      }
67                  }
68              }
69          }
70      }
71  }
72  
73  # Report on the files that are referenced for more than one version.
74  $referencedFileVersionsPerDll.keys | ForEach-Object {
75      if($referencedFileVersionsPerDll[$_].Count -gt 1) {
76          $dllName = $_
77          Write-Host $dllName
78          $referencedFileVersionsPerDll[$dllName].keys | ForEach-Object {
79              Write-Host "`t" $_ 
80              $referencedFileVersionsPerDll[$dllName][$_] | ForEach-Object {
81                  Write-Host "`t`t" $_
82              }
83          }
84          $totalFailures++;
85      }
86  }
87  
88  if ($totalFailures -gt 0) {
89      Write-Host -ForegroundColor Red "Detected " $totalFailures " libraries that are mentioned with different version across the dependencies.`r`n"
90      exit 1
91  }
92  
93  Write-Host -ForegroundColor Green "All " $referencedFileVersionsPerDll.keys.Count " libraries are mentioned with the same version across the dependencies.`r`n"
94  exit 0