/ .pipelines / UpdateVersions.ps1
UpdateVersions.ps1
1 Param( 2 # Using the default value of 1.7 for winAppSdkVersionNumber and useExperimentalVersion as false 3 [Parameter(Mandatory=$False,Position=1)] 4 [string]$winAppSdkVersionNumber = "1.8", 5 6 # When the pipeline calls the PS1 file, the passed parameters are converted to string type 7 [Parameter(Mandatory=$False,Position=2)] 8 [boolean]$useExperimentalVersion = $False, 9 10 # Root folder Path for processing 11 [Parameter(Mandatory=$False,Position=3)] 12 [string]$rootPath = $(Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)), 13 14 # Root folder Path for processing 15 [Parameter(Mandatory=$False,Position=4)] 16 [string]$sourceLink = "https://microsoft.pkgs.visualstudio.com/ProjectReunion/_packaging/Project.Reunion.nuget.internal/nuget/v3/index.json" 17 ) 18 19 20 21 function Read-FileWithEncoding { 22 param ( 23 [string]$Path 24 ) 25 26 $reader = New-Object System.IO.StreamReader($Path, $true) # auto-detect encoding 27 $content = $reader.ReadToEnd() 28 $encoding = $reader.CurrentEncoding 29 $reader.Close() 30 31 return [PSCustomObject]@{ 32 Content = $content 33 Encoding = $encoding 34 } 35 } 36 37 function Write-FileWithEncoding { 38 param ( 39 [string]$Path, 40 [string]$Content, 41 [System.Text.Encoding]$Encoding 42 ) 43 44 $writer = New-Object System.IO.StreamWriter($Path, $false, $Encoding) 45 $writer.Write($Content) 46 $writer.Close() 47 } 48 49 50 function Add-NuGetSourceAndMapping { 51 param ( 52 [xml]$Xml, 53 [string]$Key, 54 [string]$Value, 55 [string[]]$Patterns 56 ) 57 58 # Ensure packageSources exists 59 if (-not $Xml.configuration.packageSources) { 60 $Xml.configuration.AppendChild($Xml.CreateElement("packageSources")) | Out-Null 61 } 62 $sources = $Xml.configuration.packageSources 63 64 # Add/Update Source 65 $sourceNode = $sources.SelectSingleNode("add[@key='$Key']") 66 if (-not $sourceNode) { 67 $sourceNode = $Xml.CreateElement("add") 68 $sourceNode.SetAttribute("key", $Key) 69 $sources.AppendChild($sourceNode) | Out-Null 70 } 71 $sourceNode.SetAttribute("value", $Value) 72 73 # Ensure packageSourceMapping exists 74 if (-not $Xml.configuration.packageSourceMapping) { 75 $Xml.configuration.AppendChild($Xml.CreateElement("packageSourceMapping")) | Out-Null 76 } 77 $mapping = $Xml.configuration.packageSourceMapping 78 79 # Remove invalid packageSource nodes (missing key or empty key) 80 $invalidNodes = $mapping.SelectNodes("packageSource[not(@key) or @key='']") 81 if ($invalidNodes) { 82 foreach ($node in $invalidNodes) { 83 $mapping.RemoveChild($node) | Out-Null 84 } 85 } 86 87 # Add/Update Mapping Source 88 $mappingSource = $mapping.SelectSingleNode("packageSource[@key='$Key']") 89 if (-not $mappingSource) { 90 $mappingSource = $Xml.CreateElement("packageSource") 91 $mappingSource.SetAttribute("key", $Key) 92 # Insert at top for priority 93 if ($mapping.HasChildNodes) { 94 $mapping.InsertBefore($mappingSource, $mapping.FirstChild) | Out-Null 95 } else { 96 $mapping.AppendChild($mappingSource) | Out-Null 97 } 98 } 99 100 # Double check and force attribute 101 if (-not $mappingSource.HasAttribute("key")) { 102 $mappingSource.SetAttribute("key", $Key) 103 } 104 105 # Update Patterns 106 # RemoveAll() removes all child nodes AND attributes, so we must re-set the key afterwards 107 $mappingSource.RemoveAll() 108 $mappingSource.SetAttribute("key", $Key) 109 110 foreach ($pattern in $Patterns) { 111 $pkg = $Xml.CreateElement("package") 112 $pkg.SetAttribute("pattern", $pattern) 113 $mappingSource.AppendChild($pkg) | Out-Null 114 } 115 } 116 117 function Resolve-WinAppSdkSplitDependencies { 118 Write-Host "Version $WinAppSDKVersion detected. Resolving split dependencies..." 119 $installDir = Join-Path $rootPath "localpackages\output" 120 New-Item -ItemType Directory -Path $installDir -Force | Out-Null 121 122 # Create a temporary nuget.config to avoid interference from the repo's config 123 $tempConfig = Join-Path $env:TEMP "nuget_$(Get-Random).config" 124 Set-Content -Path $tempConfig -Value "<?xml version='1.0' encoding='utf-8'?><configuration><packageSources><clear /><add key='TempSource' value='$sourceLink' /></packageSources></configuration>" 125 126 try { 127 # Extract BuildTools version from Directory.Packages.props to ensure we have the required version 128 $dirPackagesProps = Join-Path $rootPath "Directory.Packages.props" 129 if (Test-Path $dirPackagesProps) { 130 $propsContent = Get-Content $dirPackagesProps -Raw 131 if ($propsContent -match '<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="([^"]+)"') { 132 $buildToolsVersion = $Matches[1] 133 Write-Host "Downloading Microsoft.Windows.SDK.BuildTools version $buildToolsVersion..." 134 $nugetArgsBuildTools = "install Microsoft.Windows.SDK.BuildTools -Version $buildToolsVersion -ConfigFile $tempConfig -OutputDirectory $installDir -NonInteractive -NoCache" 135 Invoke-Expression "nuget $nugetArgsBuildTools" | Out-Null 136 } 137 } 138 139 # Download package to inspect nuspec and keep it for the build 140 $nugetArgs = "install Microsoft.WindowsAppSDK -Version $WinAppSDKVersion -ConfigFile $tempConfig -OutputDirectory $installDir -NonInteractive -NoCache" 141 Invoke-Expression "nuget $nugetArgs" | Out-Null 142 143 # Parse dependencies from the installed folders 144 # Folder structure is typically {PackageId}.{Version} 145 $directories = Get-ChildItem -Path $installDir -Directory 146 $allLocalPackages = @() 147 foreach ($dir in $directories) { 148 # Match any package pattern: PackageId.Version 149 if ($dir.Name -match "^(.+?)\.(\d+\..*)$") { 150 $pkgId = $Matches[1] 151 $pkgVer = $Matches[2] 152 $allLocalPackages += $pkgId 153 154 $packageVersions[$pkgId] = $pkgVer 155 Write-Host "Found dependency: $pkgId = $pkgVer" 156 } 157 } 158 159 # Update repo's nuget.config to use localpackages 160 $nugetConfig = Join-Path $rootPath "nuget.config" 161 $configData = Read-FileWithEncoding -Path $nugetConfig 162 [xml]$xml = $configData.Content 163 164 Add-NuGetSourceAndMapping -Xml $xml -Key "localpackages" -Value $installDir -Patterns $allLocalPackages 165 166 $xml.Save($nugetConfig) 167 Write-Host "Updated nuget.config with localpackages mapping." 168 } catch { 169 Write-Warning "Failed to resolve dependencies: $_" 170 } finally { 171 Remove-Item $tempConfig -Force -ErrorAction SilentlyContinue 172 } 173 } 174 175 # Execute nuget list and capture the output 176 if ($useExperimentalVersion) { 177 # The nuget list for experimental versions will cost more time 178 # So, we will not use -AllVersions to wast time 179 # But it can only get the latest experimental version 180 Write-Host "Fetching WindowsAppSDK with experimental versions" 181 $nugetOutput = nuget list Microsoft.WindowsAppSDK ` 182 -Source $sourceLink ` 183 -Prerelease 184 # Filter versions based on the specified version prefix 185 $escapedVersionNumber = [regex]::Escape($winAppSdkVersionNumber) 186 $filteredVersions = $nugetOutput | Where-Object { $_ -match "Microsoft.WindowsAppSDK $escapedVersionNumber\." } 187 $latestVersions = $filteredVersions 188 } else { 189 Write-Host "Fetching stable WindowsAppSDK versions for $winAppSdkVersionNumber" 190 $nugetOutput = nuget list Microsoft.WindowsAppSDK ` 191 -Source $sourceLink ` 192 -AllVersions 193 # Filter versions based on the specified version prefix 194 $escapedVersionNumber = [regex]::Escape($winAppSdkVersionNumber) 195 $filteredVersions = $nugetOutput | Where-Object { $_ -match "Microsoft.WindowsAppSDK $escapedVersionNumber\." } 196 $latestVersions = $filteredVersions | Sort-Object { [version]($_ -split ' ')[1] } -Descending | Select-Object -First 1 197 } 198 199 Write-Host "Latest versions found: $latestVersions" 200 # Extract the latest version number from the output 201 $latestVersion = $latestVersions -split "`n" | ` 202 Select-String -Pattern 'Microsoft.WindowsAppSDK\s*([0-9]+\.[0-9]+\.[0-9]+-*[a-zA-Z0-9]*)' | ` 203 ForEach-Object { $_.Matches[0].Groups[1].Value } | ` 204 Sort-Object -Descending | ` 205 Select-Object -First 1 206 207 if ($latestVersion) { 208 $WinAppSDKVersion = $latestVersion 209 Write-Host "Extracted version: $WinAppSDKVersion" 210 Write-Host "##vso[task.setvariable variable=WinAppSDKVersion]$WinAppSDKVersion" 211 } else { 212 Write-Host "Failed to extract version number from nuget list output" 213 exit 1 214 } 215 216 # Resolve dependencies for 1.8+ 217 $packageVersions = @{ "Microsoft.WindowsAppSDK" = $WinAppSDKVersion } 218 219 Resolve-WinAppSdkSplitDependencies 220 221 # Update Directory.Packages.props file 222 Get-ChildItem -Path $rootPath -Recurse "Directory.Packages.props" | ForEach-Object { 223 $file = Read-FileWithEncoding -Path $_.FullName 224 $content = $file.Content 225 $isModified = $false 226 227 foreach ($pkgId in $packageVersions.Keys) { 228 $ver = $packageVersions[$pkgId] 229 # Escape dots in package ID for regex 230 $pkgIdRegex = $pkgId -replace '\.', '\.' 231 232 $newVersionString = "<PackageVersion Include=""$pkgId"" Version=""$ver"" />" 233 $oldVersionString = "<PackageVersion Include=""$pkgIdRegex"" Version=""[-.0-9a-zA-Z]*"" />" 234 235 if ($content -match "<PackageVersion Include=""$pkgIdRegex""") { 236 # Update existing package 237 if ($content -notmatch [regex]::Escape($newVersionString)) { 238 $content = $content -replace $oldVersionString, $newVersionString 239 $isModified = $true 240 } 241 } 242 } 243 244 if ($isModified) { 245 Write-FileWithEncoding -Path $_.FullName -Content $content -Encoding $file.encoding 246 Write-Host "Modified " $_.FullName 247 } 248 }