问题描述
在使用TeamCity构建链时遇到了一个问题。他在构建链中有两个步骤:build
和test
,并且有一个依赖于它们的步骤docker publish
。他开启了”当依赖构建失败时取消构建”选项,这意味着如果build
或test
失败,排队的docker publish
步骤将被取消。然而,如果build
失败,test
步骤仍然会继续运行,反之亦然。用户希望能够在任何一个步骤失败时取消所有同级任务,或者如果一个依赖步骤被取消(例如docker publish
),那么所有当前正在运行的该依赖步骤的子任务都会被停止。他在TeamCity的社区论坛上找到了一个类似的问题,但不确定链接的YouTrack问题是否真正解决了这个问题。
解决方案
请注意以下操作可能涉及到TeamCity API的使用,请确保您对其操作有足够的了解。
要实现在TeamCity中取消同级依赖的快照关系,您可以使用TeamCity API来实现这一功能。以下是一个解决方案的示例,这个示例中使用了一个bash脚本来完成操作。这个脚本被扩展了,以在构建脚本失败时触发相应的操作。
方案
- 在
build.sh
和test.sh
的构建脚本中,扩展失败函数,这是一个在构建脚本失败时调用的简单bash函数。
teamcityFailure () {
. ./cancel_build_chain.sh
echo "##teamcity[buildProblem description='$1']"
exit 1
}
- 创建一个名为
cancel_build_chain.sh
的新脚本,用于处理取消操作。该脚本的逻辑如下:
#!/bin/bash
teamcityProgress () {
echo "##teamcity[progressMessage '$1']"
}
teamcityProgress "Build step has failed, attempting to cancel the rest of the build chain..."
BUILD_ID=$TEAMCITY_BUILD_ID # 从构建链配置中传递的
# 使用当前失败步骤ID查询快照依赖关系
FINAL_STEP_DATA=$(curl --silent --request GET \
"https://teamcity/app/rest/builds/project:MyProjectName,snapshotDependency:(from:(id:$BUILD_ID),includeInitial:true),defaultFilter:false" \
--header "Content-Type: application/xml")
# 从最终的“docker publish”步骤中解析出所有依赖步骤ID。其中一个是当前步骤,其他的是其兄弟步骤
# 这一步骤需要进行两次,一次针对排队的步骤,一次针对当前运行的步骤。因为我们需要以不同的方式取消运行中和排队中的构建
QUEUED_DEPENDENT_STEP_IDS=$(echo $FINAL_STEP_DATA | grep -Eo '<snapshot-dependencies.+<build id="[0-9]+".+state="queued"' \
| grep -Eo 'id="([0-9]+)"' | grep -Eo '[0-9]+')
QUEUED_DEPENDENT_STEP_IDS=${QUEUED_DEPENDENT_STEP_IDS/$BUILD_ID/}
QUEUED_DEPENDENT_STEP_IDS=${QUEUED_DEPENDENT_STEP_IDS/ /}
RUNNING_DEPENDENT_STEP_IDS=$(echo $FINAL_STEP_DATA | grep -Eo '<snapshot-dependencies.+<build id="[0-9]+".+state="running"' \
| grep -Eo 'id="([0-9]+)"' | grep -Eo '[0-9]+')
RUNNING_DEPENDENT_STEP_IDS=${RUNNING_DEPENDENT_STEP_IDS/$BUILD_ID/}
RUNNING_DEPENDENT_STEP_IDS=${RUNNING_DEPENDENT_STEP_IDS/ /}
# 取消所有排队中的依赖步骤
for DEP_ID in $QUEUED_DEPENDENT_STEP_IDS
do
teamcityProgress "Cancelling queued build step $DEP_ID"
curl --silent --request POST \
"https://teamcity/app/rest/buildQueue/project:MyProjectName,id:$DEP_ID" \
--data "<buildCancelRequest comment='Another part of the build chain failed so this sibling step was cancelled.' readdIntoQueue='false' />" \
--header "Content-Type: application/xml"
done
# 取消所有运行中的依赖步骤
for DEP_ID in $RUNNING_DEPENDENT_STEP_IDS
do
teamcityProgress "Cancelling running build step $DEP_ID"
curl --silent --request POST \
"https://teamcity/app/rest/builds/project:MyProjectName,id:$DEP_ID" \
--data "<buildCancelRequest comment='Another part of the build chain failed so this sibling step was cancelled.' readdIntoQueue='false' />" \
--header "Content-Type: application/xml"
done
这个解决方案不太优雅,但能够实现目标,防止构建代理在已经失败的构建步骤上继续运行。根据实际需要,您可以根据此示例进一步优化或适应您的环境。
总结
在TeamCity中,通过使用TeamCity API,您可以编写脚本来在构建步骤失败时取消同级依赖的快照关系。这个解决方案允许您在一个依赖步骤被取消时,停止所有当前正在运行的该依赖步骤的子任务,以确保构建链的正确性。希望这个解决方案能够帮助您解决您的问题。
如果您想了解更多有关TeamCity的定制和扩展的信息,可以参考TeamCity的官方文档和社区论坛。