仅在项目已更改时创建 Nuget 包

Only create Nuget package if project has changed

给出的解决方案同时包含 Web Api 项目、Api 客户端项目和包含共享 Dto 对象的程序集项目,如下所示:

我有一个 Azure Devops 构建管道来构建和测试所有项目。 在该构建管道中,我有一个步骤为 Api 客户端和共享 Dto 项目创建 2 个 Nuget 包。

但是,我不需要一直创建新包,比如我只是添加了一个单元测试或修复了 Web Api 项目中的一个错误,我不想创建新包如果 Api 客户端项目(或其依赖项)中没有任何内容发生变化,Nuget 包(或担心会影响包版本),但我仍然想对其进行回归测试。

我想也许我可以通过多个构建管道来做到这一点,一个用于 Web Api 项目,另一个用于 Api 客户端和共享项目,然后使用路径过滤器来触发适当的构建。

还有其他方法可以实现吗? 最佳做法是什么? 我不想维护比我需要的更多的构建定义。

Are there any other ways to achieve this? Whats the best practice? I don't want to have to maintain more build definitions than I need.

有多种实现方式,但不确定哪种方式是最佳做法,这完全取决于您的要求或品味。

简单方法和你的想法差不多。还需要创建一个新的构建管道。不同的是我们不需要维护这个构建定义。

详情:

  • 在此管道中添加一个没有任何任务的新管道,并使用 path 过滤器以触发适当的构建(Api 客户端和 共享 Dto 项目)。
  • 构建完成 添加到您的原始 Azure Devops 构建管道:
  • 为基于Build.Reason创建2个Nuget包的步骤添加一个custom condition,如:

    and(succeeded(), eq(variables['Build.Reason'], 'BuildCompletion'))
    

现在,创建 2 个 Nuget 包的步骤在文件更改来自特定项目时执行。当然这个解决方案的局限性是,如果你已经有一个构建完成,它就不起作用了。

如果上述方法不是您想要的,我们可以调用 REST API commits 来获取每个构建的提交信息:

GET https://dev.azure.com/{organization}/{project}/_apis/git/repositories/{repositoryId}/commits/{commitId}?changeCount=100&api-version=5.1

我们可以在返回的正文中找到 changes/path:

  "changes": [
    {
      "item": {
        "gitObjectType": "blob",
        "path": "/.gitattributes",
        "url": "https://dev.azure.com/fabrikam/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249/items/.gitattributes?versionType=Commit"
      },
      "changeType": "add"
    },
    {
      "item": {
        "gitObjectType": "blob",
        "path": "/.gitignore",
        "url": "https://dev.azure.com/fabrikam/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249/items/.gitignore?versionType=Commit"
      },
      "changeType": "add"
    },
    {
      "item": {
        "gitObjectType": "tree",
        "path": "/MyWebSite",
        "isFolder": true,
        "url": "https://dev.azure.com/fabrikam/_apis/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249/items/MyWebSite?versionType=Commit"
      },
      "changeType": "add"
    },

然后我们可以使用powershell脚本遍历这些路径,看是否包含ApiClient和Shared Dto项目,如果是,我们设置一个变量,并根据这个值添加条件用于创建 2 个 Nuget 包的步骤。

注意:在使用 REST API commits 之前,我们需要使用 Commits - Get Commits 来获取最新的提交 ID:

GET https://dev.azure.com/{organization}/{project}/_apis/git/repositories/{repositoryId}/commits?$top=1&api-version=5.1

希望这对您有所帮助。

我最终对

# Checks which files have been updated to determine if new Nuget packages are required
$editedFiles = git diff HEAD HEAD~ --name-only
echo "$($editedFiles.Length) files modified:"
$editedFiles | ForEach-Object {
   echo $_
    Switch -Wildcard ($_ ) {
        'Whds.Configuration.Models/*' { 
              # If the Models project is updated, we need to create both packages
              Write-Output "##vso[task.setvariable variable=CreateModelsPackage]True"
              Write-Output "##vso[task.setvariable variable=CreateClientPackage]True"  
         }        
        'Whds.Configuration.Standard/*' { Write-Output "##vso[task.setvariable 
variable=CreateClientPackage]True" }
        # The rest of your path filters
    }
}

此脚本设置变量,然后在构建管道的 dotnet pack 步骤中的自定义条件中引用这些变量:

and(succeeded(), eq(variables['CreateModelsPackage'], 'True'))

如果更改了 Dto 项目,则设置两个变量以创建两个包。 如果只有客户端(又名标准)项目发生了变化,则不会创建 Dto 项目的包。