* Add exact version lookup for ApiDiff.ps1 * Allow passing arbitrary NuGet feeds * Use az cli for auth if needed * Split NuGetFeed into two for previous and current * Support auth also on version search path * Address feedback ExactVersion -> Version
830 lines
28 KiB
PowerShell
830 lines
28 KiB
PowerShell
# 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
|
|
# -PreviousDotNetVersion : The 'before' .NET version: '6.0', '7.0', '8.0', etc.
|
|
# -PreviousPreviewOrRC : An optional word that indicates if the 'before' version is a Preview, an RC, or GA. Accepted values: "preview", "rc" or "ga".
|
|
# -PreviousPreviewNumberVersion : The optional preview or RC number of the 'before' version: '1', '2', '3', etc. For GA, this number is the 3rd one in the released version (7.0.0, 7.0.1, 7.0.2, ...).
|
|
# -CurrentDotNetVersion : The 'after' .NET version: '6.0', '7.0', '8.0', etc.
|
|
# -CurrentPreviewOrRC : An optional word that indicates if the 'after' version is a Preview, an RC, or GA. Accepted values: "preview", "rc" or "ga".
|
|
# -CurrentPreviewNumberVersion : The optional preview or RC number of the 'before' version: '1', '2', '3', etc. For GA, this number is the 3rd one in the released version (7.0.0, 7.0.1, 7.0.2, ...).
|
|
# -CoreRepo : The full path to your local clone of the dotnet/core repo.
|
|
# -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.
|
|
# -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.
|
|
# -InstallApiDiff : Optional boolean to install or update the ApiDiff tool. Default is false.
|
|
# -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 -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"
|
|
|
|
Param (
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidatePattern("\d+\.\d")]
|
|
[string]
|
|
$PreviousDotNetVersion # 7.0, 8.0, 9.0, ...
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[string]
|
|
[ValidateSet("preview", "rc", "ga")]
|
|
$PreviousPreviewOrRC
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidatePattern("(\d+)?")]
|
|
[string]
|
|
$PreviousPreviewNumberVersion # 0, 1, 2, 3, ...
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidatePattern("\d+\.\d")]
|
|
[string]
|
|
$CurrentDotNetVersion # 7.0, 8.0, 9.0, ...
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[string]
|
|
[ValidateSet("preview", "rc", "ga")]
|
|
$CurrentPreviewOrRC
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidatePattern("(\d+)?")]
|
|
[string]
|
|
$CurrentPreviewNumberVersion # 0, 1, 2, 3, ...
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$CoreRepo #"D:\\core"
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$TmpFolder #"D:\tmp"
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$AttributesToExcludeFilePath = "ApiDiffAttributesToExclude.txt"
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$AssembliesToExcludeFilePath = "ApiDiffAssembliesToExclude.txt"
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$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]
|
|
$ExcludeNetCore = $false
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[bool]
|
|
$ExcludeAspNetCore = $false
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[bool]
|
|
$ExcludeWindowsDesktop = $false
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[bool]
|
|
$InstallApiDiff = $false
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[string]
|
|
$PreviousPackageVersion = ""
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[string]
|
|
$CurrentPackageVersion = ""
|
|
)
|
|
|
|
#######################
|
|
### Start Functions ###
|
|
#######################
|
|
|
|
Function Write-Color {
|
|
Param (
|
|
[ValidateNotNullOrEmpty()]
|
|
[string] $newColor
|
|
)
|
|
|
|
$oldColor = $host.UI.RawUI.ForegroundColor
|
|
$host.UI.RawUI.ForegroundColor = $newColor
|
|
|
|
If ($args) {
|
|
Write-Output $args
|
|
}
|
|
Else {
|
|
$input | Write-Output
|
|
}
|
|
|
|
$host.UI.RawUI.ForegroundColor = $oldColor
|
|
}
|
|
|
|
Function VerifyPathOrExit {
|
|
Param (
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$path
|
|
)
|
|
|
|
If (-Not (Test-Path -Path $path)) {
|
|
Write-Error "The path '$path' does not exist." -ErrorAction Stop
|
|
}
|
|
}
|
|
|
|
Function RemoveFolderIfExists {
|
|
Param (
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$path
|
|
)
|
|
|
|
If (Test-Path -Path $path) {
|
|
Write-Color yellow "Removing existing folder: $path"
|
|
Remove-Item -Recurse -Path $path
|
|
}
|
|
}
|
|
|
|
Function RecreateFolder {
|
|
Param (
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$path
|
|
)
|
|
|
|
RemoveFolderIfExists $path
|
|
|
|
Write-Color cyan "Creating new folder: $path"
|
|
New-Item -ItemType Directory -Path $path
|
|
}
|
|
|
|
Function VerifyCountDlls {
|
|
Param (
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$path
|
|
)
|
|
|
|
VerifyPathOrExit $path
|
|
|
|
$count = (Get-ChildItem -Path $path -Filter "*.dll" | Measure-Object).Count
|
|
If ($count -eq 0) {
|
|
Write-Error "There are no DLL files inside the folder." -ErrorAction Stop
|
|
}
|
|
}
|
|
|
|
Function RunCommand {
|
|
Param (
|
|
[Parameter(Mandatory = $True)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$command
|
|
)
|
|
|
|
Write-Color yellow $command
|
|
Invoke-Expression "$command"
|
|
}
|
|
|
|
Function GetDotNetFullName {
|
|
Param (
|
|
[Parameter(Mandatory = $true)]
|
|
[bool]
|
|
$IsComparingReleases
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidatePattern("\d+\.\d")]
|
|
[string]
|
|
$dotNetVersion # 7.0, 8.0, 9.0, ...
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[string]
|
|
[ValidateSet("preview", "rc", "ga")]
|
|
$previewOrRC
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidatePattern("(\d+)?")]
|
|
[string]
|
|
$previewNumberVersion # 0, 1, 2, 3, ...
|
|
)
|
|
|
|
If ($IsComparingReleases) {
|
|
Return "$dotNetVersion.$previewNumberVersion"
|
|
}
|
|
|
|
If ($previewOrRC -eq "ga") {
|
|
If ($previewNumberVersion -eq "0") {
|
|
# Example: Don't return "7.0-ga0", instead just return "7.0-ga"
|
|
Return "$dotNetVersion-$previewOrRC"
|
|
}
|
|
|
|
# Examples: Don't include "ga", instead just return "7.0.1", "7.0.2"
|
|
Return "$dotNetVersion.$previewNumberVersion"
|
|
}
|
|
|
|
# Examples: "7.0-preview5", "7.0-rc2", "7.0-ga"
|
|
Return "$dotNetVersion-$previewOrRC$previewNumberVersion"
|
|
}
|
|
|
|
Function GetDotNetFriendlyName {
|
|
Param (
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidatePattern("\d+\.\d")]
|
|
[string]
|
|
$DotNetVersion # 7.0, 8.0, 9.0, ...
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[string]
|
|
[ValidateSet("preview", "rc", "ga")]
|
|
$PreviewOrRC
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidatePattern("(\d+)?")]
|
|
[string]
|
|
$PreviewNumberVersion # 0, 1, 2, 3, ...
|
|
)
|
|
|
|
$friendlyPreview = ""
|
|
If ($PreviewOrRC -eq "preview") {
|
|
$friendlyPreview = "Preview"
|
|
}
|
|
ElseIf ($PreviewOrRC -eq "rc") {
|
|
$friendlyPreview = "RC"
|
|
}
|
|
ElseIf ($PreviewOrRC -eq "ga") {
|
|
$friendlyPreview = "GA"
|
|
If ($PreviewNumberVersion -eq 0) {
|
|
# Example: Don't return "7.0 GA 0", instead just return "7.0 GA"
|
|
Return ".NET $DotNetVersion $friendlyPreview"
|
|
}
|
|
|
|
# Examples: Don't include "ga", instead just return "7.0.1", "7.0.2"
|
|
Return ".NET $DotNetVersion.$PreviewNumberVersion"
|
|
}
|
|
|
|
# Examples: "7.0 Preview 5", "7.0 RC 2"
|
|
Return ".NET $DotNetVersion $friendlyPreview $PreviewNumberVersion"
|
|
}
|
|
|
|
Function GetPreviewOrRCFolderName {
|
|
Param (
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidatePattern("\d+\.\d")]
|
|
[string]
|
|
$dotNetVersion # 7.0, 8.0, 9.0, ...
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[string]
|
|
[ValidateSet("preview", "rc", "ga")]
|
|
$previewOrRC
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidatePattern("(\d+)?")]
|
|
[string]
|
|
$previewNumberVersion # 0, 1, 2, 3, ...
|
|
)
|
|
|
|
If ($previewOrRC -eq "ga") {
|
|
If ($previewNumberVersion -eq "0") {
|
|
# return "ga", not "ga0"
|
|
Return $previewOrRC
|
|
}
|
|
|
|
# return "7.0.1", "7.0.2", not "ga1, ga2"
|
|
Return "$dotNetVersion$previewNumberVersion"
|
|
}
|
|
|
|
Return "$previewOrRC$previewNumberVersion"
|
|
}
|
|
|
|
Function GetPreviewFolderPath {
|
|
Param (
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$rootFolder #"D:\\core"
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidatePattern("\d+\.\d")]
|
|
[string]
|
|
$dotNetVersion # 7.0, 8.0, 9.0, ...
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[string]
|
|
[ValidateSet("preview", "rc", "ga")]
|
|
$previewOrRC
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidatePattern("(\d+)?")]
|
|
[string]
|
|
$previewNumberVersion # 0, 1, 2, 3, ...
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[bool]
|
|
$IsComparingReleases # True when comparing 8.0 GA with 9.0 GA
|
|
)
|
|
|
|
$prefixFolder = [IO.Path]::Combine($rootFolder, "release-notes", $dotNetVersion)
|
|
$apiDiffFolderName = "api-diff"
|
|
|
|
If ($IsComparingReleases) {
|
|
Return [IO.Path]::Combine($prefixFolder, "$dotNetVersion.$previewNumberVersion", $apiDiffFolderName)
|
|
}
|
|
|
|
$previewOrRCFolderName = GetPreviewOrRCFolderName $dotNetVersion $previewOrRC $previewNumberVersion
|
|
Return [IO.Path]::Combine($prefixFolder, "preview", $previewOrRCFolderName, $apiDiffFolderName)
|
|
}
|
|
|
|
Function RunApiDiff {
|
|
Param (
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$apiDiffExe
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$outputFolder
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$beforeFolder
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$afterFolder
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$tableOfContentsFileNamePrefix
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$assembliesToExclude
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$attributesToExclude
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$beforeFriendlyName
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$afterFriendlyName
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[string]
|
|
$beforeReferenceFolder = ""
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[string]
|
|
$afterReferenceFolder = ""
|
|
)
|
|
|
|
VerifyPathOrExit $apiDiffExe
|
|
VerifyPathOrExit $beforeFolder
|
|
VerifyPathOrExit $afterFolder
|
|
|
|
$referenceParams = ""
|
|
if (-not [string]::IsNullOrEmpty($beforeReferenceFolder) -and -not [string]::IsNullOrEmpty($afterReferenceFolder)) {
|
|
VerifyPathOrExit $beforeReferenceFolder
|
|
VerifyPathOrExit $afterReferenceFolder
|
|
$referenceParams = " -rb '$beforeReferenceFolder' -ra '$afterReferenceFolder'"
|
|
}
|
|
|
|
RunCommand "$apiDiffExe -b '$beforeFolder' -a '$afterFolder' -o '$outputFolder' -tc '$tableOfContentsFileNamePrefix' -eas '$assembliesToExclude' -eattrs '$attributesToExclude' -bfn '$beforeFriendlyName' -afn '$afterFriendlyName'$referenceParams"
|
|
}
|
|
|
|
Function CreateReadme {
|
|
Param (
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$previewFolderPath
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$dotNetFriendlyName
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$dotNetFullName
|
|
)
|
|
|
|
$readmePath = [IO.Path]::Combine($previewFolderPath, "README.md")
|
|
If (Test-Path -Path $readmePath) {
|
|
Remove-Item -Path $readmePath
|
|
}
|
|
New-Item -ItemType File $readmePath
|
|
|
|
Add-Content $readmePath "# $dotNetFriendlyName API Changes"
|
|
Add-Content $readmePath ""
|
|
Add-Content $readmePath "The following API changes were made in $($dotNetFriendlyName):"
|
|
Add-Content $readmePath ""
|
|
Add-Content $readmePath "- [Microsoft.NETCore.App](./Microsoft.NETCore.App/$dotNetFullName.md)"
|
|
Add-Content $readmePath "- [Microsoft.AspNetCore.App](./Microsoft.AspNetCore.App/$dotNetFullName.md)"
|
|
Add-Content $readmePath "- [Microsoft.WindowsDesktop.App](./Microsoft.WindowsDesktop.App/$dotNetFullName.md)"
|
|
}
|
|
|
|
Function GetAuthHeadersForFeed {
|
|
Param (
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$feedUrl
|
|
)
|
|
|
|
# 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-Host "Using Azure CLI authentication for internal Azure DevOps feed" -ForegroundColor Cyan
|
|
return @{
|
|
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 @{}
|
|
}
|
|
|
|
Function RebuildIfExeNotFound {
|
|
Param (
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$exePath
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$projectPath
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$artifactsPath
|
|
)
|
|
|
|
VerifyPathOrExit $projectPath
|
|
|
|
If (-Not (Test-Path -Path $exePath)) {
|
|
# Building the project
|
|
|
|
Write-Color cyan "Building project '$projectPath'"
|
|
RunCommand "$SdkRepo/.dotnet/dotnet build -c release $projectPath"
|
|
|
|
# Verifying expected output from building
|
|
VerifyPathOrExit $artifactsPath
|
|
VerifyPathOrExit $exePath
|
|
}
|
|
}
|
|
|
|
Function DownloadPackage {
|
|
Param
|
|
(
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$nuGetFeed
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateSet("NETCore", "AspNetCore", "WindowsDesktop")]
|
|
[string]
|
|
$sdkName
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateSet("Before", "After")]
|
|
[string]
|
|
$beforeOrAfter
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidatePattern("\d+\.\d")]
|
|
[string]
|
|
$dotNetVersion
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateSet("preview", "rc", "ga")]
|
|
[string]
|
|
$previewOrRC
|
|
,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidatePattern("(\d+)?")]
|
|
[string]
|
|
$previewNumberVersion
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[string]
|
|
$version = ""
|
|
,
|
|
[ref]
|
|
$resultingPath
|
|
)
|
|
|
|
$fullSdkName = "Microsoft.$sdkName.App"
|
|
$destinationFolder = [IO.Path]::Combine($TmpFolder, "$fullSdkName.$beforeOrAfter")
|
|
RecreateFolder $destinationFolder
|
|
|
|
$refPackageName = "$fullSdkName.Ref"
|
|
|
|
# If exact version is provided, use it directly
|
|
If (-Not ([System.String]::IsNullOrWhiteSpace($version))) {
|
|
Write-Color cyan "Using exact package version: $version"
|
|
}
|
|
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*"
|
|
}
|
|
|
|
# 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
|
|
}
|
|
|
|
$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 = $matchingVersions[0].version
|
|
}
|
|
|
|
$nupkgFile = [IO.Path]::Combine($TmpFolder, "$refPackageName.$version.nupkg")
|
|
|
|
If (-Not(Test-Path -Path $nupkgFile)) {
|
|
# 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'..."
|
|
|
|
# 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 {
|
|
Write-Color green "File '$nupkgFile' already exists locally. Skipping re-download."
|
|
}
|
|
|
|
Expand-Archive -Path $nupkgFile -DestinationPath $destinationFolder -ErrorAction Stop
|
|
|
|
$dllPath = [IO.Path]::Combine($destinationFolder, "ref", "net$dotNetVersion")
|
|
VerifyPathOrExit $dllPath
|
|
VerifyCountDlls $dllPath
|
|
$resultingPath.value = $dllPath
|
|
}
|
|
|
|
Function ProcessSdk
|
|
{
|
|
Param(
|
|
[Parameter(Mandatory = $false)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$sdkName
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$previousNuGetFeed
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$currentNuGetFeed
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$apiDiffExe
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$currentDotNetFullName
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$assembliesToExclude
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$attributesToExclude
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$previousDotNetFriendlyName
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$currentDotNetFriendlyName
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[string]
|
|
$previousVersion = ""
|
|
,
|
|
[Parameter(Mandatory = $false)]
|
|
[string]
|
|
$currentVersion = ""
|
|
)
|
|
|
|
$beforeDllFolder = ""
|
|
DownloadPackage $previousNuGetFeed $sdkName "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion $previousVersion ([ref]$beforeDllFolder)
|
|
VerifyPathOrExit $beforeDllFolder
|
|
|
|
$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 $previousVersion ([ref]$beforeReferenceFolder)
|
|
VerifyPathOrExit $beforeReferenceFolder
|
|
|
|
DownloadPackage $currentNuGetFeed "NETCore" "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $currentVersion ([ref]$afterReferenceFolder)
|
|
VerifyPathOrExit $afterReferenceFolder
|
|
}
|
|
|
|
$targetFolder = [IO.Path]::Combine($previewFolderPath, "Microsoft.$sdkName.App")
|
|
RecreateFolder $targetFolder
|
|
|
|
RunApiDiff $apiDiffExe $targetFolder $beforeDllFolder $afterDllFolder $currentDotNetFullName $assembliesToExclude $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName $beforeReferenceFolder $afterReferenceFolder
|
|
}
|
|
|
|
#####################
|
|
### End Functions ###
|
|
#####################
|
|
|
|
#######################
|
|
### Start Execution ###
|
|
#######################
|
|
|
|
if ($PSVersionTable.PSVersion.Major -lt 7) {
|
|
Write-Error "This script requires PowerShell 7.0 or later. See https://aka.ms/PSWindows for instructions." -ErrorAction Stop
|
|
}
|
|
|
|
## Generate strings with no whitespace
|
|
|
|
# True when comparing 8.0 GA with 9.0 GA
|
|
$IsComparingReleases = ($PreviousDotNetVersion -Ne $CurrentDotNetVersion) -And ($PreviousPreviewOrRC -Eq "ga") -And ($CurrentPreviewOrRC -eq "ga")
|
|
|
|
|
|
## Check folders passed as parameters exist
|
|
VerifyPathOrExit $CoreRepo
|
|
VerifyPathOrExit $TmpFolder
|
|
|
|
$currentMajorVersion = $CurrentDotNetVersion.Split(".")[0]
|
|
$InstallApiDiffCommand = "dotnet tool install --global Microsoft.DotNet.ApiDiff.Tool --source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet$currentMajorVersion-transport/nuget/v3/index.json --prerelease"
|
|
|
|
if ($InstallApiDiff) {
|
|
Write-Color white "Installing ApiDiff tool..."
|
|
RunCommand $InstallApiDiffCommand
|
|
}
|
|
|
|
$apiDiffCommand = get-command "apidiff" -ErrorAction SilentlyContinue
|
|
|
|
if (-Not $apiDiffCommand)
|
|
{
|
|
Write-Error "The command apidiff could not be found. Please first install the tool using the following command: $InstallApiDiffCommand" -ErrorAction Stop
|
|
}
|
|
|
|
$apiDiffExe = $apiDiffCommand.Source
|
|
## Recreate api-diff folder in core repo folder
|
|
|
|
$previewFolderPath = GetPreviewFolderPath $CoreRepo $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $IsComparingReleases
|
|
If (-Not (Test-Path -Path $previewFolderPath))
|
|
{
|
|
Write-Color white "Creating new diff folder: $previewFolderPath"
|
|
New-Item -ItemType Directory -Path $previewFolderPath
|
|
}
|
|
|
|
## Run the ApiDiff commands
|
|
|
|
# Example: "10.0-preview2"
|
|
$currentDotNetFullName = GetDotNetFullName $IsComparingReleases $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion
|
|
|
|
# Examples: ".NET 10 Preview 1" and ".NET 10 Preview 2"
|
|
$previousDotNetFriendlyName = GetDotNetFriendlyName $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion
|
|
$currentDotNetFriendlyName = GetDotNetFriendlyName $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion
|
|
|
|
If (-Not $ExcludeNetCore)
|
|
{
|
|
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 $PreviousPackageVersion $CurrentPackageVersion
|
|
}
|
|
|
|
If (-Not $ExcludeWindowsDesktop)
|
|
{
|
|
ProcessSdk "WindowsDesktop" $PreviousNuGetFeed $CurrentNuGetFeed $apiDiffExe $currentDotNetFullName $AssembliesToExcludeFilePath $AttributesToExcludeFilePath $previousDotNetFriendlyName $currentDotNetFriendlyName $PreviousPackageVersion $CurrentPackageVersion
|
|
}
|
|
|
|
CreateReadme $previewFolderPath $currentDotNetFriendlyName $currentDotNetFullName
|
|
|
|
#####################
|
|
### End Execution ###
|
|
##################### |