Git 基于对子文件夹的更改触发Azure DevOps构建

Git 基于对子文件夹的更改触发Azure DevOps构建,git,azure-devops,azure-pipelines,Git,Azure Devops,Azure Pipelines,我有一个包含多个项目的VisualStudio解决方案,每个项目都是一个单独的微服务。对于开发团队来说,将所有服务放在同一个解决方案和git repo中非常方便,因为服务可以相互调用 Master.sln - SubFolderA - MicroserviceA.sln - SubFolderB - MicroserviceB.sln - SubFolderC - MicroserviceC.sln 然而,我想在Azure DevOps中独立构建/发

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

Master.sln - SubFolderA - MicroserviceA.sln
           - SubFolderB - MicroserviceB.sln
           - SubFolderC - MicroserviceC.sln
然而,我想在Azure DevOps中独立构建/发布单个微服务,当它们发生更改时,因此如果ServiceA是唯一要更改的服务,那么ServiceA是唯一构建和部署的服务

为此,我创建了一个新的构建管道定义,其中设置了“路径过滤器”,以在微服务文件夹的内容发生更改时触发构建(因此每个微服务添加一个要监视的路径过滤器)

我这里的问题是,当触发生成时(例如,基于对子文件夹a的更改),我无法告诉生成定义仅在子文件夹a中生成.sln文件

我可以为每个微服务创建一个单独的构建定义,并在单独的子文件夹上触发每个构建,但这会带来很大的开销,即我需要维护15个单独的构建定义(对于我构建的每个分支也是如此),我们的自主机构建代理现在需要的存储是NumberOfService x NumberOfBranchesBeingBuild x SizeOfRepo

有没有一种方法可以使用带有git“路径过滤器”的单个生成定义和定义的多个路径,从而启动多个生成实例,并将触发生成的路径的值输入到生成定义中,从而告诉生成实例要生成哪个.sln文件

我希望这是有道理的

你可以像下面这样做

  • 基于微服务创建值为“False”的变量
  • 例如,
    microserviceupdated
    =“False”、
    microservicebuupdated
    =“False”等

  • 在生成定义的开头添加Powershell脚本任务。 powershell脚本将执行以下操作:
  • 在生成中获取变更集/提交,以检查哪些文件已更改

    • microserviceupdated
      变量更新为“true”(如果有) 文件在
      子文件夹A下更改
    • MicroserviceBUpdated
      变量更新为“true”(如果只有
      文件在
      子文件夹A下更改
    等等

  • 为每个微服务创建单独的构建任务,将构建任务配置为在如下自定义条件下运行
  • 用于微服务构建任务

    “自定义条件”:
    和(succeed(),eq(变量['microserviceupdated'],'True'))

    用于MicroserviceB构建任务

    “自定义条件”:
    和(succeed(),eq(变量['MicroserviceBUpdated'],'True'))

    等等

    这样,如果变量的值为
    False

    对于第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"
        }
    }
    

    Jayendran的回答非常好!下面是执行步骤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
        }
    }
    

    在“触发器”选项卡上,有一个选项可以指定要生成的项目的路径。指定该路径后,只有包含与包含/排除规则匹配的修改的提交才会触发生成

    在我的例子中,这是一个比PowerShell脚本更好的解决方案,PowerShell脚本仍然会触发所有项目的构建和发布,垃圾处理我们的空闲时间,并用垃圾填充我们项目的历史


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

    -任务:Bash@3
    displayName:“确定更新了哪些应用”
    投入:
    targetType:“内联”
    脚本:|
    diff=“$(git diff HEAD~--仅限名称)”
    [[“${diff[@]}”=~“包/共享”]&&echo“##vso[task.setvariable=shared_UPDATED]True”
    [[“${DIFFS[@]}”=~“packages/mobile”]]&&echo“##vso[task.setvariable=mobile_UPDATED]True”
    [[“${DIFFS[@]}”=~“packages/web”]]&&echo“##vso[task.setvariable=web_UPDATED]True”
    
    这篇文章对我帮助很大,所以我想添加一些对流程所做的有用修改

    我发现的第一个主要问题是,这个git diff命令不能同时处理多个提交

    git diff HEAD HEAD~ --name-only
    
    HEAD~只查看一次提交,一次推送可以同时包含多个提交

    git diff HEAD HEAD~ --name-only
    
    我意识到,自从管道上次成功运行以来,我需要在HEAD和commit id之间进行区分

    此提交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
    

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

    trigger:
      branches:
        include:
        - master
      paths:
        include:
        - /path/to/src*
    
    请注意,要使用路径触发器,还需要使用分支触发器


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

    trigger:
      branches:
        include:
          - master
      paths:
        include:
          - <service subfolder name>/*
    
    触发器:
    分支机构:
    包括:
    -主人
    路径:
    包括:
    - /*
    
    yaml的paths->include部分告诉azure管道只有在特定路径发生更改时才触发

    没有必要在子文件夹中为azure-pipelines.yml指定不同的名称,可以保留相同的名称。类似地,没有必要将azure-pipelines.yml添加到repo的根目录中,除非在子文件夹之外的根目录中需要构建一些代码。在这种情况下,必须将以下触发器部分添加到
    trigger:
      branches:
        include:
          - master
      paths:
        exclude:
          - <service subfolder name 1>/*
          - <service subfolder name 2>/*