Azure Pipeline步骤列表模板:如何在参数中引用另一参数?
需求背景
需要创建一个包含步骤列表的Azure Pipelines模板,该模板包含steps对象和若干parameters,要求能在其他文件的steps对象中引用此模板,与其他模板合并为单个步骤列表。初始可用模板如下:
parameters: # 要使用的解决方案配置,例如Release、Debug等。 - name: solutionConfig type: string default: Release steps: # 编译目标 - task: VSBuild@1 displayName: 编译目标 inputs: configuration: ${{ parameters.solutionConfig }}
尝试过程及问题
想要新增一个可被用户覆盖的binContentWildcard参数,其默认值需要引用solutionConfig参数的值,尝试了多种写法均遇报错:
1. 参数默认值直接引用另一个参数
尝试直接在binContentWildcard的默认值中使用模板表达式引用solutionConfig,写法如下:
parameters: # 要使用的解决方案配置,例如Release、Debug等。 - name: solutionConfig type: string default: Release # 编译后二进制文件的路径。 - name: binContentWildcard type: string default: '**/${{ parameters.solutionConfig }}/**/*.msi' steps: # 编译目标 - task: VSBuild@1 displayName: 编译目标 inputs: configuration: ${{ parameters.solutionConfig }} # 复制二进制文件到暂存目录 - task: CopyFiles@2 displayName: 复制二进制制品 inputs: contents: ${{ parameters.binContentWildcard }} targetFolder: $(Build.ArtifactStagingDirectory)/bin
运行时Azure Pipelines报错:A template expression is not allowed in this context。
2. 用变量实现运行时解析
根据微软文档说明:
Parameters are only available at template parsing time. Parameters are expanded just before the pipeline runs so that values surrounded by ${{ }} are replaced with parameter values. Use variables if you need your values to be more widely available during your pipeline run.
尝试通过变量处理默认值逻辑,但由于模板是在step上下文被引用,变量仅允许在pipeline、stage或job上下文声明,因此报错Unexpected value,写法如下:
parameters: # 要使用的解决方案配置,例如Release、Debug等。 - name: solutionConfig type: string default: Release # 编译后二进制文件的路径。 - name: binContentWildcard type: string default: '' variables: ${{ if eq(parameters.binContentWildcard, '') }}: binContentWildcardVar: '**/${{ parameters.solutionConfig }}/**/*.msi' ${{ if ne(parameters.binContentWildcard, '') }}: binContentWildcardVar: ${{ parameters.binContentWildcard }} steps: # 编译目标 - task: VSBuild@1 displayName: 编译目标 inputs: configuration: ${{ parameters.solutionConfig }} # 复制二进制文件到暂存目录 - task: CopyFiles@2 displayName: 复制二进制制品 inputs: contents: $(binContentWildcardVar) targetFolder: $(Build.ArtifactStagingDirectory)/bin
3. 使用运行时表达式语法
尝试用$[]运行时表达式语法设置参数默认值,结果是将字符串字面量"$[ parameters.binContentWildcard ]"直接传入contents输入项,未达到预期效果,写法如下:
parameters: # 要使用的解决方案配置,例如Release、Debug等。 - name: solutionConfig type: string default: Release # 编译后二进制文件的路径。 - name: binContentWildcard type: string default: '**/$[ parameters.solutionConfig ]/**/*.msi' steps: # 编译目标 - task: VSBuild@1 displayName: 编译目标 inputs: configuration: ${{ parameters.solutionConfig }} # 复制二进制文件到暂存目录 - task: CopyFiles@2 displayName: 复制二进制制品 inputs: contents: $[ parameters.binContentWildcard ] targetFolder: $(Build.ArtifactStagingDirectory)/bin
可行解决方案
可以利用模板解析阶段的条件表达式或coalesce函数,直接在任务输入中处理默认值逻辑,无需额外声明变量,完全符合步骤模板的上下文限制。
方案1:条件模板表达式
parameters: # 要使用的解决方案配置,例如Release、Debug等。 - name: solutionConfig type: string default: Release # 编译后二进制文件的路径,为空时使用默认路径。 - name: binContentWildcard type: string default: '' steps: # 编译目标 - task: VSBuild@1 displayName: 编译目标 inputs: configuration: ${{ parameters.solutionConfig }} # 复制二进制文件到暂存目录 - task: CopyFiles@2 displayName: 复制二进制制品 inputs: contents: ${{ if eq(parameters.binContentWildcard, '') }}: '**/${{ parameters.solutionConfig }}/**/*.msi' ${{ else }}: ${{ parameters.binContentWildcard }} targetFolder: $(Build.ArtifactStagingDirectory)/bin
方案2:使用coalesce函数
coalesce函数会返回第一个非空值,更简洁地实现默认值逻辑:
parameters: # 要使用的解决方案配置,例如Release、Debug等。 - name: solutionConfig type: string default: Release # 编译后二进制文件的路径,为空时使用默认路径。 - name: binContentWildcard type: string default: '' steps: # 编译目标 - task: VSBuild@1 displayName: 编译目标 inputs: configuration: ${{ parameters.solutionConfig }} # 复制二进制文件到暂存目录 - task: CopyFiles@2 displayName: 复制二进制制品 inputs: contents: ${{ coalesce(parameters.binContentWildcard, format('**/{0}/**/*.msi', parameters.solutionConfig)) }} targetFolder: $(Build.ArtifactStagingDirectory)/bin
这两种方法都在模板解析阶段就确定了contents的最终值,既满足了binContentWildcard参数可被用户覆盖的需求,又适配了步骤模板的上下文限制。
内容的提问来源于stack exchange,提问作者Drew M

