diff --git a/tools/ci_build/github/azure-pipelines/dml-nuget-packaging.yml b/tools/ci_build/github/azure-pipelines/dml-nuget-packaging.yml index 2868963b637a8..3cf28655c36e7 100644 --- a/tools/ci_build/github/azure-pipelines/dml-nuget-packaging.yml +++ b/tools/ci_build/github/azure-pipelines/dml-nuget-packaging.yml @@ -75,9 +75,13 @@ extends: DoNugetPack: 'true' DoEsrp: ${{ parameters.DoEsrp }} NuPackScript: | + python -m pip install setuptools msbuild $(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.proj /p:Configuration=RelWithDebInfo /t:CreatePackage /p:OrtPackageId=Microsoft.ML.OnnxRuntime.DirectML /p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} /p:CurrentData=$(BuildDate) /p:CurrentTime=$(BuildTime) + if errorlevel 1 exit /b 1 copy $(Build.SourcesDirectory)\csharp\src\Microsoft.ML.OnnxRuntime\bin\RelWithDebInfo\*.nupkg $(Build.ArtifactStagingDirectory) - copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\*.nupkg $(Build.ArtifactStagingDirectory) + if errorlevel 1 exit /b 1 + powershell -ExecutionPolicy Bypass -File $(Build.SourcesDirectory)\tools\ci_build\github\windows\select_dml_package.ps1 -SourceDir "$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo" -IsReleaseBuild "${{ parameters.IsReleaseBuild }}" -Action copy -DestinationDir "$(Build.ArtifactStagingDirectory)" + if errorlevel 1 exit /b 1 mkdir $(Build.ArtifactStagingDirectory)\testdata copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\custom_op_library.* $(Build.ArtifactStagingDirectory)\testdata @@ -94,13 +98,16 @@ extends: DoEsrp: ${{ parameters.DoEsrp }} RunTests: 'false' NuPackScript: | + python -m pip install setuptools msbuild $(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.proj /p:Configuration=RelWithDebInfo /p:TargetArchitecture=arm64 /t:CreatePackage /p:OrtPackageId=Microsoft.ML.OnnxRuntime.DirectML /p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} - cd $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\ - ren Microsoft.ML.OnnxRuntime.DirectML.* win-dml-arm64.zip + if errorlevel 1 exit /b 1 + powershell -ExecutionPolicy Bypass -File $(Build.SourcesDirectory)\tools\ci_build\github\windows\select_dml_package.ps1 -SourceDir "$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo" -IsReleaseBuild "${{ parameters.IsReleaseBuild }}" -Action rename -NewName "win-dml-arm64.zip" + if errorlevel 1 exit /b 1 copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\win-dml-arm64.zip $(Build.ArtifactStagingDirectory) + if errorlevel 1 exit /b 1 mkdir $(Build.ArtifactStagingDirectory)\testdata copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\custom_op_library.* $(Build.ArtifactStagingDirectory)\testdata - template: stages/nuget_dml_packaging_stage.yml parameters: - DoEsrp: ${{ parameters.DoEsrp }} \ No newline at end of file + DoEsrp: ${{ parameters.DoEsrp }} diff --git a/tools/ci_build/github/azure-pipelines/templates/validate-package.yml b/tools/ci_build/github/azure-pipelines/templates/validate-package.yml index 529cca4586ef6..950a5a6a34f4d 100644 --- a/tools/ci_build/github/azure-pipelines/templates/validate-package.yml +++ b/tools/ci_build/github/azure-pipelines/templates/validate-package.yml @@ -4,6 +4,7 @@ parameters: PackageType: '' PackageName: '' PackagePath: '' + IsReleaseBuild: false ScriptPath: '$(Build.SourcesDirectory)/tools/nuget/validate_package.py' workingDirectory: "$(Build.BinariesDirectory)" @@ -17,5 +18,5 @@ steps: displayName: 'Validate Package' inputs: scriptPath: '${{parameters.ScriptPath}}' - arguments: '--package_type ${{parameters.PackageType}} --package_name ${{parameters.PackageName}} --package_path ${{parameters.PackagePath}} --platforms_supported ${{parameters.PlatformsSupported}} --verify_nuget_signing ${{parameters.VerifyNugetSigning}}' + arguments: '--package_type ${{parameters.PackageType}} --package_name ${{parameters.PackageName}} --package_path ${{parameters.PackagePath}} --platforms_supported ${{parameters.PlatformsSupported}} --verify_nuget_signing ${{parameters.VerifyNugetSigning}} --is_release_build ${{parameters.IsReleaseBuild}}' workingDirectory: ${{parameters.workingDirectory}} diff --git a/tools/ci_build/github/windows/bundle_dml_package.ps1 b/tools/ci_build/github/windows/bundle_dml_package.ps1 index ef7f781096b25..36088e772bf2d 100644 --- a/tools/ci_build/github/windows/bundle_dml_package.ps1 +++ b/tools/ci_build/github/windows/bundle_dml_package.ps1 @@ -27,17 +27,27 @@ $arm64ExtractPath = "win-dml-arm64-unzipped" Write-Host "Extracting $arm64ZipFile to $arm64ExtractPath..." & $sevenZipPath x $arm64ZipFile -o"$arm64ExtractPath" -y +# Debug: List contents of extracted arm64 zip +Write-Host "Contents of $arm64ExtractPath (recursive):" +Get-ChildItem -Path $arm64ExtractPath -Recurse | ForEach-Object { Write-Host " - $($_.FullName)" } + # 2. Find the target NuGet package. # It finds all .nupkg files that do not contain "Managed" in their name. -$nupkgFiles = Get-ChildItem -Path . -Recurse -Filter *.nupkg | Where-Object { $_.Name -notlike "*Managed*" } +$nupkgFiles = Get-ChildItem -Path . -Filter *.nupkg | Where-Object { ($_.Name -notlike "*Managed*") -and ($_.Name -notlike "*.symbols.nupkg") } + +Write-Host "Found $($nupkgFiles.Count) candidate nupkg file(s) for bundling:" +$nupkgFiles | ForEach-Object { Write-Host " - $($_.FullName)" } -# 3. Validate that exactly one package was found. -if ($nupkgFiles.Count -ne 1) { - Write-Error "Error: Expected to find exactly one non-managed NuGet package, but found $($nupkgFiles.Count)." +# 3. Select the best package (shortest name prefers Release over Dev, and Main over Symbols) +if ($nupkgFiles.Count -eq 0) { + Write-Error "Error: No matching NuGet packages found to bundle into." exit 1 } -$nupkg = $nupkgFiles[0] -Write-Host "Found package to process: $($nupkg.Name)" +if ($nupkgFiles.Count -gt 1) { + Write-Warning "Found multiple packages. Selecting the one with the shortest filename as the target for bundling." +} +$nupkg = $nupkgFiles | Sort-Object {$_.Name.Length} | Select-Object -First 1 +Write-Host "Selected target package: $($nupkg.Name)" # 4. Validate the package name matches the expected format. if ($nupkg.Name -notlike "Microsoft.ML.OnnxRuntime.DirectML*.nupkg") { @@ -61,14 +71,36 @@ New-Item -ItemType Directory -Path $tempDir | Out-Null Write-Host "Extracting $($nupkg.Name) to $tempDir..." & $sevenZipPath x $nupkg.FullName -o"$tempDir" -y +# Debug: Print the .nuspec content +$nuspecFile = Get-ChildItem -Path $tempDir -Filter *.nuspec | Select-Object -First 1 +if ($nuspecFile) { + Write-Host "Found manifest: $($nuspecFile.FullName)" + Write-Host "--- Manifest Content ---" + Get-Content $nuspecFile.FullName | ForEach-Object { Write-Host $_ } + Write-Host "------------------------" +} + +# Debug: List contents of extracted target nupkg +Write-Host "Contents of $tempDir (recursive):" +Get-ChildItem -Path $tempDir -Recurse | ForEach-Object { Write-Host " - $($_.FullName)" } + # Step B: Create the new runtime directory structure. $newRuntimePath = Join-Path $tempDir "runtimes\win-arm64\native" +Write-Host "Ensuring destination path exists: $newRuntimePath" New-Item -ItemType Directory -Path $newRuntimePath -Force | Out-Null # Step C: Copy the ARM64 binaries into the new structure. $arm64SourcePath = Join-Path . "$arm64ExtractPath\runtimes\win-arm64\native" -Write-Host "Copying ARM64 binaries from $arm64SourcePath to $newRuntimePath..." -Copy-Item -Path "$arm64SourcePath\*" -Destination $newRuntimePath -Recurse -Force +if (Test-Path $arm64SourcePath) { + Write-Host "Copying ARM64 binaries from $arm64SourcePath to $newRuntimePath..." + $filesToCopy = Get-ChildItem -Path "$arm64SourcePath\*" + Write-Host "Files found in source: $($filesToCopy.Count)" + $filesToCopy | ForEach-Object { Write-Host " -> $($_.Name)" } + Copy-Item -Path "$arm64SourcePath\*" -Destination $newRuntimePath -Recurse -Force +} else { + Write-Error "Error: ARM64 source path not found: $arm64SourcePath. Bailing out to avoid creating a broken package." + exit 1 +} # Step D: Delete the original nupkg file. Remove-Item -Path $nupkg.FullName -Force @@ -79,6 +111,13 @@ Push-Location $tempDir & $sevenZipPath a -tzip "$($nupkg.FullName)" ".\" -r Pop-Location +# Debug: Check final nupkg existence +if (Test-Path $nupkg.FullName) { + Write-Host "Final package created successfully: $($nupkg.FullName)" + $finalSize = (Get-Item $nupkg.FullName).Length + Write-Host "Final package size: $finalSize bytes" +} + # --- Cleanup and Final Steps --- Write-Host "Cleaning up temporary directory $tempDir..." Remove-Item -Recurse -Force $tempDir @@ -91,4 +130,4 @@ Write-Host "Copying final artifact to $ArtifactStagingDirectory..." Copy-Item -Path ".\Microsoft.ML.OnnxRuntime.DirectML*.nupkg" -Destination $ArtifactStagingDirectory -Force Write-Host "---" -Write-Host "Script completed successfully." \ No newline at end of file +Write-Host "Script completed successfully." diff --git a/tools/ci_build/github/windows/select_dml_package.ps1 b/tools/ci_build/github/windows/select_dml_package.ps1 new file mode 100644 index 0000000000000..b6a3ed936ae23 --- /dev/null +++ b/tools/ci_build/github/windows/select_dml_package.ps1 @@ -0,0 +1,86 @@ +# select_dml_package.ps1 +# Helper script to select the correct DML NuGet package based on build type +# Usage: select_dml_package.ps1 -SourceDir -IsReleaseBuild -Action [-DestinationDir ] [-NewName ] + +param( + [Parameter(Mandatory=$true)] + [string]$SourceDir, + + [Parameter(Mandatory=$true)] + [string]$IsReleaseBuild, + + [Parameter(Mandatory=$true)] + [ValidateSet("copy", "rename")] + [string]$Action, + + [Parameter(Mandatory=$false)] + [string]$DestinationDir, + + [Parameter(Mandatory=$false)] + [string]$NewName +) + +$ErrorActionPreference = "Stop" + +Write-Host "Searching for packages in: $SourceDir" +Write-Host "IsReleaseBuild: $IsReleaseBuild" +Write-Host "Action: $Action" + +# Convert string to boolean +$isRelease = [System.Convert]::ToBoolean($IsReleaseBuild) + +# Find all matching packages +$allPackages = Get-ChildItem -Path $SourceDir -Filter "Microsoft.ML.OnnxRuntime.DirectML.*.nupkg" +Write-Host "Found $($allPackages.Count) total package(s):" +$allPackages | ForEach-Object { Write-Host " - $($_.Name)" } + +# Filter packages based on build type +$filteredPackages = $allPackages | Where-Object { + $name = $_.Name + $isSymbols = $name -like "*symbols*" + $isDev = $name -like "*-dev*" + + if ($isSymbols) { + return $false + } + + if ($isRelease) { + return -not $isDev + } else { + return $isDev + } +} + +Write-Host "After filtering (isRelease=$isRelease), found $($filteredPackages.Count) matching package(s):" +$filteredPackages | ForEach-Object { Write-Host " - $($_.Name)" } + +if ($filteredPackages.Count -eq 0) { + Write-Error "No matching package found!" + exit 1 +} + +# Select the first matching package (sorted by name length for consistency) +$selectedPackage = $filteredPackages | Sort-Object { $_.Name.Length } | Select-Object -First 1 +Write-Host "Selected package: $($selectedPackage.FullName)" + +# Perform the action +if ($Action -eq "copy") { + if (-not $DestinationDir) { + Write-Error "DestinationDir is required for copy action" + exit 1 + } + Write-Host "Copying to: $DestinationDir" + Copy-Item -Path $selectedPackage.FullName -Destination $DestinationDir -Force + Write-Host "Copy successful." +} +elseif ($Action -eq "rename") { + if (-not $NewName) { + Write-Error "NewName is required for rename action" + exit 1 + } + Write-Host "Renaming to: $NewName" + Rename-Item -Path $selectedPackage.FullName -NewName $NewName -Force + Write-Host "Rename successful." +} + +exit 0 diff --git a/tools/nuget/validate_package.py b/tools/nuget/validate_package.py index 961109c595ed5..0ad1fc07eafd7 100644 --- a/tools/nuget/validate_package.py +++ b/tools/nuget/validate_package.py @@ -67,6 +67,10 @@ def parse_arguments(): "--verify_nuget_signing", help="Flag indicating if Nuget package signing is to be verified. Only accepts 'true' or 'false'", ) + parser.add_argument( + "--is_release_build", + help="Flag indicating if validating a release build or dev build. Only accepts 'true' or 'false'", + ) return parser.parse_args() @@ -285,7 +289,14 @@ def validate_zip(args): def validate_nuget(args): files = glob.glob(os.path.join(args.package_path, args.package_name)) - nuget_packages_found_in_path = [i for i in files if i.endswith(".nupkg") and "Managed" not in i] + is_release_build = args.is_release_build and args.is_release_build.lower() == "true" + nuget_packages_found_in_path = [ + i + for i in files + if i.endswith(".nupkg") + and "Managed" not in i + and ((is_release_build and "-dev" not in i) or (not is_release_build and "-dev" in i)) + ] if len(nuget_packages_found_in_path) != 1: print("Nuget packages found in path: ") print(nuget_packages_found_in_path)