我有一个包含多个项目的Visual Studio解决方案,每个项目都是一个单独的微服务。对于开发团队来说,将所有服务都放在同一解决方案和git repo中非常方便,因为服务可以相互调用。
Master.sln - SubFolderA - MicroserviceA.sln
- SubFolderB - MicroserviceB.sln
- SubFolderC - MicroserviceC.sln
但是,我想在Azure DevOps发生更改时独立构建/发布单个微服务,因此,如果ServiceA是唯一要更改的服务,则ServiceA是唯一构建和部署的服务。
为此,我创建了一个新的构建管道定义,其中设置了“路径过滤器”,以在微服务文件夹的内容更改时触发构建(因此,每个微服务都添加了一个路径过滤器以进行监视)。
我的问题是,当触发构建时(例如,基于对SubFolderA的更改),我无法告诉构建定义仅在SubFolderA中构建.sln文件。
我可以为每个微服务创建一个单独的构建定义,并在单独的子文件夹上触发每个构建,但这会产生很大的开销,即我将需要维护15个单独的构建定义(对于我构建的每个分支也是如此),并且现在,自托管构建代理程序上所需的存储为NumberOfService x NumberOfBranchesBeingBuild x SizeOfRepo。
有没有一种方法可以使用带有git“路径过滤器”和多个路径的单个构建定义,这反过来又启动了多个构建实例,并将触发构建的路径的值输入到构建定义中,因此告诉构建实例要构建哪个.sln文件?
我希望这是有道理的!
答案 0 :(得分:8)
您可以像下面这样
例如,MicroserviceAUpdated
=“假”,MicroserviceBUpdated
=“假”等,
在构建中获取更改集/提交,以检查哪些文件已更改。
MicroserviceAUpdated
变量更新为“ true”
文件在SubFolderA
下进行了更改。MicroserviceBUpdated
变量更新为“ true” SubFolderA
下进行了更改。等等。
对于MicroserviceA构建任务
“自定义条件”:
and(succeeded(), eq(variables['MicroserviceAUpdated'], 'True'))
对于MicroserviceB构建任务
“自定义条件”:
and(succeeded(), eq(variables['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"
}
}
答案 1 :(得分:6)
在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"
答案 2 :(得分:4)
这篇文章对我有很大帮助,所以我想对自己的流程进行一些有用的修改。
我发现的第一个主要问题是该git diff命令不能一次处理多个提交。
git diff HEAD HEAD~ --name-only
HEAD〜只看1次提交,因为一次推送可以一次包含多个提交。
我意识到自从管道最后一次成功运行以来,我需要在HEAD和提交ID之间进行区别。
git diff HEAD [commit id of last successful build] --name-only
可以通过在/ build /最新端点sourceVersion上调用Azure DevOps API来获得此提交ID。
$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
答案 3 :(得分:3)
Jayendran的答案非常好!这是执行步骤2的一种更加PowerShell-y的方式:
$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
}
}
答案 4 :(得分:3)
为补充deleb的回答,以下是用于设置路径触发器的YAML代码:
trigger:
branches:
include:
- master
paths:
include:
- /path/to/src*
请注意,您还需要具有分支触发器才能使用路径触发器。
答案 5 :(得分:2)
在“触发器”选项卡上,有一个选项可以指定要构建的项目的路径。指定该路径后,只有包含与包含/排除规则匹配的修改的提交才会触发构建。
就我而言,这是一个比PowerShell脚本更好的解决方案,该脚本仍触发所有项目的构建和发布,这些项目散布了我们的Slack并充满了我们项目的历史。
答案 6 :(得分:0)
解决方案是为每个位于子文件夹中的服务创建一个 azure-pipelines.yml。子文件夹中的每个 azure-pipelines.yml 必须具有以下触发器定义。
trigger:
branches:
include:
- master
paths:
include:
- <service subfolder name>/*
路径 -> yaml 的包含部分,告诉 azure 管道仅在该特定路径发生更改时才触发。
子文件夹内的 azure-pipelines.yml 不需要给不同的名称,可以保留相同的名称。同样,没有必要将 azure-pipelines.yml 添加到 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 管道。