如何将复杂的DevOps管道模板参数传递给脚本

时间:2020-01-29 17:15:34

标签: azure-devops yaml azure-pipelines azure-pipelines-yaml

在Azure DevOps管道模板中,我将参数声明为数组/序列

parameters:
  mySubscription: ''
  myArray: []

steps:
- AzureCLI@2
  inputs:
    azureSubscription: ${{ parameters.mySubscription }}
    scriptType: pscore
    scriptPath: $(Build.SourcesDirectory)/script.ps1
    arguments: '-MyYAMLArgument ${{ parameters.myArray }}'

然后将参数值从管道定义传递为

steps:
- template: myTemplate.yml
  parameters:
    mySubscription: 'azure-connection'
    myArray:
    - field1: 'a'
      field2: 'b'
    - field1: 'aa'
      field2: 'bb'

我的问题是我无法按YAML语法(ToString()类)原样传递该数组,以便能够在我的模板中使用PowerShell处理和处理该数组。尝试运行此管道时,出现以下错误: /myTemplate.yml (Line: X, Col: X): Unable to convert from Array to String. Value: Array。错误消息中引用的行/列对应于我模板中的arguments: '-MyYAMLArgument ${{ parameters.myArray }}'

我还尝试将参数映射为脚本的环境

- AzureCLI@2
  inputs:
    azureSubscription: ${{ parameters.mySubscription }}
    scriptType: pscore
    scriptPath: $(Build.SourcesDirectory)/script.ps1
    arguments: '-MyYAMLArgument $Env:MY_ENV_VAR'
  env:
    MY_ENV_VAR: ${{ parameters.myArray }}

这也不起作用: /myTemplate.yml (Line: X, Col: Y): A sequence was not expected。该时间轴/列指向MY_ENV_VAR: ${{ parameters.myArray }}

是否有人面临过类似的要求,即将从管道定义中定义的复杂类型(此处为对象的数组/序列)传递给PowerShell脚本?如果是这样,您是如何实现的?

4 个答案:

答案 0 :(得分:3)

我也面临类似的问题,我的解决方法是使用不同尺寸的分隔符将字符串中的数组弄平。

例如,我想使某些参数成为必需,并且如果未传递这些参数,则会使构建失败,而不是为每个参数添加任务以供检查,而是希望在单个任务中执行此操作。

为此,我首先将一个数组作为参数(传递给另一个名为check-required-params.yml的模板,该模板负责负责检查参数的任务),其中每个元素都是类型为{{1}的字符串},它是name:valueformat的必需参数(用冒号隔开)的串联(使用name表达式:

value

然后在# templates/pipeline-template.yml parameters: - name: endpoint type: string default: '' - name: rootDirectory type: string default: $(Pipeline.Workspace) - name: remoteDirectory type: string default: '/' - name: archiveName type: string default: '' #other stuff - template: check-required-params.yml parameters: requiredParams: - ${{ format('endpoint:{0}', parameters.endpont) }} - ${{ format('archiveName:{0}', parameters.archiveName) }} 中,使用表达式check-required-params.yml连接用分号分隔元素的数组,这将创建类型为${{ join(';', parameters.requiredParams) }}的字符串,并将其作为环境变量传递。 / p>

在这一点上,使用一些字符串操作,在脚本中,我可以使用分号作为分隔符来拆分字符串,这样我将得到一个字符串数组,例如endpoint:value;archiveName:value,我可以进一步拆分,但是这次使用冒号作为分隔符。 我的name:value如下:

check-required-params.yml

然后在我的# templates/check-required-params.yml parameters: - name: requiredParams type: object default: [] steps: - task: PowerShell@2 inputs: script: | $params = $env:REQURED_PARAMS -split ";" foreach($param in $params) { if ([string]::IsNullOrEmpty($param.Split(":")[1])) { Write-Host "##vso[task.logissue type=error;]Missing template parameter $($param.Split(":")[0])" Write-Host "##vso[task.complete result=Failed;]" } } targetType: inline pwsh: true env: REQURED_PARAMS: ${{ join(';', parameters.requiredParams) }} displayName: Check for required parameters 中可以做到:

azure-pipelines.yml

在此示例中,构建失败,因为我没有传递参数#other stuff - template: templates/pipeline-template.yml parameters: endpoint: 'myEndpoint' rootDirectory: $(Pipeline.Workspace)/mycode

您还可以通过使用变量来定义分隔符来增加灵活性,而不是在脚本和表达式中进行硬编码

答案 1 :(得分:3)

您现在可以在 ADO 管道中使用(未记录的)convertToJson 函数将这些类型的参数转换为字符串:

parameters:
  - name: myParameter
    type: object
    default:
        name1: value1
        name2: value2

...

- task: Bash@3
  inputs:
    targetType: inline
    script: |
      echo "${{ convertToJson(parameters.myParameter) }}"

参考:https://developercommunity.visualstudio.com/t/allow-type-casting-or-expression-function-from-yam/880210

答案 2 :(得分:0)

如何将复杂的DevOps管道模板参数传递给脚本

恐怕我们无法将复杂的DevOps管道模板参数传递给PowerShell脚本。

当前,Azure开发人员的任务仅支持一维数组的传输。它不能接受和传送二维数组。尽管我们可以定义二维数组的参数,但是我们需要使用以下脚本从模板扩展参数:

- ${{ each field in parameters.myArray}}:

我们可以像这样使用它:

- ${{ each step in parameters.buildSteps }}:
  #- ${{ each pair in step }}:

    - task: PowerShell@2
      inputs:
        targetType : inline
        script: |
          Write-Host 'Hello World'

但是我们无法将二维数组直接传递给任务,例如:[field1: 'a', field2: 'b']。这就是您收到错误Unable to convert from Array to String的原因。

您可以查看文档Extend from a template了解更多详细信息。

希望这会有所帮助。

答案 3 :(得分:0)

@Leo Liu MSFT mentioned in its answer一样,目前确实不支持此功能,但是已经有人opened an issue for this improvement

此问题现在还包含一个很好的解决方法,现在可以使用环境变量。该解决方案的缺点是您需要了解数据结构才能正确映射它。

parameters:
  mylist:[]
  #where mylist is a sequence of object matching the mapping:
  #- name: 'the name 1'
  #  value: 'the value of 1'
  #  index: 0
  #- name: 'the name 2'
  #  value: 'the value of 2'
  #  index: 1

env:
  ${{ each item in parameters.mylist }}:
    ${{ format('SCRIPT_PARAM_{0}_KEY', item.index) }}: ${{ item.name }}
    ${{ format('SCRIPT_PARAM_{0}_VAL', item.index) }}: ${{ item.value }}