azure-pipelines-tasks: "dotnet tool install/update" not working with Azure Artifacts

Note

Issues in this repo are for tracking bugs, feature requests and questions for the tasks in this repo

For a list:
https://github.com/Microsoft/azure-pipelines-tasks/tree/master/Tasks

If you have an issue or request for the Azure Pipelines service, use developer community instead:

https://developercommunity.visualstudio.com/spaces/21/index.html )

Required Information

Entering this information will route you directly to the right team and expedite traction.

Question, Bug, or Feature?
Type: Question or Feature request

Enter Task Name: DotNetCLI@2

list here (V# not needed):
https://github.com/Microsoft/azure-pipelines-tasks/tree/master/Tasks

Environment

  • Server - Azure Pipelines
  • Agent - Private: Windows Server

Issue Description

dotnet tool install (invoked as custom command via DotNetCLI@2) cannot install tool when NuGet points to Azure Artifacts.

We’ve got an Azure Artifacts feed for our packages that is configured to use the NuGet gallery as upstream source. We’ve created a NuGet.config file pointing to the Azure Artifacts feed only. Restoring packages using the restore command works, however trying to restore a tool via a custom command does not. Trying to retrieve information about the package results in a 401 (Unauthorized).

Looking at the implementation of DotNetCLI@2 it looks like there are special cases for dotnet pack, dotnet push and dotnet restore among other things handling implicit authentication. However there is not special treatment for dotnet tool install or dotnet tool update.

Feature Request: Handle dotnet tool install and dotnet tool update or make the authentication globally available to all dotnet commands.

Question: Is there a workaround for this scenario (other than not removing nuget.org via NuGet.config, which would be against the point of using Azure Artifacts with upsteram nuget.org)?

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 11
  • Comments: 30 (5 by maintainers)

Most upvoted comments

@hiyadav, if I understand things correctly, the ticket that you referenced is about a situation where dotnet tool install doesn’t work, because there are two feeds in NuGet.config and a feed that requires authentication (but is not authenticated) blocks installation, even if the tool comes from the other feed that does not require authentication.

This is more about the fact that DotNetCLI@2 does some magic for the “pack”, “push” and “restore” commands to provide authentication for Azure Artifact feeds (and maybe others, don’t know) that require authentication, but it doesn’t do that for “tool install” or “tool update”.

This is still a problem. So not stale!

Not sure if it was the right way to solve the problem, but I submitted a PR to add tool install as a command on the DotNetCoreCLI task with functionality similar to how the restore command words (I.E. selecting a feed to use). Worked like a charm when I tested so let’s see what happens.

For all those that come after me:

I will be posting this response on a few issues that I frequented when troubleshooting a similar issue. This is not strictly related to this particular issue but someone may find it useful in the end.

In my case, we were having issues with intermittent packages not being restored from a nuget feed with a networking error, for example:

  Failed to download package 'System.Data.OleDb.4.7.0' from 'https://pkgs.dev.azure.com/acme/af808fc2-ae7d-42da-887a-ea7a78a65e52/_packaging/7648731a-3d0b-4888-816b-d229e1e80fd4/nuget/v3/flat2/system.data.oledb/4.7.0/system.data.oledb.4.7.0.nupkg'.
  The SSL connection could not be established, see inner exception.
    Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host..
    An existing connection was forcibly closed by the remote host.

Multiple packages would fail, and the packages that failed would be different every time. We would also periodically see a dotnet tool restore command simply hang and never complete.

We eventually figured out that these issues only seemed to be occurring when multiple builds were happening in parallel on Azure DevOps. This led me to believe that perhaps there was some kind of rate-limiting happening against the Azure Artifacts server, because the solution in question had ~70 projects to be restored, thus making a lot of network calls.

I enabled caching of nuget packages to alleviate this, which seemed to solve the problem. Below is a template YAML that I have added for all build tasks in our pipeline, and this seems to work for us.

steps:
  - task: NuGetAuthenticate@0
    displayName: "Authenticate with NuGet"
    inputs:
      forceReinstallCredentialProvider: true

  - task: UseDotNet@2
    displayName: Install .NET Core
    inputs:
      useGlobalJson: true

  - task: Cache@2
    displayName: Cache NuGet packages
    inputs:
      key: "nuget | $(Agent.OS) | **/global.json, **/*.csproj"
      restoreKeys: "nuget | $(Agent.OS)"
      path: $(NUGET_PACKAGES)

Usage example:

jobs:
  - job: Compile
    displayName: "⚙ Compile"
    dependsOn: []
    steps:
      - template: setup-build-task.azure-pipelines.yml

      - task: CmdLine@2
        displayName: Restore, lint, and build
        inputs:
          script: "./build.cmd RestoreTools Restore Lint Compile --skip"

Godspeed. I had a hell of a few days with this one.

@andrewdmoreno : Thanks for the quick reply. I see that integration has completely foundered on that PR.

For those that come after: I was able to strip down a workaround from the PR comments a bit more. The following steps worked for me:

  - task: NuGetCommand@2
    displayName: 'NuGet Add Credentials For Internal Feed'
    inputs:
      command: custom
      arguments: 'sources add -Name "<INTERNALFEEDNAME>" -Source "<INTERNALFEEDURL>/nuget/v3/index.json" -Username "this_value_could_anything" -Password "$(System.AccessToken)"'
  - task: CmdLine@2
    displayName: Install tools
    inputs:
      targetType: inline
      script: dotnet tool install <TOOLNAME> --global

Where:

  • <INTERNALFEEDURL> is obtained from your Azure project
  • <INTERNALFEEDNAME> doesn’t matter, as long as it doesn’t conflict with any defaults
  • <TOOLNAME> is the name of the tool to execute

This is utterly unintuitive, but it works and it’s not too much hacking. At least I can copy/paste these build steps between projects that rely on my dotnet tool without having to worry about copying secret information or uploading secure files. The idea to use $(System.AccessToken) was great.

I think it’s indisputable that it would be much nicer if “install tool” was an option for the “dotnet” command. It’s not like it’s an external tool. This is literally how Microsoft has asked us to work.

It would be nice if I hadn’t had to spend half an afternoon trying to figure out how to get a dotnet tool installed from a feed in the same project on Azure. I’m glad I got it working, but everyone who comes after will also waste time trying to figure this out—or will give up and use a gross hack instead.

Same problem, this was my workaround:

  - script: |
        dotnet tool restore  --add-source https://api.nuget.org/v3/index.json --ignore-failed-sources
    displayName: Restore .NET Tools

This worked for me:

Add a global.json:

{
  "sdk": {
    "version": "3.1.300"
  }
}
steps:

- task: NuGetAuthenticate@0

- task: UseDotNet@2
  displayName: Install .NET Core
  inputs:
    useGlobalJson: true

- task: CmdLine@2
  displayName: 'Execute Cake Script'
  inputs:
    script: |
      dotnet tool restore --interactive

I have have the same issue, but with the dotnet tool restore command (to restore local tools specified in .config/dotnet-tools.json).