Cache de pacotes NuGet

Serviços de DevOps do Azure | Azure DevOps Server | Azure DevOps Server 2022

O cache de pipeline ajuda a reduzir o tempo de compilação armazenando dependências para reutilização em execuções futuras. Neste artigo, você aprenderá a usar a tarefa Cache para armazenar em cache e restaurar seus pacotes NuGet.

Nota

A cache de pipeline não é suportada em pipelines de lançamento clássico.

Pré-requisitos

Produto Requisitos
Azure DevOps - Um projeto Azure DevOps .
- Permissões:
    - Para conceder acesso a todos os pipelines no projeto, deves ser membro do grupo Administradores de Projeto.

Bloquear dependências

Antes de configurar a tarefa de cache, você precisa bloquear as dependências do projeto e gerar um arquivo package.lock.json. A chave de cache exclusiva é derivada do hash do conteúdo desse arquivo de bloqueio para garantir a consistência entre as compilações.

Para bloquear as dependências do projeto, adicione a propriedade RestorePackagesWithLockFile ao seu arquivo csproj do e defina-o como true. Quando você executa nuget restore, ele gera um arquivo packages.lock.json no diretório raiz do projeto. Certifique-se de incluir o seu arquivo packages.lock.json no seu código-fonte.

<PropertyGroup>
  <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>

Nota

Se usares ficheiros de bloqueio de pacotes, considera especificar uma versão exata do SDK .NET num ficheiro global.json e definir rollForward para disable. Isto pode ajudar a evitar falhas no restauro em modo bloqueado quando as dependências implícitas variam entre versões do SDK .NET. Para mais informações, consulte .NET SDK global.json.

Cache de pacotes NuGet

Para armazenar em cache pacotes NuGet, defina uma variável de pipeline que aponte para o local dos pacotes no agente que executa o pipeline.

No exemplo abaixo, o conteúdo do packages.lock.json é colocado em hash para gerar uma chave de cache dinâmica. Isso garante que, sempre que o arquivo for alterado, uma nova chave de cache seja criada.

Uma captura de tela exibindo como a chave de cache é gerada no Azure Pipelines.

variables:
  NUGET_PACKAGES: $(Pipeline.Workspace)/.nuget/packages

- task: Cache@2
  displayName: Cache v2 task 
  inputs:
    key: 'nuget | "$(Agent.OS)" | **/packages.lock.json,!**/bin/**,!**/obj/**'
    restoreKeys: |
       nuget | "$(Agent.OS)"
       nuget
    path: '$(NUGET_PACKAGES)'
    cacheHitVar: 'CACHE_RESTORED'

Nota

Os caches são imutáveis, uma vez que um cache é criado, seu conteúdo não pode ser modificado.

Restaurar cache

A tarefa seguinte só será executada se a variável CACHE_RESTORED for falso. Isso significa que, se ocorrer um acerto de cache (os pacotes já estão disponíveis no cache), a etapa de restauração será ignorada para economizar recursos e tempo. Se nenhum cache for encontrado, o comando restore será executado para baixar as dependências necessárias.

- task: NuGetCommand@2
  condition: ne(variables.CACHE_RESTORED, true)
  inputs:
    command: 'restore'
    restoreSolution: '**/*.sln'

Nota

Se você estiver usando o Ubuntu 24.04 ou posterior, você deve usar a tarefa NuGetAuthenticate com a CLI do .NET em vez da tarefa NuGetCommand@2. Consulte Suporte para imagens hospedadas mais recentes do Ubuntu para obter mais detalhes.

Lidar com o erro "project.assets.json não encontrado"

Se você encontrar o erro "project.assets.json não encontrado" durante a tarefa de compilação, remova a condição condition: ne(variables.CACHE_RESTORED, true) da tarefa de restauração. Isso garante que o comando restore seja executado e gere o arquivo project.assets.json. A tarefa de restauração não baixará novamente os pacotes que já estão presentes na pasta correspondente.

Nota

Um pipeline pode incluir várias tarefas de cache, e trabalhos e tarefas dentro do mesmo pipeline podem acessar e compartilhar o mesmo cache.

Comparação de desempenho

O cache de pipeline reduz significativamente o tempo necessário para restaurar dependências, resultando em compilações mais rápidas. A comparação a seguir ilustra o impacto do cache no tempo de execução do pipeline para dois pipelines diferentes:

  • Sem cache (à direita): A tarefa de restauração levou aproximadamente 41 segundos.

  • Com cache (esquerda): adicionamos a tarefa de cache a um segundo pipeline e configuramos a tarefa de restauração para ser executada somente quando ocorrer uma falha de cache. A tarefa de restauração, neste caso, foi concluída em apenas 8 segundos.

Uma captura de tela exibindo o desempenho do pipeline com e sem cache.

Abaixo está o pipeline YAML completo para referência:

pool:
  vmImage: 'windows-latest'

variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'
  NUGET_PACKAGES: $(Pipeline.Workspace)/.nuget/packages

steps:
- task: NuGetToolInstaller@1
  displayName: 'NuGet tool installer'

- task: Cache@2
  displayName: 'NuGet Cache'
  inputs:
    key: 'nuget | "$(Agent.OS)" | **/packages.lock.json,!**/bin/**,!**/obj/**'
    restoreKeys: |
       nuget | "$(Agent.OS)"
       nuget
    path: '$(NUGET_PACKAGES)'
    cacheHitVar: 'CACHE_RESTORED'

- task: NuGetCommand@2
  displayName: 'NuGet restore'
  condition: ne(variables.CACHE_RESTORED, true)
  inputs:
    command: 'restore'
    restoreSolution: '$(solution)'

- task: VSBuild@1
  displayName: 'Visual Studio Build'
  inputs:
    solution: '$(solution)'
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

Essa abordagem também se aplica a projetos .NET Core, desde que seu projeto use packages.lock.json para bloquear versões de pacote. Você pode habilitar isso definindo RestorePackagesWithLockFile para True no arquivo * Csproj* ou executando o seguinte comando: dotnet restore --use-lock-file.