Azure Pipelines能否基于运行时数组变量而非数组参数循环执行任务?
Azure Pipelines 运行时动态生成多缓存任务问题
我们知道在Azure Pipelines中可以基于参数提供的数组值迭代执行任务,示例如下:
template.yml
parameters: param: [] jobs: - ${{each p in parameters.param}}: - script: 'echo ${{ p }}'
pipeline.yml
steps: - template: template.yml parameters: param: ["a", "b"]
但这种方式需要在管道编译时就确定param的取值。我的使用场景需要运行Cache@2任务,为构建流程产出的数量、名称均不固定的文件生成独立的缓存项。
我已经可以通过如下bash任务查找并列出这些文件:
steps: - bash | FILE_LIST='' while IFS= read -r; do FILE_LIST+=" $REPLY " done < <(find ../../build -name '*.desired_extension' -type d | xargs basename)
之后我可以通过如下命令将该列表暴露为其他任务可调用的变量(数组语法仅为表达意图,不确定是否正确):
echo "##vso[task.setvariable variable=fileList]\"[$FILE_LIST]\""
但我在这里遇到了问题:任务循环仅支持参数驱动,不支持变量驱动,我无法基于这个运行时计算得到的变量触发动态数量的Cache@2任务。是否有其他方案可以实现运行时才确定数量的多缓存实例创建需求?
可行解决方案
以下两种方案均可实现需求,可根据自身场景选择:
方案1:拆分多阶段+动态作业矩阵
该方案利用Azure Pipelines支持运行时生成作业矩阵的特性,拆分两个阶段实现动态缓存任务创建,优势是每个缓存任务独立运行,日志、重试逻辑互不干扰。
- 第一阶段仅做文件探测,输出符合矩阵格式的结构化变量
stages: - stage: DetectFiles jobs: - job: DetectJob steps: - bash: | # 探测目标目录,生成矩阵所需的JSON结构 MATRIX_JSON="{" FIRST_ENTRY=1 while IFS= read -r fileName; do if [ $FIRST_ENTRY -eq 0 ]; then MATRIX_JSON+="," fi MATRIX_JSON+="\"$fileName\": {\"fileName\": \"$fileName\"}" FIRST_ENTRY=0 done < <(find ../../build -name '*.desired_extension' -type d | xargs basename) MATRIX_JSON+="}" # 输出为阶段级别的输出变量 echo "##vso[task.setvariable variable=fileMatrix;isOutput=true]$MATRIX_JSON" name: detectStep
- 第二阶段引用第一阶段的输出变量生成动态矩阵,每个矩阵项对应一个独立的
Cache@2任务
- stage: ProcessCache dependsOn: DetectFiles variables: fileMatrix: $[ stageDependencies.DetectFiles.DetectJob.outputs['detectStep.fileMatrix'] ] jobs: - job: GenerateCache strategy: matrix: $[ variables.fileMatrix ] steps: - task: Cache@2 inputs: key: 'customCache | "$(fileName)"' path: ../../build/$(fileName) displayName: 缓存$(fileName)
方案2:单作业内循环调用缓存工具
该方案不需要拆分阶段,直接在单个bash任务中循环处理所有文件的缓存逻辑,适合对执行效率要求高、不需要单独任务日志的场景。Cache@2任务的底层依赖Azure官方的Pipeline Cache命令行工具,你可以直接在脚本中循环调用该工具实现相同的缓存效果:
steps: - bash: | # 全局安装Pipeline Cache工具 dotnet tool install --global Azure.Pipeline.Cache.Tool export PATH="$PATH:/root/.dotnet/tools" # 遍历所有目标文件,逐个处理缓存 while IFS= read -r fileName; do CACHE_KEY="customCache|$fileName" CACHE_PATH="../../build/$fileName" # 尝试恢复缓存 pipeline-cache restore --key "$CACHE_KEY" --path "$CACHE_PATH" if [ $? -ne 0 ]; then # 此处添加缓存未命中时的文件生成逻辑 your_build_logic_here "$fileName" # 保存新生成的文件到缓存 pipeline-cache save --key "$CACHE_KEY" --path "$CACHE_PATH" fi done < <(find ../../build -name '*.desired_extension' -type d | xargs basename)
内容的提问来源于stack exchange,提问作者Sam Hanley
相关产品推荐
相关产品推荐

