From 2f2b80c225bea189b4bc28002fa0bbda50399ac7 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Mon, 27 Apr 2026 05:03:41 +0000 Subject: [PATCH 1/5] Update dependencies from https://github.com/dotnet/arcade build 20260425.1 On relative base path root Microsoft.DotNet.Arcade.Sdk From Version 11.0.0-beta.26211.1 -> To Version 11.0.0-beta.26225.1 --- eng/Version.Details.props | 2 +- eng/Version.Details.xml | 4 +- eng/common/core-templates/job/onelocbuild.yml | 3 + .../core-templates/post-build/post-build.yml | 2 +- eng/common/cross/toolchain.cmake | 12 +- eng/common/sdk-task.ps1 | 2 +- eng/common/sdk-task.sh | 2 +- eng/common/tools.ps1 | 130 +++++++++++++++--- eng/common/tools.sh | 122 +++++++++++++--- global.json | 6 +- 10 files changed, 236 insertions(+), 49 deletions(-) diff --git a/eng/Version.Details.props b/eng/Version.Details.props index 5933d2dfe98..7a72d2538a9 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -6,7 +6,7 @@ This file should be imported by eng/Versions.props - 11.0.0-beta.26211.1 + 11.0.0-beta.26225.1 18.6.1 18.6.1 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ed369c7e7ca..4b1fbb2c90a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -76,9 +76,9 @@ - + https://github.com/dotnet/arcade - a08169b890573cfd7f949ea9062c86a4db1aab1b + e822416a9237f26c9a62562fa6ce0f707da1dfe3 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/common/core-templates/job/onelocbuild.yml b/eng/common/core-templates/job/onelocbuild.yml index eefed3b667a..86ea9f63504 100644 --- a/eng/common/core-templates/job/onelocbuild.yml +++ b/eng/common/core-templates/job/onelocbuild.yml @@ -22,6 +22,7 @@ parameters: GitHubOrg: dotnet MirrorRepo: '' MirrorBranch: main + xLocCustomPowerShellScript: '' condition: '' JobNameSuffix: '' is1ESPipeline: '' @@ -97,6 +98,8 @@ jobs: gitHubOrganization: ${{ parameters.GitHubOrg }} mirrorRepo: ${{ parameters.MirrorRepo }} mirrorBranch: ${{ parameters.MirrorBranch }} + ${{ if ne(parameters.xLocCustomPowerShellScript, '') }}: + xLocCustomPowerShellScript: ${{ parameters.xLocCustomPowerShellScript }} condition: ${{ parameters.condition }} # Copy the locProject.json to the root of the Loc directory, then publish a pipeline artifact diff --git a/eng/common/core-templates/post-build/post-build.yml b/eng/common/core-templates/post-build/post-build.yml index fcf40d1d2e6..8aa86e30491 100644 --- a/eng/common/core-templates/post-build/post-build.yml +++ b/eng/common/core-templates/post-build/post-build.yml @@ -225,7 +225,7 @@ stages: displayName: Validate inputs: filePath: eng\common\sdk-task.ps1 - arguments: -task SigningValidation -restore + arguments: -task SigningValidation -restore -msbuildEngine dotnet /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts' /p:SignCheckExclusionsFile='$(System.DefaultWorkingDirectory)/eng/SignCheckExclusionsFile.txt' ${{ parameters.signingValidationAdditionalParameters }} diff --git a/eng/common/cross/toolchain.cmake b/eng/common/cross/toolchain.cmake index ff2dfdb4a5b..99d6dfe82dd 100644 --- a/eng/common/cross/toolchain.cmake +++ b/eng/common/cross/toolchain.cmake @@ -225,13 +225,19 @@ elseif(ILLUMOS) locate_toolchain_exec(g++ CMAKE_CXX_COMPILER) elseif(HAIKU) set(CMAKE_SYSROOT "${CROSS_ROOTFS}") - set(CMAKE_PROGRAM_PATH "${CMAKE_PROGRAM_PATH};${CROSS_ROOTFS}/cross-tools-x86_64/bin") set(CMAKE_SYSTEM_PREFIX_PATH "${CROSS_ROOTFS}") set(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES} -lssp") set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} -lssp") - locate_toolchain_exec(gcc CMAKE_C_COMPILER) - locate_toolchain_exec(g++ CMAKE_CXX_COMPILER) + if ($ENV{CCC_CC} MATCHES ".*gcc.*") + set(CMAKE_PROGRAM_PATH "${CMAKE_PROGRAM_PATH};${CROSS_ROOTFS}/cross-tools-x86_64/bin") + locate_toolchain_exec(gcc CMAKE_C_COMPILER) + locate_toolchain_exec(g++ CMAKE_CXX_COMPILER) + else() + set(CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN "${CROSS_ROOTFS}/cross-tools-x86_64") + set(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN "${CROSS_ROOTFS}/cross-tools-x86_64") + set(CMAKE_ASM_COMPILER_EXTERNAL_TOOLCHAIN "${CROSS_ROOTFS}/cross-tools-x86_64") + endif() # let CMake set up the correct search paths include(Platform/Haiku) diff --git a/eng/common/sdk-task.ps1 b/eng/common/sdk-task.ps1 index 64fd2f8abec..68119de603e 100644 --- a/eng/common/sdk-task.ps1 +++ b/eng/common/sdk-task.ps1 @@ -22,7 +22,7 @@ $warnAsError = if ($noWarnAsError) { $false } else { $true } function Print-Usage() { Write-Host "Common settings:" - Write-Host " -task Name of Arcade task (name of a project in SdkTasks directory of the Arcade SDK package)" + Write-Host " -task Name of Arcade task (name of a project in toolset directory of the Arcade SDK package)" Write-Host " -restore Restore dependencies" Write-Host " -verbosity Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]" Write-Host " -help Print help and exit" diff --git a/eng/common/sdk-task.sh b/eng/common/sdk-task.sh index 3270f83fa9a..1cf71bb2aea 100644 --- a/eng/common/sdk-task.sh +++ b/eng/common/sdk-task.sh @@ -2,7 +2,7 @@ show_usage() { echo "Common settings:" - echo " --task Name of Arcade task (name of a project in SdkTasks directory of the Arcade SDK package)" + echo " --task Name of Arcade task (name of a project in toolset directory of the Arcade SDK package)" echo " --restore Restore dependencies" echo " --verbosity Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]" echo " --help Print help and exit" diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index e28db6c7c8f..b5d13be7aef 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -168,6 +168,12 @@ function InitializeDotNetCli([bool]$install, [bool]$createSdkLocationFile) { $env:DOTNET_CLI_TELEMETRY_OPTOUT=1 } + # Keep repo builds isolated from machine-installed SDK state and workload advertising. + # This avoids preview SDK builds picking up mismatched workloads on CI images. + $env:DOTNET_MULTILEVEL_LOOKUP = '0' + $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = '1' + $env:DOTNET_CLI_WORKLOAD_UPDATE_NOTIFY_DISABLE = '1' + # Find the first path on %PATH% that contains the dotnet.exe if ($useInstalledDotNetCli -and (-not $globalJsonHasRuntimes) -and ($env:DOTNET_INSTALL_DIR -eq $null)) { $dotnetExecutable = GetExecutableFileName 'dotnet' @@ -230,6 +236,9 @@ function InitializeDotNetCli([bool]$install, [bool]$createSdkLocationFile) { Write-PipelinePrependPath -Path $dotnetRoot Write-PipelineSetVariable -Name 'DOTNET_NOLOGO' -Value '1' + Write-PipelineSetVariable -Name 'DOTNET_MULTILEVEL_LOOKUP' -Value '0' + Write-PipelineSetVariable -Name 'DOTNET_SKIP_FIRST_TIME_EXPERIENCE' -Value '1' + Write-PipelineSetVariable -Name 'DOTNET_CLI_WORKLOAD_UPDATE_NOTIFY_DISABLE' -Value '1' return $global:_DotNetInstallDir = $dotnetRoot } @@ -480,7 +489,6 @@ function LocateVisualStudio([object]$vsRequirements = $null){ if (Get-Member -InputObject $GlobalJson.tools -Name 'vswhere') { $vswhereVersion = $GlobalJson.tools.vswhere } else { - # keep this in sync with the VSWhereVersion in DefaultVersions.props $vswhereVersion = '3.1.7' } @@ -615,7 +623,17 @@ function GetNuGetPackageCachePath() { # Returns a full path to an Arcade SDK task project file. function GetSdkTaskProject([string]$taskName) { - return Join-Path (Split-Path (InitializeToolset) -Parent) "SdkTasks\$taskName.proj" + $toolsetDir = Split-Path (InitializeToolset) -Parent + $proj = Join-Path $toolsetDir "$taskName.proj" + if (Test-Path $proj) { + return $proj + } + # TODO: Remove this fallback once all supported versions use the new layout. + $legacyProj = Join-Path $toolsetDir "SdkTasks\$taskName.proj" + if (Test-Path $legacyProj) { + return $legacyProj + } + throw "Unable to find $taskName.proj in toolset at: $toolsetDir" } function InitializeNativeTools() { @@ -652,13 +670,18 @@ function InitializeToolset() { $nugetCache = GetNuGetPackageCachePath $toolsetVersion = Read-ArcadeSdkVersion - $toolsetLocationFile = Join-Path $ToolsetDir "$toolsetVersion.txt" + $toolsetToolsDir = Join-Path $ToolsetDir $toolsetVersion - if (Test-Path $toolsetLocationFile) { - $path = Get-Content $toolsetLocationFile -TotalCount 1 - if (Test-Path $path) { - return $global:_InitializeToolset = $path - } + # Check if the toolset has already been extracted + $toolsetBuildProj = $null + $buildProjPath = Join-Path $toolsetToolsDir 'Build.proj' + + if (Test-Path $buildProjPath) { + $toolsetBuildProj = $buildProjPath + } + + if ($toolsetBuildProj -ne $null) { + return $global:_InitializeToolset = $toolsetBuildProj } if (-not $restore) { @@ -666,21 +689,50 @@ function InitializeToolset() { ExitWithExitCode 1 } - $buildTool = InitializeBuildTool + $downloadArgs = @("package", "download", "Microsoft.DotNet.Arcade.Sdk@$toolsetVersion", "--verbosity", "minimal", "--prerelease", "--output", "$nugetCache") + $nugetConfig = $env:NUGET_CONFIG + if (-not $nugetConfig) { + # Search for any variation of nuget.config in the RepoRoot + $configFile = Get-ChildItem -Path $RepoRoot -File | Where-Object { $_.Name -ieq "nuget.config" } | Select-Object -First 1 - $proj = Join-Path $ToolsetDir 'restore.proj' - $bl = if ($binaryLog) { '/bl:' + (Join-Path $LogDir 'ToolsetRestore.binlog') } else { '' } + if ($configFile) { + $nugetConfig = $configFile.FullName + } + } - '' | Set-Content $proj + if ($nugetConfig) { + $downloadArgs += "--configfile" + $downloadArgs += $nugetConfig + } + DotNet @downloadArgs - MSBuild-Core $proj $bl /t:__WriteToolsetLocation /clp:ErrorsOnly`;NoSummary /p:__ToolsetLocationOutputFile=$toolsetLocationFile + $packageDir = Join-Path $nugetCache (Join-Path 'microsoft.dotnet.arcade.sdk' $toolsetVersion) + $packageToolsetDir = Join-Path $packageDir 'toolset' + $packageToolsDir = Join-Path $packageDir 'tools' - $path = Get-Content $toolsetLocationFile -Encoding UTF8 -TotalCount 1 - if (!(Test-Path $path)) { - throw "Invalid toolset path: $path" + # TODO: Remove the tools/ check once all supported versions have the toolset folder. + if (!(Test-Path $packageToolsetDir) -and !(Test-Path $packageToolsDir)) { + Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Arcade SDK package does not contain a toolset or tools folder: $packageDir" + ExitWithExitCode 3 } - return $global:_InitializeToolset = $path + New-Item -ItemType Directory -Path $toolsetToolsDir -Force | Out-Null + + # Copy toolset if present at the package root (new layout), otherwise fall back to tools + if (Test-Path $packageToolsetDir) { + Copy-Item -Path "$packageToolsetDir\*" -Destination $toolsetToolsDir -Recurse -Force + } else { + # TODO: Remove this fallback once all supported versions have the toolset folder. + Copy-Item -Path "$packageToolsDir\*" -Destination $toolsetToolsDir -Recurse -Force + } + + if (Test-Path $buildProjPath) { + $toolsetBuildProj = $buildProjPath + } else { + throw "Unable to find Build.proj in toolset at: $toolsetToolsDir" + } + + return $global:_InitializeToolset = $toolsetBuildProj } function ExitWithExitCode([int] $exitCode) { @@ -741,6 +793,40 @@ function MSBuild() { MSBuild-Core @args } +# +# Executes a dotnet command with arguments passed to the function. +# Terminates the script if the command fails. +# +function DotNet() { + $dotnetRoot = InitializeDotNetCli -install:$restore + $dotnetPath = Join-Path $dotnetRoot (GetExecutableFileName 'dotnet') + + $cmdArgs = "" + foreach ($arg in $args) { + if ($null -ne $arg -and $arg.Trim() -ne "") { + if ($arg.EndsWith('\')) { + $arg = $arg + "\" + } + $cmdArgs += " `"$arg`"" + } + } + + $env:ARCADE_BUILD_TOOL_COMMAND = "`"$dotnetPath`" $cmdArgs" + + $exitCode = Exec-Process $dotnetPath $cmdArgs + + if ($exitCode -ne 0) { + Write-Host "dotnet command failed with exit code $exitCode. Check errors above." -ForegroundColor Red + + if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null -and !$fromVMR) { + Write-PipelineSetResult -Result "Failed" -Message "dotnet command execution failed." + ExitWithExitCode 0 + } else { + ExitWithExitCode $exitCode + } + } +} + # # Executes msbuild (or 'dotnet msbuild') with arguments passed to the function. # The arguments are automatically quoted. @@ -765,6 +851,10 @@ function MSBuild-Core() { $cmdArgs = "$($buildTool.Command) /m /nologo /clp:Summary /v:$verbosity /nr:$nodeReuse /p:ContinuousIntegrationBuild=$ci" + if ($ci -and $buildTool.Tool -eq 'dotnet') { + $cmdArgs += ' /p:MSBuildEnableWorkloadResolver=false' + } + # Add -mt flag for MSBuild multithreaded mode if enabled via environment variable if ($env:MSBUILD_MT_ENABLED -eq "1") { $cmdArgs += ' -mt' @@ -875,6 +965,12 @@ Create-Directory $ToolsetDir Create-Directory $TempDir Create-Directory $LogDir +# Direct MSBuild crash diagnostics (MSB4166 failure.txt files) to a known location +# under artifacts/log so they are captured as build artifacts in CI. +if (-not $env:MSBUILDDEBUGPATH) { + $env:MSBUILDDEBUGPATH = Join-Path $LogDir 'MsbuildDebugLogs' +} + Write-PipelineSetVariable -Name 'Artifacts' -Value $ArtifactsDir Write-PipelineSetVariable -Name 'Artifacts.Toolset' -Value $ToolsetDir Write-PipelineSetVariable -Name 'Artifacts.Log' -Value $LogDir diff --git a/eng/common/tools.sh b/eng/common/tools.sh index 1e37fd95b21..c0f0b13cbee 100755 --- a/eng/common/tools.sh +++ b/eng/common/tools.sh @@ -126,6 +126,12 @@ function InitializeDotNetCli { export DOTNET_CLI_TELEMETRY_OPTOUT=1 fi + # Keep repo builds isolated from machine-installed SDK state and workload advertising. + # This avoids preview SDK builds picking up mismatched workloads on CI images. + export DOTNET_MULTILEVEL_LOOKUP=0 + export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 + export DOTNET_CLI_WORKLOAD_UPDATE_NOTIFY_DISABLE=1 + # LTTNG is the logging infrastructure used by Core CLR. Need this variable set # so it doesn't output warnings to the console. export LTTNG_HOME="$HOME" @@ -171,6 +177,9 @@ function InitializeDotNetCli { Write-PipelinePrependPath -path "$dotnet_root" Write-PipelineSetVariable -name "DOTNET_NOLOGO" -value "1" + Write-PipelineSetVariable -name "DOTNET_MULTILEVEL_LOOKUP" -value "0" + Write-PipelineSetVariable -name "DOTNET_SKIP_FIRST_TIME_EXPERIENCE" -value "1" + Write-PipelineSetVariable -name "DOTNET_CLI_WORKLOAD_UPDATE_NOTIFY_DISABLE" -value "1" # return value _InitializeDotNetCli="$dotnet_root" @@ -411,15 +420,18 @@ function InitializeToolset { ReadGlobalVersion "Microsoft.DotNet.Arcade.Sdk" local toolset_version=$_ReadGlobalVersion - local toolset_location_file="$toolset_dir/$toolset_version.txt" + local toolset_tools_dir="$toolset_dir/$toolset_version" - if [[ -a "$toolset_location_file" ]]; then - local path=`cat "$toolset_location_file"` - if [[ -a "$path" ]]; then - # return value - _InitializeToolset="$path" - return - fi + # Check if the toolset has already been extracted + local toolset_build_proj="" + if [[ -a "$toolset_tools_dir/Build.proj" ]]; then + toolset_build_proj="$toolset_tools_dir/Build.proj" + fi + + if [[ -n "$toolset_build_proj" ]]; then + # return value + _InitializeToolset="$toolset_build_proj" + return fi if [[ "$restore" != true ]]; then @@ -427,20 +439,45 @@ function InitializeToolset { ExitWithExitCode 2 fi - local proj="$toolset_dir/restore.proj" + local download_args=("package" "download" "Microsoft.DotNet.Arcade.Sdk@$toolset_version" "--verbosity" "minimal" "--prerelease" "--output" "$_GetNuGetPackageCachePath") + local nuget_config="${NUGET_CONFIG:-}" + if [[ -z "$nuget_config" ]]; then + # Search for any variation of nuget.config in the RepoRoot + local found_config + found_config=$(find "$repo_root" -maxdepth 1 -type f -iname "nuget.config" -print -quit) - local bl="" - if [[ "$binary_log" == true ]]; then - bl="/bl:$log_dir/ToolsetRestore.binlog" + if [[ -n "$found_config" ]]; then + nuget_config="$found_config" + fi fi - echo '' > "$proj" - MSBuild-Core "$proj" $bl /t:__WriteToolsetLocation /clp:ErrorsOnly\;NoSummary /p:__ToolsetLocationOutputFile="$toolset_location_file" + if [[ -n "$nuget_config" ]]; then + download_args+=("--configfile" "$nuget_config") + fi + DotNet "${download_args[@]}" - local toolset_build_proj=`cat "$toolset_location_file"` + local package_dir="$_GetNuGetPackageCachePath/microsoft.dotnet.arcade.sdk/$toolset_version" - if [[ ! -a "$toolset_build_proj" ]]; then - Write-PipelineTelemetryError -category 'Build' "Invalid toolset path: $toolset_build_proj" + # TODO: Remove the tools/ check once all supported versions have the toolset folder. + if [[ ! -d "$package_dir/toolset" && ! -d "$package_dir/tools" ]]; then + Write-PipelineTelemetryError -category 'InitializeToolset' "Arcade SDK package does not contain a toolset or tools folder: $package_dir" + ExitWithExitCode 3 + fi + + mkdir -p "$toolset_tools_dir" + + # Copy toolset if present at the package root (new layout), otherwise fall back to tools + if [[ -d "$package_dir/toolset" ]]; then + cp -r "$package_dir/toolset/." "$toolset_tools_dir" + else + # TODO: Remove this fallback once all supported versions have the toolset folder. + cp -r "$package_dir/tools/." "$toolset_tools_dir" + fi + + if [[ -a "$toolset_tools_dir/Build.proj" ]]; then + toolset_build_proj="$toolset_tools_dir/Build.proj" + else + Write-PipelineTelemetryError -category 'Build' "Unable to find Build.proj in toolset at: $toolset_tools_dir" ExitWithExitCode 3 fi @@ -462,6 +499,26 @@ function StopProcesses { return 0 } +function DotNet { + InitializeDotNetCli $restore + + local dotnet_path="$_InitializeDotNetCli/dotnet" + + export ARCADE_BUILD_TOOL_COMMAND="$dotnet_path $@" + + "$dotnet_path" "$@" || { + local exit_code=$? + echo "dotnet command failed with exit code $exit_code. Check errors above." + + if [[ "$ci" == true && -n ${SYSTEM_TEAMPROJECT:-} && "$from_vmr" != true ]]; then + Write-PipelineSetResult -result "Failed" -message "dotnet command execution failed." + ExitWithExitCode 0 + else + ExitWithExitCode $exit_code + fi + } +} + function MSBuild { local args=( "$@" ) if [[ "$pipelines_log" == true ]]; then @@ -542,7 +599,12 @@ function MSBuild-Core { warnnotaserror_switch="/warnnotaserror:$warn_not_as_error /p:AdditionalWarningsNotAsErrors=$warn_not_as_error" fi - RunBuildTool "$_InitializeBuildToolCommand" /m /nologo /clp:Summary /v:$verbosity /nr:$node_reuse $warnaserror_switch $mt_switch $warnnotaserror_switch /p:TreatWarningsAsErrors=$warn_as_error /p:ContinuousIntegrationBuild=$ci "$@" + local workload_resolver_switch="" + if [[ "$ci" == true && -n "${_InitializeBuildToolCommand:-}" ]]; then + workload_resolver_switch="/p:MSBuildEnableWorkloadResolver=false" + fi + + RunBuildTool "$_InitializeBuildToolCommand" /m /nologo /clp:Summary /v:$verbosity /nr:$node_reuse $warnaserror_switch $mt_switch $warnnotaserror_switch $workload_resolver_switch /p:TreatWarningsAsErrors=$warn_as_error /p:ContinuousIntegrationBuild=$ci "$@" } function GetDarc { @@ -559,8 +621,22 @@ function GetDarc { # Returns a full path to an Arcade SDK task project file. function GetSdkTaskProject { - taskName=$1 - echo "$(dirname $_InitializeToolset)/SdkTasks/$taskName.proj" + local taskName=$1 + local toolsetDir + toolsetDir="$(dirname "$_InitializeToolset")" + local proj="$toolsetDir/$taskName.proj" + if [[ -a "$proj" ]]; then + echo "$proj" + return + fi + # TODO: Remove this fallback once all supported versions use the new layout. + local legacyProj="$toolsetDir/SdkTasks/$taskName.proj" + if [[ -a "$legacyProj" ]]; then + echo "$legacyProj" + return + fi + Write-PipelineTelemetryError -category 'Build' "Unable to find $taskName.proj in toolset at: $toolsetDir" + ExitWithExitCode 3 } ResolvePath "${BASH_SOURCE[0]}" @@ -598,6 +674,12 @@ mkdir -p "$toolset_dir" mkdir -p "$temp_dir" mkdir -p "$log_dir" +# Direct MSBuild crash diagnostics (MSB4166 failure.txt files) to a known location +# under artifacts/log so they are captured as build artifacts in CI. +if [[ -z "${MSBUILDDEBUGPATH:-}" ]]; then + export MSBUILDDEBUGPATH="$log_dir/MsbuildDebugLogs" +fi + Write-PipelineSetVariable -name "Artifacts" -value "$artifacts_dir" Write-PipelineSetVariable -name "Artifacts.Toolset" -value "$toolset_dir" Write-PipelineSetVariable -name "Artifacts.Log" -value "$log_dir" diff --git a/global.json b/global.json index ab623d776cd..3c4b9b1a809 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "11.0.100-preview.3.26170.106", + "version": "11.0.100-preview.4.26210.111", "allowPrerelease": true, "paths": [ ".dotnet", @@ -12,7 +12,7 @@ "runner": "Microsoft.Testing.Platform" }, "tools": { - "dotnet": "11.0.100-preview.3.26170.106", + "dotnet": "11.0.100-preview.4.26210.111", "vs": { "version": "18.0", "components": [ @@ -22,7 +22,7 @@ "xcopy-msbuild": "18.0.0" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "11.0.0-beta.26211.1", + "Microsoft.DotNet.Arcade.Sdk": "11.0.0-beta.26225.1", "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23255.2" } } From cc8f7680fc12e911f075cf987956027d0a44c8ab Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 29 Apr 2026 08:33:59 +0200 Subject: [PATCH 2/5] Fix build: replace removed arcade BuildReleasePackages.targets with PackageReference The arcade SDK 11.0.0-beta.26225.1 removed tools/BuildReleasePackages.targets (moved to toolset/). Replace the direct import with a PackageReference to Microsoft.DotNet.NuGetRepack.Tasks, which provides the UsingTask for UpdatePackageVersionTask through its build assets. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Microsoft.FSharp.Compiler.fsproj | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.FSharp.Compiler/Microsoft.FSharp.Compiler.fsproj b/src/Microsoft.FSharp.Compiler/Microsoft.FSharp.Compiler.fsproj index 0323b00ea92..a1989b083b4 100644 --- a/src/Microsoft.FSharp.Compiler/Microsoft.FSharp.Compiler.fsproj +++ b/src/Microsoft.FSharp.Compiler/Microsoft.FSharp.Compiler.fsproj @@ -11,12 +11,9 @@ true - - <_ArcadeSdkMSBuildProjectDir>$([System.IO.Path]::GetDirectoryName('$(ArcadeSdkBuildTasksAssembly)'))\..\ - <_BuildReleasePackagesTargets>$(_ArcadeSdkMSBuildProjectDir)BuildReleasePackages.targets - - - + + + From 1dc3732dd29b67e1ae7b11a5734b1e9645499836 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 29 Apr 2026 09:16:47 +0200 Subject: [PATCH 3/5] Disable NuGet package pruning in DependencyManager project template The .NET 11 Preview 4 SDK enables NuGet package pruning by default, which removes packages already provided by the shared framework. This breaks FSI #r nuget resolution for packages like Microsoft.Extensions.DependencyInjection.Abstractions. Disable pruning in the generated project file so all user-requested packages are resolved. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../FSharp.DependencyManager.ProjectFile.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.ProjectFile.fs b/src/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.ProjectFile.fs index 5386ea5a283..db567ae0feb 100644 --- a/src/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.ProjectFile.fs +++ b/src/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.ProjectFile.fs @@ -52,6 +52,7 @@ $(POUND_R) $(RUNTIMEIDENTIFIER) false true + false true From 4763ba787860d03308482311ed7427398ee46dc9 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 29 Apr 2026 10:39:36 +0200 Subject: [PATCH 4/5] Fix NuGet scripting resolution for framework-provided assemblies In .NET 11 Preview 4+, several Microsoft.Extensions.* assemblies moved into the shared framework (Microsoft.NETCore.App.Ref). When a NuGet package's assemblies are superseded by the shared framework, they appear in ReferencePath from the framework ref pack but not in RuntimeCopyLocalItems. The DependencyManager's MSBuild target now correctly discovers these assemblies: - Use RestoreEnablePackagePruning (correct property name, was EnablePackagePruning which NuGet ignores) to ensure NuGet resolves actual package DLLs, triggering conflict resolution - Add Update rule to mark framework conflict-resolution winners with AssetType=runtime so FSI can discover them via #r nuget resolution - Guard the Update with a CopyLocal check to preserve existing behavior for packages that still have real runtime assets Update test assertions to reflect that framework-provided assemblies resolve to ref pack paths (not NuGet cache paths) and have no package roots. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../FSharp.DependencyManager.ProjectFile.fs | 16 +++++++++++++++- .../DependencyManagerInteractiveTests.fs | 11 ++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.ProjectFile.fs b/src/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.ProjectFile.fs index db567ae0feb..dfe128da71d 100644 --- a/src/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.ProjectFile.fs +++ b/src/FSharp.DependencyManager.Nuget/FSharp.DependencyManager.ProjectFile.fs @@ -52,7 +52,7 @@ $(POUND_R) $(RUNTIMEIDENTIFIER) false true - false + false true @@ -115,6 +115,7 @@ $(PACKAGEREFERENCES) <__Conflicts>@(__ConflictsList, ';'); + <_CopyLocalNames>;@(__InteractiveReferencedAssembliesCopyLocal->'%(Filename)', ';'); @@ -139,6 +140,19 @@ $(PACKAGEREFERENCES) %(__InteractiveReferencedAssembliesCopyLocal.NuGetPackageId) %(__InteractiveReferencedAssembliesCopyLocal.NuGetPackageVersion) + + + + runtime + %(InteractiveResolvedFile.PackageRoot)content\%(InteractiveResolvedFile.NugetPackageId)$(SCRIPTEXTENSION) diff --git a/tests/FSharp.Compiler.Private.Scripting.UnitTests/DependencyManagerInteractiveTests.fs b/tests/FSharp.Compiler.Private.Scripting.UnitTests/DependencyManagerInteractiveTests.fs index eaee96a1b28..274da88b16a 100644 --- a/tests/FSharp.Compiler.Private.Scripting.UnitTests/DependencyManagerInteractiveTests.fs +++ b/tests/FSharp.Compiler.Private.Scripting.UnitTests/DependencyManagerInteractiveTests.fs @@ -238,15 +238,16 @@ type DependencyManagerInteractiveTests() = Assert.True((result1.Roots |> Seq.head).EndsWith("/microsoft.extensions.configuration.abstractions/3.1.1/")) // Netstandard gets fewer dependencies than desktop, because desktop framework doesn't contain assemblies like System.Memory - // Those assemblies must be delivered by nuget for desktop apps + // Those assemblies must be delivered by nuget for desktop apps. + // In .NET 11+, Microsoft.Extensions.* assemblies are part of the shared framework. + // The conflict resolution returns framework ref pack paths instead of NuGet cache paths, + // and framework assemblies have no NuGet package roots. let result2 = dp1.Resolve(idm1, ".fsx", [|"r", "Microsoft.Extensions.Configuration.Abstractions, 3.1.1"|], reportError, TestFramework.productTfm) Assert.Equal(true, result2.Success) Assert.Equal(2, result2.Resolutions |> Seq.length) - let expected = "/netcoreapp3.1/" - Assert.True((result2.Resolutions |> Seq.head).Contains(expected)) + Assert.True((result2.Resolutions |> Seq.head).Contains("Microsoft.Extensions.Configuration.Abstractions")) Assert.Equal(1, result2.SourceFiles |> Seq.length) - Assert.Equal(2, result2.Roots |> Seq.length) - Assert.True((result2.Roots |> Seq.head).EndsWith("/microsoft.extensions.configuration.abstractions/3.1.1/")) + Assert.Equal(0, result2.Roots |> Seq.length) () /// Native dll resolution is not implemented on desktop From c04eb5707960b8c12c355d9ec9d020655c72a23e Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 29 Apr 2026 11:26:07 +0200 Subject: [PATCH 5/5] Fix test: expect 1 root (directly-requested package) instead of 0 On CI, NuGet generates Pkg* properties for resolved packages, which the DependencyManager uses to find nuspec files and derive package roots. The directly-requested package still provides its root; only the transitive dependency root is gone (now framework-provided). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../DependencyManagerInteractiveTests.fs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/FSharp.Compiler.Private.Scripting.UnitTests/DependencyManagerInteractiveTests.fs b/tests/FSharp.Compiler.Private.Scripting.UnitTests/DependencyManagerInteractiveTests.fs index 274da88b16a..c6d773560b4 100644 --- a/tests/FSharp.Compiler.Private.Scripting.UnitTests/DependencyManagerInteractiveTests.fs +++ b/tests/FSharp.Compiler.Private.Scripting.UnitTests/DependencyManagerInteractiveTests.fs @@ -240,14 +240,15 @@ type DependencyManagerInteractiveTests() = // Netstandard gets fewer dependencies than desktop, because desktop framework doesn't contain assemblies like System.Memory // Those assemblies must be delivered by nuget for desktop apps. // In .NET 11+, Microsoft.Extensions.* assemblies are part of the shared framework. - // The conflict resolution returns framework ref pack paths instead of NuGet cache paths, - // and framework assemblies have no NuGet package roots. + // The conflict resolution returns framework ref pack paths instead of NuGet cache paths. + // Only the directly-requested package root is available (transitive deps are framework-provided). let result2 = dp1.Resolve(idm1, ".fsx", [|"r", "Microsoft.Extensions.Configuration.Abstractions, 3.1.1"|], reportError, TestFramework.productTfm) Assert.Equal(true, result2.Success) Assert.Equal(2, result2.Resolutions |> Seq.length) Assert.True((result2.Resolutions |> Seq.head).Contains("Microsoft.Extensions.Configuration.Abstractions")) Assert.Equal(1, result2.SourceFiles |> Seq.length) - Assert.Equal(0, result2.Roots |> Seq.length) + Assert.Equal(1, result2.Roots |> Seq.length) + Assert.True((result2.Roots |> Seq.head).EndsWith("/microsoft.extensions.configuration.abstractions/3.1.1/")) () /// Native dll resolution is not implemented on desktop