@@ -168,6 +168,12 @@ function InitializeDotNetCli([bool]$install, [bool]$createSdkLocationFile) {
168168 $env: DOTNET_CLI_TELEMETRY_OPTOUT = 1
169169 }
170170
171+ # Keep repo builds isolated from machine-installed SDK state and workload advertising.
172+ # This avoids preview SDK builds picking up mismatched workloads on CI images.
173+ $env: DOTNET_MULTILEVEL_LOOKUP = ' 0'
174+ $env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE = ' 1'
175+ $env: DOTNET_CLI_WORKLOAD_UPDATE_NOTIFY_DISABLE = ' 1'
176+
171177 # Find the first path on %PATH% that contains the dotnet.exe
172178 if ($useInstalledDotNetCli -and (-not $globalJsonHasRuntimes ) -and ($env: DOTNET_INSTALL_DIR -eq $null )) {
173179 $dotnetExecutable = GetExecutableFileName ' dotnet'
@@ -230,6 +236,9 @@ function InitializeDotNetCli([bool]$install, [bool]$createSdkLocationFile) {
230236 Write-PipelinePrependPath - Path $dotnetRoot
231237
232238 Write-PipelineSetVariable - Name ' DOTNET_NOLOGO' - Value ' 1'
239+ Write-PipelineSetVariable - Name ' DOTNET_MULTILEVEL_LOOKUP' - Value ' 0'
240+ Write-PipelineSetVariable - Name ' DOTNET_SKIP_FIRST_TIME_EXPERIENCE' - Value ' 1'
241+ Write-PipelineSetVariable - Name ' DOTNET_CLI_WORKLOAD_UPDATE_NOTIFY_DISABLE' - Value ' 1'
233242
234243 return $global :_DotNetInstallDir = $dotnetRoot
235244}
@@ -480,7 +489,6 @@ function LocateVisualStudio([object]$vsRequirements = $null){
480489 if (Get-Member - InputObject $GlobalJson.tools - Name ' vswhere' ) {
481490 $vswhereVersion = $GlobalJson.tools.vswhere
482491 } else {
483- # keep this in sync with the VSWhereVersion in DefaultVersions.props
484492 $vswhereVersion = ' 3.1.7'
485493 }
486494
@@ -615,7 +623,17 @@ function GetNuGetPackageCachePath() {
615623
616624# Returns a full path to an Arcade SDK task project file.
617625function GetSdkTaskProject ([string ]$taskName ) {
618- return Join-Path (Split-Path (InitializeToolset) - Parent) " SdkTasks\$taskName .proj"
626+ $toolsetDir = Split-Path (InitializeToolset) - Parent
627+ $proj = Join-Path $toolsetDir " $taskName .proj"
628+ if (Test-Path $proj ) {
629+ return $proj
630+ }
631+ # TODO: Remove this fallback once all supported versions use the new layout.
632+ $legacyProj = Join-Path $toolsetDir " SdkTasks\$taskName .proj"
633+ if (Test-Path $legacyProj ) {
634+ return $legacyProj
635+ }
636+ throw " Unable to find $taskName .proj in toolset at: $toolsetDir "
619637}
620638
621639function InitializeNativeTools () {
@@ -652,35 +670,69 @@ function InitializeToolset() {
652670 $nugetCache = GetNuGetPackageCachePath
653671
654672 $toolsetVersion = Read-ArcadeSdkVersion
655- $toolsetLocationFile = Join-Path $ToolsetDir " $toolsetVersion .txt "
673+ $toolsetToolsDir = Join-Path $ToolsetDir $toolsetVersion
656674
657- if (Test-Path $toolsetLocationFile ) {
658- $path = Get-Content $toolsetLocationFile - TotalCount 1
659- if (Test-Path $path ) {
660- return $global :_InitializeToolset = $path
661- }
675+ # Check if the toolset has already been extracted
676+ $toolsetBuildProj = $null
677+ $buildProjPath = Join-Path $toolsetToolsDir ' Build.proj'
678+
679+ if (Test-Path $buildProjPath ) {
680+ $toolsetBuildProj = $buildProjPath
681+ }
682+
683+ if ($toolsetBuildProj -ne $null ) {
684+ return $global :_InitializeToolset = $toolsetBuildProj
662685 }
663686
664687 if (-not $restore ) {
665688 Write-PipelineTelemetryError - Category ' InitializeToolset' - Message " Toolset version $toolsetVersion has not been restored."
666689 ExitWithExitCode 1
667690 }
668691
669- $buildTool = InitializeBuildTool
692+ $downloadArgs = @ (" package" , " download" , " Microsoft.DotNet.Arcade.Sdk@$toolsetVersion " , " --verbosity" , " minimal" , " --prerelease" , " --output" , " $nugetCache " )
693+ $nugetConfig = $env: NUGET_CONFIG
694+ if (-not $nugetConfig ) {
695+ # Search for any variation of nuget.config in the RepoRoot
696+ $configFile = Get-ChildItem - Path $RepoRoot - File | Where-Object { $_.Name -ieq " nuget.config" } | Select-Object - First 1
670697
671- $proj = Join-Path $ToolsetDir ' restore.proj'
672- $bl = if ($binaryLog ) { ' /bl:' + (Join-Path $LogDir ' ToolsetRestore.binlog' ) } else { ' ' }
698+ if ($configFile ) {
699+ $nugetConfig = $configFile.FullName
700+ }
701+ }
673702
674- ' <Project Sdk="Microsoft.DotNet.Arcade.Sdk"/>' | Set-Content $proj
703+ if ($nugetConfig ) {
704+ $downloadArgs += " --configfile"
705+ $downloadArgs += $nugetConfig
706+ }
707+ DotNet @downloadArgs
675708
676- MSBuild- Core $proj $bl / t:__WriteToolsetLocation / clp:ErrorsOnly` ;NoSummary / p:__ToolsetLocationOutputFile= $toolsetLocationFile
709+ $packageDir = Join-Path $nugetCache (Join-Path ' microsoft.dotnet.arcade.sdk' $toolsetVersion )
710+ $packageToolsetDir = Join-Path $packageDir ' toolset'
711+ $packageToolsDir = Join-Path $packageDir ' tools'
677712
678- $path = Get-Content $toolsetLocationFile - Encoding UTF8 - TotalCount 1
679- if (! (Test-Path $path )) {
680- throw " Invalid toolset path: $path "
713+ # TODO: Remove the tools/ check once all supported versions have the toolset folder.
714+ if (! (Test-Path $packageToolsetDir ) -and ! (Test-Path $packageToolsDir )) {
715+ Write-PipelineTelemetryError - Category ' InitializeToolset' - Message " Arcade SDK package does not contain a toolset or tools folder: $packageDir "
716+ ExitWithExitCode 3
681717 }
682718
683- return $global :_InitializeToolset = $path
719+ New-Item - ItemType Directory - Path $toolsetToolsDir - Force | Out-Null
720+
721+ # Copy toolset if present at the package root (new layout), otherwise fall back to tools
722+ if (Test-Path $packageToolsetDir ) {
723+ Copy-Item - Path " $packageToolsetDir \*" - Destination $toolsetToolsDir - Recurse - Force
724+ } else {
725+ # TODO: Remove this fallback once all supported versions have the toolset folder.
726+ Copy-Item - Path " $packageToolsDir \*" - Destination $toolsetToolsDir - Recurse - Force
727+ }
728+
729+ if (Test-Path $buildProjPath ) {
730+ $toolsetBuildProj = $buildProjPath
731+ } else {
732+ throw " Unable to find Build.proj in toolset at: $toolsetToolsDir "
733+ }
734+
735+ return $global :_InitializeToolset = $toolsetBuildProj
684736}
685737
686738function ExitWithExitCode ([int ] $exitCode ) {
@@ -741,6 +793,40 @@ function MSBuild() {
741793 MSBuild- Core @args
742794}
743795
796+ #
797+ # Executes a dotnet command with arguments passed to the function.
798+ # Terminates the script if the command fails.
799+ #
800+ function DotNet () {
801+ $dotnetRoot = InitializeDotNetCli - install:$restore
802+ $dotnetPath = Join-Path $dotnetRoot (GetExecutableFileName ' dotnet' )
803+
804+ $cmdArgs = " "
805+ foreach ($arg in $args ) {
806+ if ($null -ne $arg -and $arg.Trim () -ne " " ) {
807+ if ($arg.EndsWith (' \' )) {
808+ $arg = $arg + " \"
809+ }
810+ $cmdArgs += " `" $arg `" "
811+ }
812+ }
813+
814+ $env: ARCADE_BUILD_TOOL_COMMAND = " `" $dotnetPath `" $cmdArgs "
815+
816+ $exitCode = Exec- Process $dotnetPath $cmdArgs
817+
818+ if ($exitCode -ne 0 ) {
819+ Write-Host " dotnet command failed with exit code $exitCode . Check errors above." - ForegroundColor Red
820+
821+ if ($ci -and $env: SYSTEM_TEAMPROJECT -ne $null -and ! $fromVMR ) {
822+ Write-PipelineSetResult - Result " Failed" - Message " dotnet command execution failed."
823+ ExitWithExitCode 0
824+ } else {
825+ ExitWithExitCode $exitCode
826+ }
827+ }
828+ }
829+
744830#
745831# Executes msbuild (or 'dotnet msbuild') with arguments passed to the function.
746832# The arguments are automatically quoted.
@@ -765,6 +851,10 @@ function MSBuild-Core() {
765851
766852 $cmdArgs = " $ ( $buildTool.Command ) /m /nologo /clp:Summary /v:$verbosity /nr:$nodeReuse /p:ContinuousIntegrationBuild=$ci "
767853
854+ if ($ci -and $buildTool.Tool -eq ' dotnet' ) {
855+ $cmdArgs += ' /p:MSBuildEnableWorkloadResolver=false'
856+ }
857+
768858 # Add -mt flag for MSBuild multithreaded mode if enabled via environment variable
769859 if ($env: MSBUILD_MT_ENABLED -eq " 1" ) {
770860 $cmdArgs += ' -mt'
@@ -875,6 +965,12 @@ Create-Directory $ToolsetDir
875965Create- Directory $TempDir
876966Create- Directory $LogDir
877967
968+ # Direct MSBuild crash diagnostics (MSB4166 failure.txt files) to a known location
969+ # under artifacts/log so they are captured as build artifacts in CI.
970+ if (-not $env: MSBUILDDEBUGPATH ) {
971+ $env: MSBUILDDEBUGPATH = Join-Path $LogDir ' MsbuildDebugLogs'
972+ }
973+
878974Write-PipelineSetVariable - Name ' Artifacts' - Value $ArtifactsDir
879975Write-PipelineSetVariable - Name ' Artifacts.Toolset' - Value $ToolsetDir
880976Write-PipelineSetVariable - Name ' Artifacts.Log' - Value $LogDir
0 commit comments