asp.net.netazure-devopsazure-pipelinesazure-yaml-pipelines

Why UseDotNet@2 tasks downloads SDK even if it is already present on build agent?


I have a azure pipeline yaml file:

trigger:
- master

pool:
  vmImage: windows-latest

variables:
  buildConfiguration: 'Release'

steps:
- script: dotnet --info

- task: UseDotNet@2
  displayName: 'Install .NET Core SDK'
  inputs:
    version: 8.x
    performMultiLevelLookup: true

The first steps show current .net sdk version 8.100

dotnet --info
========================== Starting Command Output ===========================
"C:\Windows\system32\cmd.exe" /D /E:ON /V:OFF /S /C "CALL "D:\a\_temp\664f63f2-5ed6-42f1-bc1c-ec022164d139.cmd""
.NET SDK:
 Version:           8.0.100
 Commit:            57efcf1350
 Workload version:  8.0.100-manifests.8d38d0cc

Second install it anyway:

Starting: Install .NET Core SDK
==============================================================================
Task         : Use .NET Core
Description  : Acquires a specific version of the .NET Core SDK from the internet or the local cache and adds it to the PATH. Use this task to change the version of .NET Core used in subsequent tasks. Additionally provides proxy support.
Version      : 2.232.0
Author       : Microsoft Corporation
Help         : https://aka.ms/AA4xgy0
==============================================================================
Tool to install: .NET Core sdk version 8.x.
Found version 8.0.100 in channel 8.0 for user specified version spec: 8.x
Version 8.0.100 was not found in cache.
Getting URL to download .NET Core sdk version: 8.0.100.
Detecting OS platform to find correct download package for the OS.
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command "& 'D:\a\_tasks\UseDotNet_b0ce7256-7898-45d3-9cb5-176b752bfea6\2.232.0\externals\get-os-platform.ps1'"
Primary:win-x64
Detected platform (Primary): win-x64
Downloading: https://download.visualstudio.microsoft.com/download/pr/2b2d6133-c4f9-46dd-9ab6-86443a7f5783/340054e2ac7de2bff9eea73ec9d4995a/dotnet-sdk-8.0.100-win-x64.zip
Extracting downloaded package D:\a\_temp\8b1e68d4-a606-4bcf-b743-153c1e712c27.
Extracting archive
C:\Windows\system32\chcp.com 65001
Active code page: 65001
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command "$ErrorActionPreference = 'Stop' ; try { Add-Type -AssemblyName System.IO.Compression.FileSystem } catch { } ; [System.IO.Compression.ZipFile]::ExtractToDirectory('D:\a\_temp\8b1e68d4-a606-4bcf-b743-153c1e712c27', 'D:\a\_temp\897f')"
Successfully installed .NET Core sdk version 8.0.100.
Creating global tool path and pre-pending to PATH.
Finishing: Install .NET Core SDK
  1. How can I avoid installing it if not necessary?

  2. Are the UseDotNet and DotNetCLI tasks still recommended option, since DotNetCLI defaults to .NET 2 instead default installed SDK?


Solution

  • This is an interesting observation between Microsoft-provided and Self-hosted pipeline images.

    Microsoft builds their windows-latest image using code from the https://github.com/runner-images/ repository, which contains InstallDotNetSDK.ps1. Their installer puts the dotnet SDKs in C:\Program Files\dotnet\sdk\<version>, adds the installation location to the %PATH%

    The UseDotNet@2 task is responsible for downloading and installing specific versions of the SDK and then setting the appropriate environment variables. This task is especially useful for:

    The UseDotNet@2 tool installs the dotnet SDK into the build agent's tool directory $(Agent.ToolDirectory)/dotnet. For a Microsoft-hosted agent, this should translate into c:\hostedtoolcache\windows\dotnet.

    The intention of the tools directory is aimed towards Python and Nodejs installers, where the %PATH% must be altered to switch between installed versions. However, with dotnet, this isn't a big concern because dotnet.exe can typically find the right framework to use, assuming the version you want is installed.

    If you're using the Microsoft-provided agent and using the latest SDK, there's a really good chance the SDK is already installed, so the UseDotNet@2 task might not be necessary at all. But, for deterministic builds, it's a best practice to specify the version you're using.

    The UseDotNet@2 task has pre-installation checks that you might be able to short-circuit by specifying the installation folder:

    - task: UseDotNet@2
      displayName: 'Install .NET Core SDK'
      inputs:
        version: 8.x
        performMultiLevelLookup: true
        installationPath: 'C:\Program Files\dotnet`
    

    Update:

    There's an open bug for this. The check to verify if it's already installed appears to be looking for both the c:\program files\dotnet\sdk\x.xx.xxx folder and the presence of a file c:\program files\dotnet\sdk\x.xx.xxx.complete.

    If you create the file in advance, the tool properly identifies that it is already installed.

    - task: PowerShell@2
      displayName: 'UseDotNet@2 fix'
      inputs:
        targetType: inline
        script: |
           Set-Content -Path 'C:\Program Files\dotnet\sdk\8.0.100.complete' -Value 'dummy'
    
    - task: UseDotNet@2
      inputs:
        version: 8.0.100
        performMultiLevelLookup: true
        installationPath: 'C:\Program Files\dotnet'
    

    with fix