git 基于对子文件夹的更改触发Azure DevOps生成

d7v8vwbk  于 2022-12-10  发布在  Git
关注(0)|答案(8)|浏览(123)

我有一个包含多个项目的Visual Studio解决方案,每个项目都是一个单独的微服务。对于开发团队来说,将所有服务都放在同一个解决方案中是非常方便的,而且git repo,因为服务可以互相调用。

Master.sln - SubFolderA - MicroserviceA.sln
           - SubFolderB - MicroserviceB.sln
           - SubFolderC - MicroserviceC.sln

但是,我希望在Azure DevOps中独立构建/发布各个微服务(当它们发生变化时),因此,如果ServiceA是唯一要更改的服务,则ServiceA是唯一构建和部署的服务。
为此,我创建了一个新的构建管道定义,并将“Path filters”设置为在微服务文件夹的内容发生更改时触发构建(因此每个要监视的微服务都添加了一个路径过滤器)。
这里我的问题是,当一个构建被触发时(例如,基于对SubFolderA的更改),我没有办法告诉构建定义只构建SubFolderA中的.sln文件。
我可以为每个微服务创建一个单独的构建定义,并在单独的子文件夹上触发每个构建,但这会带来很大的开销,也就是说,我需要维护15个单独的构建定义(对于我构建的每个分支也是如此),并且我们的自主机构建代理所需的存储现在将是NumberOfService x NumberOfBranchesBeingBuild x SizeOfRepo。
有没有一种方法可以使用一个带有git“Path filters”的构建定义,并定义多个路径,然后启动多个构建示例,并将触发构建的路径值提供给构建定义,从而告诉构建示例构建哪个.sln文件?
我希望这有意义!

i2byvkas

i2byvkas1#

你可以像下面这样做
1.基于微服务创建值为“False”的变量
例如,MicroserviceAUpdated =“假”,MicroserviceBUpdated =“假”等,
1.在生成定义的开始添加Powershell脚本任务。Powershell脚本将执行以下操作:
取得组建中的变更集/认可,以检查哪些档案已变更。

  • 如果只有SubFolderA下的任何文件发生更改,则将MicroserviceAUpdated变量更新为“true”。
  • 如果只有MicroserviceBUpdated变量

文件在SubFolderA下更改。
就这样......
1.为每个微服务创建单独的生成任务,将生成任务配置为使用如下自定义条件运行

用于微服务A生成任务

“自定义条件”:and(succeeded(), eq(variables['MicroserviceAUpdated'], 'True'))

用于微服务B生成任务

“自定义条件”:and(succeeded(), eq(variables['MicroserviceBUpdated'], 'True'))
所以......

  • 这样,如果变量的值为False,则将跳过MicoserviceTask *
    用于步骤2
$files=$(git diff HEAD HEAD~ --name-only)
$temp=$files -split ' '
$count=$temp.Length
echo "Total changed $count files"
For ($i=0; $i -lt $temp.Length; $i++)
{
  $name=$temp[$i]
  echo "this is $name file"
  if ($name -like "SubFolderA/*")
    {
      Write-Host "##vso[task.setvariable variable=MicroserviceAUpdated]True"
    }
}
lp0sw83n

lp0sw83n2#

在“触发器”选项卡上,有一个选项用于指定要生成的项目的路径。指定该路径后,只有包含与include/exclude规则匹配的修改的提交才会触发生成。
在我的例子中,这是一个比PowerShell脚本好得多的解决方案,PowerShell脚本仍然会触发所有项目的构建和发布,垃圾邮件我们的Slack和垃圾填充我们的项目历史。

3vpjnl9f

3vpjnl9f3#

Jayendran的回答非常好!下面是一个更适合PowerShell-y的方法来完成步骤2:

$editedFiles = git diff HEAD HEAD~ --name-only
$editedFiles | ForEach-Object {
    Switch -Wildcard ($_ ) {
        'SubFolderA/*' { Write-Output "##vso[task.setvariable variable=MicroserviceA]True" }
        # The rest of your path filters
    }
}
6mw9ycah

6mw9ycah4#

这篇文章对我帮助很大,所以我想添加一些有用的修改,我已经对我的过程。
我发现的第一个主要问题是这个git diff命令不能同时处理多个提交。

git diff HEAD HEAD~ --name-only

HEAD~只查看1个提交的背后,而单个推送可以同时包含多个提交。
我意识到我需要在HEAD和the commit id since the pipeline last ran successfully之间进行比较。

git diff HEAD [commit id of last successful build] --name-only

此提交ID可通过在/build/latest端点sourceVersion调用Azure DevOps API获得。

$response = (Invoke-RestMethod -Uri $url -Method GET -Headers $AzureDevOpsAuthenicationHeader)
$editedFiles = (git diff HEAD $response.sourceVersion --name-only)

我还对查找更改的项目/模块文件夹的逻辑进行了修改。我不想每次添加新项目时都要通过硬编码项目名称来修改PowerShell脚本。

$editedFiles | ForEach-Object { 
    $sepIndex = $_.IndexOf('/')
    if($sepIndex -gt 0) {
        $projectName = $_.substring(0, $sepIndex)
        AppendQueueVariable $projectName
    }
}

AppendQueueVariable将维护要返回到管道的所有已更改项目的列表。
最后,我获取排队项目的列表,并将它们传递到Maven多模块构建管道任务中。

mvn -amd -pl [list returned from PS task] clean install
pieyvz9o

pieyvz9o5#

为了补充deleb的回答,下面是设置path触发器的YAML代码:

trigger:
  branches:
    include:
    - master
  paths:
    include:
    - path/to/src*

请注意,要使用路径触发器,还需要分支触发器。
https://learn.microsoft.com/en-us/azure/devops/pipelines/repos/azure-repos-git?view=azure-devops&tabs=yaml#paths
编辑:根据Dariusz的评论修复路径

11dmarpk

11dmarpk6#

在bash中,您可以执行如下操作:

- task: Bash@3
    displayName: 'Determine which apps were updated'
    inputs:
      targetType: 'inline'
      script: |
        DIFFS="$(git diff HEAD HEAD~ --name-only)"
        [[ "${DIFFS[@]}" =~ "packages/shared" ]] && echo "##vso[task.setvariable variable=SHARED_UPDATED]True"
        [[ "${DIFFS[@]}" =~ "packages/mobile" ]] && echo "##vso[task.setvariable variable=MOBILE_UPDATED]True"
        [[ "${DIFFS[@]}" =~ "packages/web" ]] && echo "##vso[task.setvariable variable=WEB_UPDATED]True"
63lcw9qa

63lcw9qa7#

解决方案是在子文件夹中为每个服务创建一个azure-pipelines.yml。子文件夹中的每个azure-pipelines.yml都必须具有以下触发器定义。

trigger:
  branches:
    include:
      - master
  paths:
    include:
      - <service subfolder name>/*

paths -〉include是yaml的一部分,告诉azure管道只有在特定路径发生变化时才触发。
子文件夹中的azure-pipelines.yml不需要另外命名,可以保留相同的名称。同样,也不需要将azure-pipelines.yml添加到repo的根目录中,除非有一些代码需要在子文件夹以外的根目录中构建。在这种情况下,必须将下面的触发器部分添加到repo根目录的azure-pipelines.yml中。

trigger:
  branches:
    include:
      - master
  paths:
    exclude:
      - <service subfolder name 1>/*
      - <service subfolder name 2>/*

paths -〉exclude部分排除了已经包含自己的azure-pipelines.yml文件的子文件夹,并且只有在子文件夹之外的repo的根目录发生更改时才会被触发。
blog将更详细地解释monorepo管道。

disbfnqx

disbfnqx8#

根据Taul的解决方案进行即兴创作:如果一个项目需要在两个或更多子文件夹更新时重新构建,我们可以使用regex来检测所有相关的更改:
给定微服务A依赖于文件夹子文件夹A、子文件夹B和基本子文件夹

$editedFiles = git diff HEAD HEAD~ --name-only
$editedFiles | ForEach-Object {
    Switch -Regex ($_ ) {
        '(SubfolderA|SubfolderB|BaseSubfolder)(\/|$)' { Write-Output "##vso[task.setvariable variable=MicroserviceA]True" }
        # The rest of your path filters
    }
}

相关问题