Armazenar em cache pacotes NuGet

Azure DevOps Services | Azure DevOps Server | Azure DevOps Server 2022

O cache de pipeline ajuda a reduzir o tempo de build 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.

Observação

Não há suporte para o cache de pipeline em pipelines de lançamento clássicos.

Pré-requisitos

Produto Requisitos
Azure DevOps - Um projeto do Azure DevOps.
- Permissões:
    – Para conceder acesso a todos os pipelines do projeto, você deve ser membro do grupo Administradores do Projeto.

Bloquear as 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 builds.

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

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

Observação

Se você usar arquivos de bloqueio de pacote, considere especificar uma versão exata do SDK .NET em um arquivo global.json e definir rollForward para disable. Isso pode ajudar a evitar falhas no restore com bloqueio quando as dependências implícitas variam entre versões do SDK do .NET. Para obter mais informações, consulte .NET SDK global.json.

Armazenar em cache 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 a seguir, o conteúdo do packages.lock.json é convertido em hash para gerar uma chave de cache dinâmica. Isso garante que sempre que o arquivo for alterado, uma nova chave de cache será criada.

Uma captura de tela mostrando 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'

Observação

Os caches são imutáveis, depois que um cache é criado, o conteúdo dele não pode ser alterado.

Restaurar cache

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

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

Observação

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

Lidar com erros de "project.assets.json não encontrado"

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

Observação

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

Comparação de desempenho

O cache de pipelines 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 em um segundo pipeline e configuramos a tarefa de restauração para ser executada somente quando uma falha de cache ocorrer. A tarefa de restauração, nesse caso, foi concluída em apenas 8 segundos.

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

Veja abaixo 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 do .NET Core, desde que seu projeto use packages.lock.json para bloquear versões do pacote. Você pode habilitar isso definindo RestorePackagesWithLockFile para True no arquivo * Csproj* ou executando o seguinte comando: dotnet restore --use-lock-file.