From 448f42405b71f331987f7ab8fbd00491a8f11a5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Cant=C3=BA?= Date: Tue, 28 Oct 2025 16:28:22 -0500 Subject: [PATCH 1/6] Add exact version lookup for ApiDiff.ps1 --- release-notes/RunApiDiff.ps1 | 88 +++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 27 deletions(-) diff --git a/release-notes/RunApiDiff.ps1 b/release-notes/RunApiDiff.ps1 index a5e9c5ab11..072944732e 100644 --- a/release-notes/RunApiDiff.ps1 +++ b/release-notes/RunApiDiff.ps1 @@ -18,10 +18,15 @@ # -ExcludeAspNetCore : Optional boolean to exclude the AspNetCore comparison. Default is false. # -ExcludeWindowsDesktop : Optional boolean to exclude the WindowsDesktop comparison. Default is false. # -InstallApiDiff : Optional boolean to install or update the ApiDiff tool. Default is false. +# -PreviousPackageExactVersion : Optional exact package version for the previous/before comparison (e.g., "10.0.0-rc.1.25451.107"). Overrides version search logic. +# -CurrentPackageExactVersion : Optional exact package version for the current/after comparison (e.g., "10.0.0-rc.2.25502.107"). Overrides version search logic. # Example: # .\RunApiDiff.ps1 -PreviousDotNetVersion 9.0 -PreviousPreviewOrRC preview -PreviousPreviewNumberVersion 7 -CurrentDotNetVersion 9.0 -CurrentPreviewOrRC rc -CurrentPreviewNumberVersion 1 -CoreRepo C:\Users\calope\source\repos\core\ -SdkRepo C:\Users\calope\source\repos\sdk\ -TmpFolder C:\Users\calope\source\repos\tmp\ +# Example with exact package versions: +# .\RunApiDiff.ps1 -PreviousDotNetVersion 10.0 -PreviousPreviewOrRC RC -PreviousPreviewNumberVersion 1 -CurrentDotNetVersion 10.0 -CurrentPreviewOrRC RC -CurrentPreviewNumberVersion 2 -CoreRepo D:\core\ -TmpFolder D:\tmp -PreviousPackageExactVersion "10.0.0-rc.1.25451.107" -CurrentPackageExactVersion "10.0.0-rc.2.25502.107" + Param ( [Parameter(Mandatory = $true)] [ValidatePattern("\d+\.\d")] @@ -92,6 +97,14 @@ Param ( [Parameter(Mandatory = $false)] [bool] $InstallApiDiff = $false + , + [Parameter(Mandatory = $false)] + [string] + $PreviousPackageExactVersion = "" + , + [Parameter(Mandatory = $false)] + [string] + $CurrentPackageExactVersion = "" ) ####################### @@ -502,6 +515,10 @@ Function DownloadPackage { [string] $previewNumberVersion , + [Parameter(Mandatory = $false)] + [string] + $exactVersion = "" + , [ref] $resultingPath ) @@ -517,36 +534,45 @@ Function DownloadPackage { $feed = "https://api.nuget.org/v3/index.json" } - $searchTerm = "" - If ($previewOrRC -eq "ga") { - $searchTerm = "$dotNetversion.$previewNumberVersion" - } - ElseIf (-Not ([System.String]::IsNullOrWhiteSpace($previewOrRC)) -And -Not ([System.String]::IsNullOrWhiteSpace($previewNumberVersion))) { - $searchTerm = "$dotNetversion.*-$previewOrRC.$previewNumberVersion*" + $version = "" + + # If exact version is provided, use it directly + If (-Not ([System.String]::IsNullOrWhiteSpace($exactVersion))) { + Write-Color cyan "Using exact package version: $exactVersion" + $version = $exactVersion } + Else { + # Otherwise, search for the package version + $searchTerm = "" + If ($previewOrRC -eq "ga") { + $searchTerm = "$dotNetversion.$previewNumberVersion" + } + ElseIf (-Not ([System.String]::IsNullOrWhiteSpace($previewOrRC)) -And -Not ([System.String]::IsNullOrWhiteSpace($previewNumberVersion))) { + $searchTerm = "$dotNetversion.*-$previewOrRC.$previewNumberVersion*" + } - $foundPackages = Find-Package -AllVersions -Source $feed -Name $refPackageName -AllowPrereleaseVersions -ErrorAction Continue + $foundPackages = Find-Package -AllVersions -Source $feed -Name $refPackageName -AllowPrereleaseVersions -ErrorAction Continue - If ($foundPackages.Count -eq 0) { - Write-Error "No NuGet packages found with ref package name '$refPackageName' in feed '$feed'" - Get-PackageSource -Name $refPackageName | Format-Table -Property Name, SourceUri - Write-Error "Exiting" -ErrorAction Stop - } + If ($foundPackages.Count -eq 0) { + Write-Error "No NuGet packages found with ref package name '$refPackageName' in feed '$feed'" + Get-PackageSource -Name $refPackageName | Format-Table -Property Name, SourceUri + Write-Error "Exiting" -ErrorAction Stop + } - $results = $foundPackages | Where-Object -Property Version -Like $searchTerm | Sort-Object Version -Descending + $results = $foundPackages | Where-Object -Property Version -Like $searchTerm | Sort-Object Version -Descending - If ($results.Count -eq 0) { - Write-Error "No NuGet packages found with search term '$searchTerm'." -ErrorAction Stop - } + If ($results.Count -eq 0) { + Write-Error "No NuGet packages found with search term '$searchTerm'." -ErrorAction Stop + } - $version = $results[0].Version + $version = $results[0].Version + } + $nupkgFile = [IO.Path]::Combine($TmpFolder, "$refPackageName.$version.nupkg") If (-Not(Test-Path -Path $nupkgFile)) { - $href = $results[0].Links | Where-Object -Property Relationship -Eq "icon" | Select-Object -ExpandProperty HRef - $link = $href.AbsoluteUri.Replace("?extract=Icon.png", "") + $nupkgUrl = "https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/flat2/$refPackageName/$version/$refPackageName.$version.nupkg" - $nupkgUrl = $link if ($useDefaultNuGetFeed) { $nupkgUrl = "https://www.nuget.org/api/v2/package/$refPackageName/$version" } @@ -604,24 +630,32 @@ Function ProcessSdk [ValidateNotNullOrEmpty()] [string] $currentDotNetFriendlyName + , + [Parameter(Mandatory = $false)] + [string] + $previousExactVersion = "" + , + [Parameter(Mandatory = $false)] + [string] + $currentExactVersion = "" ) $beforeDllFolder = "" - DownloadPackage $UseDefaultNuGetFeed $sdkName "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion ([ref]$beforeDllFolder) + DownloadPackage $UseDefaultNuGetFeed $sdkName "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion $previousExactVersion ([ref]$beforeDllFolder) VerifyPathOrExit $beforeDllFolder $afterDllFolder = "" - DownloadPackage $UseDefaultNuGetFeed $sdkName "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion ([ref]$afterDllFolder) + DownloadPackage $UseDefaultNuGetFeed $sdkName "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $currentExactVersion ([ref]$afterDllFolder) VerifyPathOrExit $afterDllFolder # For AspNetCore and WindowsDesktop, also download NETCore references to provide core assemblies $beforeReferenceFolder = "" $afterReferenceFolder = "" if ($sdkName -eq "AspNetCore" -or $sdkName -eq "WindowsDesktop") { - DownloadPackage $UseDefaultNuGetFeed "NETCore" "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion ([ref]$beforeReferenceFolder) + DownloadPackage $UseDefaultNuGetFeed "NETCore" "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion $previousExactVersion ([ref]$beforeReferenceFolder) VerifyPathOrExit $beforeReferenceFolder - DownloadPackage $UseDefaultNuGetFeed "NETCore" "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion ([ref]$afterReferenceFolder) + DownloadPackage $UseDefaultNuGetFeed "NETCore" "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $currentExactVersion ([ref]$afterReferenceFolder) VerifyPathOrExit $afterReferenceFolder } @@ -689,17 +723,17 @@ $currentDotNetFriendlyName = GetDotNetFriendlyName $CurrentDotNetVersion $Curren If (-Not $ExcludeNetCore) { - ProcessSdk "NETCore" $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName + ProcessSdk "NETCore" $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion } If (-Not $ExcludeAspNetCore) { - ProcessSdk "AspNetCore" $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName + ProcessSdk "AspNetCore" $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion } If (-Not $ExcludeWindowsDesktop) { - ProcessSdk "WindowsDesktop" $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName + ProcessSdk "WindowsDesktop" $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion } CreateReadme $previewFolderPath $currentDotNetFriendlyName $currentDotNetFullName From 0903d21667fdf4b14fdf1e879741ad14b52802a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Cant=C3=BA?= Date: Tue, 4 Nov 2025 12:43:50 -0600 Subject: [PATCH 2/6] Allow passing arbitrary NuGet feeds --- release-notes/RunApiDiff.ps1 | 54 +++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/release-notes/RunApiDiff.ps1 b/release-notes/RunApiDiff.ps1 index 072944732e..80a17dd2ed 100644 --- a/release-notes/RunApiDiff.ps1 +++ b/release-notes/RunApiDiff.ps1 @@ -13,7 +13,7 @@ # -TmpFolder : The full path to the folder where the assets will be downloaded, extracted and compared. # -AttributesToExcludeFilePath : The full path to the file containing the attributes to exclude from the report. By default, it is "ApiDiffAttributesToExclude.txt" in the same folder as this script. # -AssembliesToExcludeFilePath : The full path to the file containing the assemblies to exclude from the report. By default, it is "ApiDiffAssembliesToExclude.txt" in the same folder as this script. -# -UseDefaultNuGetFeed : By default, the feed used is https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json , but if this is set to true, the feed used is https://api.nuget.org/v3/index.json +# -NuGetFeed : The NuGet feed URL to use for package downloads. By default, uses https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json # -ExcludeNetCore : Optional boolean to exclude the NETCore comparison. Default is false. # -ExcludeAspNetCore : Optional boolean to exclude the AspNetCore comparison. Default is false. # -ExcludeWindowsDesktop : Optional boolean to exclude the WindowsDesktop comparison. Default is false. @@ -27,6 +27,9 @@ # Example with exact package versions: # .\RunApiDiff.ps1 -PreviousDotNetVersion 10.0 -PreviousPreviewOrRC RC -PreviousPreviewNumberVersion 1 -CurrentDotNetVersion 10.0 -CurrentPreviewOrRC RC -CurrentPreviewNumberVersion 2 -CoreRepo D:\core\ -TmpFolder D:\tmp -PreviousPackageExactVersion "10.0.0-rc.1.25451.107" -CurrentPackageExactVersion "10.0.0-rc.2.25502.107" +# Example with custom NuGet feed: +# .\RunApiDiff.ps1 -PreviousDotNetVersion 9.0 -PreviousPreviewOrRC preview -PreviousPreviewNumberVersion 7 -CurrentDotNetVersion 9.0 -CurrentPreviewOrRC rc -CurrentPreviewNumberVersion 1 -CoreRepo D:\core\ -TmpFolder D:\tmp -NuGetFeed "https://api.nuget.org/v3/index.json" + Param ( [Parameter(Mandatory = $true)] [ValidatePattern("\d+\.\d")] @@ -79,8 +82,9 @@ Param ( $AssembliesToExcludeFilePath = "ApiDiffAssembliesToExclude.txt" , [Parameter(Mandatory = $false)] - [bool] - $UseDefaultNuGetFeed = $false + [ValidateNotNullOrEmpty()] + [string] + $NuGetFeed = "https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json" , [Parameter(Mandatory = $false)] [bool] @@ -487,8 +491,9 @@ Function DownloadPackage { Param ( [Parameter(Mandatory = $true)] - [bool] - $useDefaultNuGetFeed + [ValidateNotNullOrEmpty()] + [string] + $nuGetFeed , [Parameter(Mandatory = $true)] [ValidateSet("NETCore", "AspNetCore", "WindowsDesktop")] @@ -529,11 +534,6 @@ Function DownloadPackage { $refPackageName = "$fullSdkName.Ref" - $feed = "https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json" - if ($useDefaultNuGetFeed) { - $feed = "https://api.nuget.org/v3/index.json" - } - $version = "" # If exact version is provided, use it directly @@ -551,10 +551,10 @@ Function DownloadPackage { $searchTerm = "$dotNetversion.*-$previewOrRC.$previewNumberVersion*" } - $foundPackages = Find-Package -AllVersions -Source $feed -Name $refPackageName -AllowPrereleaseVersions -ErrorAction Continue + $foundPackages = Find-Package -AllVersions -Source $nuGetFeed -Name $refPackageName -AllowPrereleaseVersions -ErrorAction Continue If ($foundPackages.Count -eq 0) { - Write-Error "No NuGet packages found with ref package name '$refPackageName' in feed '$feed'" + Write-Error "No NuGet packages found with ref package name '$refPackageName' in feed '$nuGetFeed'" Get-PackageSource -Name $refPackageName | Format-Table -Property Name, SourceUri Write-Error "Exiting" -ErrorAction Stop } @@ -571,11 +571,16 @@ Function DownloadPackage { $nupkgFile = [IO.Path]::Combine($TmpFolder, "$refPackageName.$version.nupkg") If (-Not(Test-Path -Path $nupkgFile)) { - $nupkgUrl = "https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/flat2/$refPackageName/$version/$refPackageName.$version.nupkg" - - if ($useDefaultNuGetFeed) { + # Construct download URL based on the feed + if ($nuGetFeed -eq "https://api.nuget.org/v3/index.json") { + # Use NuGet.org v2 API for downloads $nupkgUrl = "https://www.nuget.org/api/v2/package/$refPackageName/$version" } + else { + # Use flat2 pattern for all other feeds + $baseUrl = $nuGetFeed -replace "/v3/index\.json$", "" + $nupkgUrl = "$baseUrl/v3/flat2/$refPackageName/$version/$refPackageName.$version.nupkg" + } Write-Color yellow "Downloading '$nupkgUrl' to '$nupkgFile'..." Invoke-WebRequest -Uri $nupkgUrl -OutFile $nupkgFile @@ -600,6 +605,11 @@ Function ProcessSdk [ValidateNotNullOrEmpty()] [string] $sdkName + , + [Parameter(Mandatory = $false)] + [ValidateNotNullOrEmpty()] + [string] + $nuGetFeed , [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] @@ -641,21 +651,21 @@ Function ProcessSdk ) $beforeDllFolder = "" - DownloadPackage $UseDefaultNuGetFeed $sdkName "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion $previousExactVersion ([ref]$beforeDllFolder) + DownloadPackage $nuGetFeed $sdkName "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion $previousExactVersion ([ref]$beforeDllFolder) VerifyPathOrExit $beforeDllFolder $afterDllFolder = "" - DownloadPackage $UseDefaultNuGetFeed $sdkName "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $currentExactVersion ([ref]$afterDllFolder) + DownloadPackage $nuGetFeed $sdkName "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $currentExactVersion ([ref]$afterDllFolder) VerifyPathOrExit $afterDllFolder # For AspNetCore and WindowsDesktop, also download NETCore references to provide core assemblies $beforeReferenceFolder = "" $afterReferenceFolder = "" if ($sdkName -eq "AspNetCore" -or $sdkName -eq "WindowsDesktop") { - DownloadPackage $UseDefaultNuGetFeed "NETCore" "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion $previousExactVersion ([ref]$beforeReferenceFolder) + DownloadPackage $nuGetFeed "NETCore" "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion $previousExactVersion ([ref]$beforeReferenceFolder) VerifyPathOrExit $beforeReferenceFolder - DownloadPackage $UseDefaultNuGetFeed "NETCore" "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $currentExactVersion ([ref]$afterReferenceFolder) + DownloadPackage $nuGetFeed "NETCore" "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $currentExactVersion ([ref]$afterReferenceFolder) VerifyPathOrExit $afterReferenceFolder } @@ -723,17 +733,17 @@ $currentDotNetFriendlyName = GetDotNetFriendlyName $CurrentDotNetVersion $Curren If (-Not $ExcludeNetCore) { - ProcessSdk "NETCore" $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion + ProcessSdk "NETCore" $NuGetFeed $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion } If (-Not $ExcludeAspNetCore) { - ProcessSdk "AspNetCore" $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion + ProcessSdk "AspNetCore" $NuGetFeed $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion } If (-Not $ExcludeWindowsDesktop) { - ProcessSdk "WindowsDesktop" $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion + ProcessSdk "WindowsDesktop" $NuGetFeed $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion } CreateReadme $previewFolderPath $currentDotNetFriendlyName $currentDotNetFullName From 6827e2d5a930b6db6fd1f73715790070340a0ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Cant=C3=BA?= Date: Tue, 4 Nov 2025 12:50:56 -0600 Subject: [PATCH 3/6] Use az cli for auth if needed --- release-notes/RunApiDiff.ps1 | 48 +++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/release-notes/RunApiDiff.ps1 b/release-notes/RunApiDiff.ps1 index 80a17dd2ed..50958b3063 100644 --- a/release-notes/RunApiDiff.ps1 +++ b/release-notes/RunApiDiff.ps1 @@ -1,5 +1,9 @@ # This script allows running API-diff to generate the dotnet/core report that compares the APIs introduced between two previews, in the format expected for publishing in the dotnet/core repo. +# Prerequisites: +# - PowerShell 7.0 or later +# - Azure CLI (az) installed and logged in (required for authenticated Azure DevOps feeds): Run 'az login' before using private feeds + # Usage: # RunApiDiff.ps1 @@ -455,6 +459,39 @@ Function CreateReadme { Add-Content $readmePath "- [Microsoft.WindowsDesktop.App](./Microsoft.WindowsDesktop.App/$dotNetFullName.md)" } +Function GetAuthHeadersForFeed { + Param ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $feedUrl + ) + + $headers = @{} + + # Check if authentication is required (internal dnceng feeds) + if ($feedUrl -match "dnceng/internal") { + try { + # Try to get Azure DevOps token using az CLI + $token = az account get-access-token --resource "499b84ac-1321-427f-aa17-267ca6975798" --query accessToken -o tsv 2>$null + if ($token) { + Write-Color cyan "Using Azure CLI authentication for internal Azure DevOps feed" + $headers = @{ + Authorization = "Bearer $token" + } + } + else { + Write-Error "Could not get Azure DevOps token from Azure CLI. Please run 'az login' first." -ErrorAction Stop + } + } + catch { + Write-Error "Azure CLI not available or not logged in. Please run 'az login' first." -ErrorAction Stop + } + } + + return $headers +} + Function RebuildIfExeNotFound { Param ( [Parameter(Mandatory = $true)] @@ -583,7 +620,16 @@ Function DownloadPackage { } Write-Color yellow "Downloading '$nupkgUrl' to '$nupkgFile'..." - Invoke-WebRequest -Uri $nupkgUrl -OutFile $nupkgFile + + # Get authentication headers if required + $headers = GetAuthHeadersForFeed $nuGetFeed + + if ($headers.Count -gt 0) { + Invoke-WebRequest -Uri $nupkgUrl -OutFile $nupkgFile -Headers $headers + } + else { + Invoke-WebRequest -Uri $nupkgUrl -OutFile $nupkgFile + } VerifyPathOrExit $nupkgFile } Else { From d9d1efd90a6e72fda1bd7a034a6cf1174333a1c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Cant=C3=BA?= Date: Tue, 4 Nov 2025 13:01:43 -0600 Subject: [PATCH 4/6] Split NuGetFeed into two for previous and current --- release-notes/RunApiDiff.ps1 | 41 ++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/release-notes/RunApiDiff.ps1 b/release-notes/RunApiDiff.ps1 index 50958b3063..61eab0bb24 100644 --- a/release-notes/RunApiDiff.ps1 +++ b/release-notes/RunApiDiff.ps1 @@ -17,7 +17,8 @@ # -TmpFolder : The full path to the folder where the assets will be downloaded, extracted and compared. # -AttributesToExcludeFilePath : The full path to the file containing the attributes to exclude from the report. By default, it is "ApiDiffAttributesToExclude.txt" in the same folder as this script. # -AssembliesToExcludeFilePath : The full path to the file containing the assemblies to exclude from the report. By default, it is "ApiDiffAssembliesToExclude.txt" in the same folder as this script. -# -NuGetFeed : The NuGet feed URL to use for package downloads. By default, uses https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json +# -PreviousNuGetFeed : The NuGet feed URL to use for downloading previous/before packages. By default, uses https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json +# -CurrentNuGetFeed : The NuGet feed URL to use for downloading current/after packages. By default, uses https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json # -ExcludeNetCore : Optional boolean to exclude the NETCore comparison. Default is false. # -ExcludeAspNetCore : Optional boolean to exclude the AspNetCore comparison. Default is false. # -ExcludeWindowsDesktop : Optional boolean to exclude the WindowsDesktop comparison. Default is false. @@ -32,7 +33,7 @@ # .\RunApiDiff.ps1 -PreviousDotNetVersion 10.0 -PreviousPreviewOrRC RC -PreviousPreviewNumberVersion 1 -CurrentDotNetVersion 10.0 -CurrentPreviewOrRC RC -CurrentPreviewNumberVersion 2 -CoreRepo D:\core\ -TmpFolder D:\tmp -PreviousPackageExactVersion "10.0.0-rc.1.25451.107" -CurrentPackageExactVersion "10.0.0-rc.2.25502.107" # Example with custom NuGet feed: -# .\RunApiDiff.ps1 -PreviousDotNetVersion 9.0 -PreviousPreviewOrRC preview -PreviousPreviewNumberVersion 7 -CurrentDotNetVersion 9.0 -CurrentPreviewOrRC rc -CurrentPreviewNumberVersion 1 -CoreRepo D:\core\ -TmpFolder D:\tmp -NuGetFeed "https://api.nuget.org/v3/index.json" +# .\RunApiDiff.ps1 -PreviousDotNetVersion 9.0 -PreviousPreviewOrRC preview -PreviousPreviewNumberVersion 7 -CurrentDotNetVersion 9.0 -CurrentPreviewOrRC rc -CurrentPreviewNumberVersion 1 -CoreRepo D:\core\ -TmpFolder D:\tmp -PreviousNuGetFeed "https://api.nuget.org/v3/index.json" -CurrentNuGetFeed "https://api.nuget.org/v3/index.json" Param ( [Parameter(Mandatory = $true)] @@ -88,7 +89,12 @@ Param ( [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string] - $NuGetFeed = "https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json" + $PreviousNuGetFeed = "https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json" + , + [Parameter(Mandatory = $false)] + [ValidateNotNullOrEmpty()] + [string] + $CurrentNuGetFeed = "https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json" , [Parameter(Mandatory = $false)] [bool] @@ -467,16 +473,14 @@ Function GetAuthHeadersForFeed { $feedUrl ) - $headers = @{} - # Check if authentication is required (internal dnceng feeds) if ($feedUrl -match "dnceng/internal") { try { # Try to get Azure DevOps token using az CLI $token = az account get-access-token --resource "499b84ac-1321-427f-aa17-267ca6975798" --query accessToken -o tsv 2>$null if ($token) { - Write-Color cyan "Using Azure CLI authentication for internal Azure DevOps feed" - $headers = @{ + Write-Host "Using Azure CLI authentication for internal Azure DevOps feed" -ForegroundColor Cyan + return @{ Authorization = "Bearer $token" } } @@ -489,7 +493,7 @@ Function GetAuthHeadersForFeed { } } - return $headers + return @{} } Function RebuildIfExeNotFound { @@ -655,7 +659,12 @@ Function ProcessSdk [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string] - $nuGetFeed + $previousNuGetFeed + , + [Parameter(Mandatory = $false)] + [ValidateNotNullOrEmpty()] + [string] + $currentNuGetFeed , [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] @@ -697,21 +706,21 @@ Function ProcessSdk ) $beforeDllFolder = "" - DownloadPackage $nuGetFeed $sdkName "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion $previousExactVersion ([ref]$beforeDllFolder) + DownloadPackage $previousNuGetFeed $sdkName "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion $previousExactVersion ([ref]$beforeDllFolder) VerifyPathOrExit $beforeDllFolder $afterDllFolder = "" - DownloadPackage $nuGetFeed $sdkName "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $currentExactVersion ([ref]$afterDllFolder) + DownloadPackage $currentNuGetFeed $sdkName "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $currentExactVersion ([ref]$afterDllFolder) VerifyPathOrExit $afterDllFolder # For AspNetCore and WindowsDesktop, also download NETCore references to provide core assemblies $beforeReferenceFolder = "" $afterReferenceFolder = "" if ($sdkName -eq "AspNetCore" -or $sdkName -eq "WindowsDesktop") { - DownloadPackage $nuGetFeed "NETCore" "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion $previousExactVersion ([ref]$beforeReferenceFolder) + DownloadPackage $previousNuGetFeed "NETCore" "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion $previousExactVersion ([ref]$beforeReferenceFolder) VerifyPathOrExit $beforeReferenceFolder - DownloadPackage $nuGetFeed "NETCore" "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $currentExactVersion ([ref]$afterReferenceFolder) + DownloadPackage $currentNuGetFeed "NETCore" "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $currentExactVersion ([ref]$afterReferenceFolder) VerifyPathOrExit $afterReferenceFolder } @@ -779,17 +788,17 @@ $currentDotNetFriendlyName = GetDotNetFriendlyName $CurrentDotNetVersion $Curren If (-Not $ExcludeNetCore) { - ProcessSdk "NETCore" $NuGetFeed $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion + ProcessSdk "NETCore" $PreviousNuGetFeed $CurrentNuGetFeed $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion } If (-Not $ExcludeAspNetCore) { - ProcessSdk "AspNetCore" $NuGetFeed $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion + ProcessSdk "AspNetCore" $PreviousNuGetFeed $CurrentNuGetFeed $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion } If (-Not $ExcludeWindowsDesktop) { - ProcessSdk "WindowsDesktop" $NuGetFeed $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion + ProcessSdk "WindowsDesktop" $PreviousNuGetFeed $CurrentNuGetFeed $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion } CreateReadme $previewFolderPath $currentDotNetFriendlyName $currentDotNetFullName From a3ec1e46e6afaa8a4a202e4848bfea0da09e68a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Cant=C3=BA?= Date: Tue, 4 Nov 2025 15:38:34 -0600 Subject: [PATCH 5/6] Support auth also on version search path --- release-notes/RunApiDiff.ps1 | 47 +++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/release-notes/RunApiDiff.ps1 b/release-notes/RunApiDiff.ps1 index 61eab0bb24..977bda685a 100644 --- a/release-notes/RunApiDiff.ps1 +++ b/release-notes/RunApiDiff.ps1 @@ -592,21 +592,46 @@ Function DownloadPackage { $searchTerm = "$dotNetversion.*-$previewOrRC.$previewNumberVersion*" } - $foundPackages = Find-Package -AllVersions -Source $nuGetFeed -Name $refPackageName -AllowPrereleaseVersions -ErrorAction Continue - - If ($foundPackages.Count -eq 0) { - Write-Error "No NuGet packages found with ref package name '$refPackageName' in feed '$nuGetFeed'" - Get-PackageSource -Name $refPackageName | Format-Table -Property Name, SourceUri - Write-Error "Exiting" -ErrorAction Stop + # Use NuGet API directly instead of Find-Package to support authenticated feeds + Write-Color cyan "Searching for package '$refPackageName' matching '$searchTerm' in feed '$nuGetFeed'..." + + $headers = GetAuthHeadersForFeed $nuGetFeed + + # Get service index + $serviceIndex = Invoke-RestMethod -Uri $nuGetFeed -Headers $headers + $searchQueryService = $serviceIndex.resources | Where-Object { $_.'@type' -match 'SearchQueryService' } | Select-Object -First 1 + + if (-not $searchQueryService) { + Write-Error "Could not find SearchQueryService endpoint in feed '$nuGetFeed'" -ErrorAction Stop } - - $results = $foundPackages | Where-Object -Property Version -Like $searchTerm | Sort-Object Version -Descending - - If ($results.Count -eq 0) { + + $searchUrl = $searchQueryService.'@id' + + $searchParams = @{ + Uri = "$searchUrl`?q=$refPackageName&prerelease=true&take=1" + Headers = $headers + } + + $searchResults = Invoke-RestMethod @searchParams + + If (-not $searchResults.data -or $searchResults.data.Count -eq 0) { + Write-Error "No NuGet packages found with ref package name '$refPackageName' in feed '$nuGetFeed'" -ErrorAction Stop + } + + $package = $searchResults.data | Where-Object { $_.id -eq $refPackageName } | Select-Object -First 1 + + If (-not $package) { + Write-Error "Package '$refPackageName' not found in search results" -ErrorAction Stop + } + + # Filter versions matching search term + $matchingVersions = $package.versions | Where-Object -Property version -Like $searchTerm | Sort-Object version -Descending + + If ($matchingVersions.Count -eq 0) { Write-Error "No NuGet packages found with search term '$searchTerm'." -ErrorAction Stop } - $version = $results[0].Version + $version = $matchingVersions[0].version } $nupkgFile = [IO.Path]::Combine($TmpFolder, "$refPackageName.$version.nupkg") From 0eff863d58194b7e21071e72caba6d1aa6b893a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Cant=C3=BA?= Date: Tue, 4 Nov 2025 15:47:59 -0600 Subject: [PATCH 6/6] Address feedback ExactVersion -> Version --- release-notes/RunApiDiff.ps1 | 37 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/release-notes/RunApiDiff.ps1 b/release-notes/RunApiDiff.ps1 index 977bda685a..03ac31c204 100644 --- a/release-notes/RunApiDiff.ps1 +++ b/release-notes/RunApiDiff.ps1 @@ -23,14 +23,14 @@ # -ExcludeAspNetCore : Optional boolean to exclude the AspNetCore comparison. Default is false. # -ExcludeWindowsDesktop : Optional boolean to exclude the WindowsDesktop comparison. Default is false. # -InstallApiDiff : Optional boolean to install or update the ApiDiff tool. Default is false. -# -PreviousPackageExactVersion : Optional exact package version for the previous/before comparison (e.g., "10.0.0-rc.1.25451.107"). Overrides version search logic. -# -CurrentPackageExactVersion : Optional exact package version for the current/after comparison (e.g., "10.0.0-rc.2.25502.107"). Overrides version search logic. +# -PreviousPackageVersion : Optional exact package version for the previous/before comparison (e.g., "10.0.0-rc.1.25451.107"). Overrides version search logic. +# -CurrentPackageVersion : Optional exact package version for the current/after comparison (e.g., "10.0.0-rc.2.25502.107"). Overrides version search logic. # Example: # .\RunApiDiff.ps1 -PreviousDotNetVersion 9.0 -PreviousPreviewOrRC preview -PreviousPreviewNumberVersion 7 -CurrentDotNetVersion 9.0 -CurrentPreviewOrRC rc -CurrentPreviewNumberVersion 1 -CoreRepo C:\Users\calope\source\repos\core\ -SdkRepo C:\Users\calope\source\repos\sdk\ -TmpFolder C:\Users\calope\source\repos\tmp\ # Example with exact package versions: -# .\RunApiDiff.ps1 -PreviousDotNetVersion 10.0 -PreviousPreviewOrRC RC -PreviousPreviewNumberVersion 1 -CurrentDotNetVersion 10.0 -CurrentPreviewOrRC RC -CurrentPreviewNumberVersion 2 -CoreRepo D:\core\ -TmpFolder D:\tmp -PreviousPackageExactVersion "10.0.0-rc.1.25451.107" -CurrentPackageExactVersion "10.0.0-rc.2.25502.107" +# .\RunApiDiff.ps1 -PreviousDotNetVersion 10.0 -PreviousPreviewOrRC RC -PreviousPreviewNumberVersion 1 -CurrentDotNetVersion 10.0 -CurrentPreviewOrRC RC -CurrentPreviewNumberVersion 2 -CoreRepo D:\core\ -TmpFolder D:\tmp -PreviousPackageVersion "10.0.0-rc.1.25451.107" -CurrentPackageVersion "10.0.0-rc.2.25502.107" # Example with custom NuGet feed: # .\RunApiDiff.ps1 -PreviousDotNetVersion 9.0 -PreviousPreviewOrRC preview -PreviousPreviewNumberVersion 7 -CurrentDotNetVersion 9.0 -CurrentPreviewOrRC rc -CurrentPreviewNumberVersion 1 -CoreRepo D:\core\ -TmpFolder D:\tmp -PreviousNuGetFeed "https://api.nuget.org/v3/index.json" -CurrentNuGetFeed "https://api.nuget.org/v3/index.json" @@ -114,11 +114,11 @@ Param ( , [Parameter(Mandatory = $false)] [string] - $PreviousPackageExactVersion = "" + $PreviousPackageVersion = "" , [Parameter(Mandatory = $false)] [string] - $CurrentPackageExactVersion = "" + $CurrentPackageVersion = "" ) ####################### @@ -563,7 +563,7 @@ Function DownloadPackage { , [Parameter(Mandatory = $false)] [string] - $exactVersion = "" + $version = "" , [ref] $resultingPath @@ -575,12 +575,9 @@ Function DownloadPackage { $refPackageName = "$fullSdkName.Ref" - $version = "" - # If exact version is provided, use it directly - If (-Not ([System.String]::IsNullOrWhiteSpace($exactVersion))) { - Write-Color cyan "Using exact package version: $exactVersion" - $version = $exactVersion + If (-Not ([System.String]::IsNullOrWhiteSpace($version))) { + Write-Color cyan "Using exact package version: $version" } Else { # Otherwise, search for the package version @@ -723,29 +720,29 @@ Function ProcessSdk , [Parameter(Mandatory = $false)] [string] - $previousExactVersion = "" + $previousVersion = "" , [Parameter(Mandatory = $false)] [string] - $currentExactVersion = "" + $currentVersion = "" ) $beforeDllFolder = "" - DownloadPackage $previousNuGetFeed $sdkName "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion $previousExactVersion ([ref]$beforeDllFolder) + DownloadPackage $previousNuGetFeed $sdkName "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion $previousVersion ([ref]$beforeDllFolder) VerifyPathOrExit $beforeDllFolder $afterDllFolder = "" - DownloadPackage $currentNuGetFeed $sdkName "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $currentExactVersion ([ref]$afterDllFolder) + DownloadPackage $currentNuGetFeed $sdkName "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $currentVersion ([ref]$afterDllFolder) VerifyPathOrExit $afterDllFolder # For AspNetCore and WindowsDesktop, also download NETCore references to provide core assemblies $beforeReferenceFolder = "" $afterReferenceFolder = "" if ($sdkName -eq "AspNetCore" -or $sdkName -eq "WindowsDesktop") { - DownloadPackage $previousNuGetFeed "NETCore" "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion $previousExactVersion ([ref]$beforeReferenceFolder) + DownloadPackage $previousNuGetFeed "NETCore" "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion $previousVersion ([ref]$beforeReferenceFolder) VerifyPathOrExit $beforeReferenceFolder - DownloadPackage $currentNuGetFeed "NETCore" "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $currentExactVersion ([ref]$afterReferenceFolder) + DownloadPackage $currentNuGetFeed "NETCore" "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $currentVersion ([ref]$afterReferenceFolder) VerifyPathOrExit $afterReferenceFolder } @@ -813,17 +810,17 @@ $currentDotNetFriendlyName = GetDotNetFriendlyName $CurrentDotNetVersion $Curren If (-Not $ExcludeNetCore) { - ProcessSdk "NETCore" $PreviousNuGetFeed $CurrentNuGetFeed $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion + ProcessSdk "NETCore" $PreviousNuGetFeed $CurrentNuGetFeed $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageVersion $CurrentPackageVersion } If (-Not $ExcludeAspNetCore) { - ProcessSdk "AspNetCore" $PreviousNuGetFeed $CurrentNuGetFeed $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion + ProcessSdk "AspNetCore" $PreviousNuGetFeed $CurrentNuGetFeed $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageVersion $CurrentPackageVersion } If (-Not $ExcludeWindowsDesktop) { - ProcessSdk "WindowsDesktop" $PreviousNuGetFeed $CurrentNuGetFeed $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageExactVersion $CurrentPackageExactVersion + ProcessSdk "WindowsDesktop" $PreviousNuGetFeed $CurrentNuGetFeed $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageVersion $CurrentPackageVersion } CreateReadme $previewFolderPath $currentDotNetFriendlyName $currentDotNetFullName