Поделиться через


Кэш пакетов NuGet

Azure DevOps Services

При кэшировании конвейера можно сократить время сборки, кэширование зависимостей для повторного использования в последующих запусках. В этой статье вы узнаете, как использовать задачу кэша для кэширования и восстановления пакетов NuGet.

Примечание.

Кэширование конвейера поддерживается в заданиях пула агентов как для YAML, так и для классических конвейеров. Однако он не поддерживается в конвейерах классических выпусков.

Зависимости блокировки

Чтобы настроить задачу кэша, сначала необходимо заблокировать зависимости проекта и создать файл package.lock.json . Мы будем использовать хэш содержимого этого файла для создания уникального ключа для кэша.

Чтобы заблокировать зависимости проекта, задайте для свойства RestorePackagesWithLockFile в файле csproj значение true. Восстановление NuGet создает файл блокировки packages.lock.json в корневом каталоге проекта. Убедитесь, что вы проверьте файл packages.lock.json в исходном коде.

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

Кэш пакетов NuGet

Необходимо создать переменную конвейера, чтобы указать расположение наших пакетов на агенте, на котором выполняется конвейер.

В этом примере содержимое packages.lock.json будет хэшировано для создания ключа динамического кэша. Это гарантирует, что при каждом изменении файла создается новый ключ кэша.

Снимок экрана: создание ключа кэша в Azure Pipelines.

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

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

Примечание.

Кэши неизменяемы после создания кэша, его содержимое нельзя изменить.

Восстановление кэша

Эта задача будет выполняться только в том случае, если CACHE_RESTORED переменная имеет значение false.

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

Если во время задачи сборки возникло сообщение об ошибке "project.assets.json не найдено", его можно устранить, удалив условие condition: ne(variables.CACHE_RESTORED, true) из задачи восстановления. Таким образом, команда восстановления будет выполнена, создав файл project.assets.json. Задача восстановления не скачивает пакеты, которые уже присутствуют в соответствующей папке.

Примечание.

Конвейер может содержать одну или несколько задач кэширования, а задания и задачи в одном конвейере могут получить доступ к одному и тому же кэшу.

Сравнение производительности

Кэширование конвейера — отличный способ ускорить выполнение конвейера. Ниже приведено параллельное сравнение производительности двух разных конвейеров. Перед добавлением задачи кэширования (справа) задача восстановления заняла около 41 секунд. Мы добавили задачу кэширования во второй конвейер (слева) и настроили задачу восстановления для выполнения при возникновении ошибки кэша. Задача восстановления в этом случае заняла 8 секунд.

Снимок экрана: производительность конвейера с кэшированием и без кэширования.

Ниже приведен полный конвейер YAML для справки:

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)'