diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 7fb2e4bed..71ea17deb 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -54,6 +54,7 @@ extends: binskim: break: false scanOutputDirectoryOnly: true + stages: # ── Compute Version ── # A single version string is computed once and shared across all stages. @@ -143,7 +144,7 @@ extends: - job: flc_win_arm64 displayName: 'win-arm64' pool: - name: onnxruntime-Win-CPU-2022 + name: onnxruntime-native-arm64-16core os: windows templateContext: outputs: @@ -674,6 +675,32 @@ extends: flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-standard' + - job: test_cs_win_arm64 + displayName: 'win-arm64' + pool: + name: onnxruntime-native-arm64-16core + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + - input: pipelineArtifact + artifactName: 'deps-versions-standard' + targetPath: '$(Pipeline.Workspace)/deps-versions-standard' + steps: + - checkout: self + clean: true + - template: .pipelines/templates/checkout-steps.yml@self + parameters: + repoName: test-data-shared + basePath: '$(Agent.BuildDirectory)' + - template: .pipelines/templates/test-cs-steps.yml@self + parameters: + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-standard' + - job: test_cs_linux_x64 displayName: 'linux-x64' pool: @@ -761,6 +788,32 @@ extends: flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-standard' + - job: test_js_win_arm64 + displayName: 'win-arm64' + pool: + name: onnxruntime-native-arm64-16core + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + - input: pipelineArtifact + artifactName: 'deps-versions-standard' + targetPath: '$(Pipeline.Workspace)/deps-versions-standard' + steps: + - checkout: self + clean: true + - template: .pipelines/templates/checkout-steps.yml@self + parameters: + repoName: test-data-shared + basePath: '$(Agent.BuildDirectory)' + - template: .pipelines/templates/test-js-steps.yml@self + parameters: + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-standard' + - job: test_js_linux_x64 displayName: 'linux-x64' pool: @@ -851,6 +904,36 @@ extends: sdkWheelsDir: '$(Pipeline.Workspace)/python-sdk' depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-standard' + - job: test_python_win_arm64 + displayName: 'win-arm64' + pool: + name: onnxruntime-native-arm64-16core + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-wheels' + targetPath: '$(Pipeline.Workspace)/flc-wheels' + - input: pipelineArtifact + artifactName: 'python-sdk' + targetPath: '$(Pipeline.Workspace)/python-sdk' + - input: pipelineArtifact + artifactName: 'deps-versions-standard' + targetPath: '$(Pipeline.Workspace)/deps-versions-standard' + steps: + - checkout: self + clean: true + - template: .pipelines/templates/checkout-steps.yml@self + parameters: + repoName: test-data-shared + basePath: '$(Agent.BuildDirectory)' + - template: .pipelines/templates/test-python-steps.yml@self + parameters: + isWinML: false + flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' + sdkWheelsDir: '$(Pipeline.Workspace)/python-sdk' + depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-standard' + - job: test_python_linux_x64 displayName: 'linux-x64' pool: @@ -945,6 +1028,32 @@ extends: flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-standard' + - job: test_rust_win_arm64 + displayName: 'win-arm64' + pool: + name: onnxruntime-native-arm64-16core + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + - input: pipelineArtifact + artifactName: 'deps-versions-standard' + targetPath: '$(Pipeline.Workspace)/deps-versions-standard' + steps: + - checkout: self + clean: true + - template: .pipelines/templates/checkout-steps.yml@self + parameters: + repoName: test-data-shared + basePath: '$(Agent.BuildDirectory)' + - template: .pipelines/templates/test-rust-steps.yml@self + parameters: + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-standard' + - job: test_rust_linux_x64 displayName: 'linux-x64' pool: @@ -1032,7 +1141,7 @@ extends: - job: flc_winml_win_arm64 displayName: 'win-arm64 (WinML)' pool: - name: onnxruntime-Win-CPU-2022 + name: onnxruntime-native-arm64-16core os: windows templateContext: outputs: @@ -1311,6 +1420,32 @@ extends: flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-winml' + - job: test_cs_winml_win_arm64 + displayName: 'win-arm64' + pool: + name: onnxruntime-native-arm64-16core + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget-winml' + targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' + - input: pipelineArtifact + artifactName: 'deps-versions-winml' + targetPath: '$(Pipeline.Workspace)/deps-versions-winml' + steps: + - checkout: self + clean: true + - template: .pipelines/templates/checkout-steps.yml@self + parameters: + repoName: test-data-shared + basePath: '$(Agent.BuildDirectory)' + - template: .pipelines/templates/test-cs-steps.yml@self + parameters: + isWinML: true + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-winml' + # ── Test JS SDK (WinML) ── - stage: test_js_winml displayName: 'Test JS (WinML)' @@ -1341,6 +1476,32 @@ extends: flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-winml' + - job: test_js_winml_win_arm64 + displayName: 'win-arm64' + pool: + name: onnxruntime-native-arm64-16core + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget-winml' + targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' + - input: pipelineArtifact + artifactName: 'deps-versions-winml' + targetPath: '$(Pipeline.Workspace)/deps-versions-winml' + steps: + - checkout: self + clean: true + - template: .pipelines/templates/checkout-steps.yml@self + parameters: + repoName: test-data-shared + basePath: '$(Agent.BuildDirectory)' + - template: .pipelines/templates/test-js-steps.yml@self + parameters: + isWinML: true + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-winml' + # ── Test Python SDK (WinML) ── - stage: test_python_winml displayName: 'Test Python (WinML)' @@ -1374,3 +1535,33 @@ extends: flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels-winml' sdkWheelsDir: '$(Pipeline.Workspace)/python-sdk-winml' depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-winml' + + - job: test_python_winml_win_arm64 + displayName: 'win-arm64' + pool: + name: onnxruntime-native-arm64-16core + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-wheels-winml' + targetPath: '$(Pipeline.Workspace)/flc-wheels-winml' + - input: pipelineArtifact + artifactName: 'python-sdk-winml' + targetPath: '$(Pipeline.Workspace)/python-sdk-winml' + - input: pipelineArtifact + artifactName: 'deps-versions-winml' + targetPath: '$(Pipeline.Workspace)/deps-versions-winml' + steps: + - checkout: self + clean: true + - template: .pipelines/templates/checkout-steps.yml@self + parameters: + repoName: test-data-shared + basePath: '$(Agent.BuildDirectory)' + - template: .pipelines/templates/test-python-steps.yml@self + parameters: + isWinML: true + flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels-winml' + sdkWheelsDir: '$(Pipeline.Workspace)/python-sdk-winml' + depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-winml' diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index c21e0b921..50a6f2cca 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -19,12 +19,36 @@ steps: $nsRoot = "$(Build.SourcesDirectory)/neutron-server" Write-Host "##vso[task.setvariable variable=nsRoot]$nsRoot" -- task: UseDotNet@2 - displayName: 'Use .NET SDK from global.json' - inputs: - packageType: sdk - useGlobalJson: true - workingDirectory: '$(nsRoot)' +# UseDotNet@2 installs x86 on win-arm64 agents and runs under emulation. +# Use dotnet-install.ps1 for win-arm64; UseDotNet@2 for all other platforms. +- ${{ if eq(parameters.flavor, 'win-arm64') }}: + - task: PowerShell@2 + displayName: 'Install .NET SDK (native ARM64)' + inputs: + targetType: inline + script: | + $globalJson = Get-Content "$(nsRoot)/global.json" -Raw | ConvertFrom-Json + $sdkVersion = $globalJson.sdk.version + Write-Host "Installing .NET SDK $sdkVersion for $env:PROCESSOR_ARCHITECTURE" + + $installDir = "$env:AGENT_TOOLSDIRECTORY/dotnet" + $scriptUrl = "https://dot.net/v1/dotnet-install.ps1" + $scriptPath = "$env:TEMP/dotnet-install.ps1" + + Invoke-WebRequest -Uri $scriptUrl -OutFile $scriptPath -UseBasicParsing + & $scriptPath -Version $sdkVersion -InstallDir $installDir -Architecture $env:PROCESSOR_ARCHITECTURE + + # Put it on PATH for subsequent steps + Write-Host "##vso[task.prependpath]$installDir" + Write-Host "Installed: $(& "$installDir/dotnet" --version)" + +- ${{ if ne(parameters.flavor, 'win-arm64') }}: + - task: UseDotNet@2 + displayName: 'Use .NET SDK from global.json' + inputs: + packageType: sdk + useGlobalJson: true + workingDirectory: '$(nsRoot)' - task: PowerShell@2 displayName: 'Override nuget.config' @@ -120,7 +144,7 @@ steps: arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release' # FLC tests on osx-arm64 are flaky in CI, will investigate separately. Skip for now since the main goal of this job is to produce the AOT binary. - - ${{ if or(eq(parameters.flavor, 'win-x64'), eq(parameters.flavor, 'linux-x64')) }}: + - ${{ if or(eq(parameters.flavor, 'win-x64'), eq(parameters.flavor, 'win-arm64'), eq(parameters.flavor, 'linux-x64')) }}: - task: DotNetCoreCLI@2 displayName: 'Restore FLC Tests ${{ parameters.flavor }}' inputs: diff --git a/.pipelines/templates/checkout-steps.yml b/.pipelines/templates/checkout-steps.yml index 601eacf56..e0474c0fa 100644 --- a/.pipelines/templates/checkout-steps.yml +++ b/.pipelines/templates/checkout-steps.yml @@ -17,6 +17,30 @@ parameters: displayName: 'Base directory to clone into (repo will be at basePath/repoName)' steps: +# Install pwsh and Azure CLI on ARM64 agents if missing +- task: PowerShell@2 + displayName: 'Install prerequisites (ARM64)' + condition: and(eq(variables['Agent.OSArchitecture'], 'ARM64'), eq(variables['Agent.OS'], 'Windows_NT')) + inputs: + targetType: inline + script: | + if (-not (Get-Command pwsh -ErrorAction SilentlyContinue)) { + Write-Host "Installing PowerShell Core..." + $arch = if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { 'arm64' } else { 'x64' } + $msiUrl = "https://github.com/PowerShell/PowerShell/releases/download/v7.4.7/PowerShell-7.4.7-win-${arch}.msi" + Invoke-WebRequest -Uri $msiUrl -OutFile "$env:TEMP\PowerShell.msi" -UseBasicParsing + Start-Process msiexec.exe -Wait -ArgumentList "/i $env:TEMP\PowerShell.msi /quiet /norestart ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL=1 ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL=1 ENABLE_PSREMOTING=0 REGISTER_MANIFEST=1 USE_MU=0 ENABLE_MU=0" + $pwshPath = "$env:ProgramFiles\PowerShell\7" + if (Test-Path $pwshPath) { Write-Host "##vso[task.prependpath]$pwshPath" } + } + if (-not (Get-Command az -ErrorAction SilentlyContinue)) { + Write-Host "Installing Azure CLI..." + Invoke-WebRequest -Uri "https://aka.ms/installazurecliwindowsarm64" -OutFile "$env:TEMP\AzureCLI.msi" -UseBasicParsing + Start-Process msiexec.exe -Wait -ArgumentList "/i $env:TEMP\AzureCLI.msi /quiet /norestart" + $azPath = "$env:ProgramFiles\Microsoft SDKs\Azure\CLI2\wbin" + if (Test-Path $azPath) { Write-Host "##vso[task.prependpath]$azPath" } + } + - task: AzureCLI@2 displayName: 'Checkout ${{ parameters.repoName }}' inputs: