首页 > 解决方案 > 有没有办法强制 NuGet 在管道执行期间恢复最新的包版本?

问题描述

我们在 Azure DevOps 环境中使用内部 NuGet 源来托管许多不同的包,这些包在许多不同的项目中使用。我想配置管道,以便每当引用内部包时,它总是被解析为最新版本。所有内部引用都在 .vbproj 文件的 PackageReference 标记中配置通配符,如下所示:

<PackageReference Include="MyPackageName" Version="*" />

YAML 文件中的 restore 命令配置如下:

- task: NuGetCommand@2
    condition: and(succeeded(), eq(variables['ModifiedProject'], 'true'))
    displayName: 'NuGet restore'
    inputs:
      command: 'restore'
      restoreSolution: '$(ModifiedProject.Directory)/$(ModifiedProject.Solution)'
      feedsToUse: 'select'
      vstsFeed: '[guid]/[guid]'
      noCache: true

项目成功构建,但最终仍使用最旧版本的包,而不是恢复最新版本。有没有办法强制恢复任务默认为最新的包版本?

标签: vb.netazure-devopsnugetyaml

解决方案


我最终通过使用Azure DevOps REST API找到了解决此问题的方法。我的目标是让管道通过这些基本步骤:

  1. 成功完成所有构建步骤后,将新的包版本推送到工件提要中。
  2. 使用 REST API 取消列出旧包版本,只保留最新版本。
  3. 由于在 PackageReference 标记中使用浮动版本,任何依赖这些包的项目将在它们各自的管道中构建时自动拉取最新版本。

我只是觉得走这条路很舒服,因为在 Azure 中“删除”一个包并没有真正删除它,它只是被移动到回收站。如果在推送后发现了重大更改,我们总是可以将以前的版本恢复到提要中。鉴于这个过程专门用于我们的 50 多个内部包,它们有自己的测试过程,这绝对是一条安全的路线,而且比我能找到的任何其他选项都高效得多。但是,我认为我不会将此标记为对该问题的明确答案,因为它仍然感觉有点老套,我希望有一个合法的选项来强制 Azure 的NuGetCommand@2任务中的最新版本。

代码

如前所述,我为这些功能使用了 Azure 记录良好的 REST API,尤其是管理工件的领域。尽管有一个专门用于从 NuGet 提要中删除包的页面,但我无法让他们的规范正常工作。我最终检查了从 UI 发出的调用并复制了这些调用,同时仍然使用我自己的令牌进行身份验证。此方法执行我需要的历史“修剪”:

public void TrimPackageFeed(string feedName, string packageName)
{
    var packageVersions = GetPackageVersions(feedName, packageName);
    var deprecated = packageVersions.Where(x => !x.IsLatest && !x.IsDeleted)?.ToList();

    if (deprecated != null && deprecated.Any())
    {
        foreach (var version in deprecated)
        {
            var url = $"{version.Links.Feed.Value.Replace("feeds.dev.azure.com", "pkgs.dev.azure.com")}/nuget/packagesBatch";
            var payload = new AzurePackagePayload
            {
                Data = null,
                Operation = 2,
                Packages = new List<AzurePackagePayloadItem>
                {
                    new AzurePackagePayloadItem
                    {
                        ID = packageName,
                        Version = version.Version
                    }
                }
            };
            ApiRequest(url, Method.POST, null, JsonConvert.SerializeObject(payload));
        }
    }
}

我将其构建为 .NET Core 3.1 命令行应用程序,在我们的构建存储库中发布为自包含的可执行文件。我使用 C# 是因为它对我来说最熟悉,但我相信它可以用任何语言编写脚本(甚至可能只是 PowerShell)。然后,我将以下任务附加到 YAML 管道定义的末尾:

- task: CmdLine@2
  condition: and(succeeded(), eq(variables['ModifiedProject'], 'true'))
  displayName: 'Trim package feed'
  inputs:
    script: |
      AzureApiClient -action trim-package-feed -feed FeedNameHere -package $(ModifiedProject.AssemblyName)
    workingDirectory: 'Azure\AzureApiClient\Output'
    failOnStderr: true

包被推送到提要,然后程序集名称被传递给我的 API 客户端,该客户端将修剪历史版本并仅保留可恢复的新版本。


推荐阅读