$ {{ if }} 语法在 Azure DevOps YAML 中。

5

我有一组自托管的虚拟机 (MyTestPool),其中一半用于安装和测试“ON”版本(开启了一些功能),另一半用于安装默认版本“OFF”。所有测试代理 VM 都具有“ALL”作为用户定义的能力。其中一半也被标记为“ON”,另一半为“OFF”。

现在我有两个阶段,称为 DEPLOYOFF 和 DEPLOYON,如果变量组变量“skipDeployOffStage”或“skipDeployOnStage”设置为true,则可以跳过这两个阶段。我想要做的是,如果只需要测试 ON/OFF,则使用“ALL”作为代理需求。如果需要同时测试 ON 和 OFF,相应的阶段将要求它们各自的“ON”或“OFF”虚拟机。

问题:${{ if }}不起作用。

trigger: none
pr: none


pool: 'MyBuildPool'

variables:
  - group: TEST_IF_VARIABLE_GROUP
  - name: subPool
    value: 'ON'
  - name: useAllPool
    value: $[ or(eq( variables.skipDeployOnStage, true), eq( variables.skipDeployOffStage, true)) ]
    
stages:
- stage: DEPLOYOFF
  condition: ne(variables['skipDeployOffStage'], 'true')

  variables:
    # The test stage's subpool
    ${{ if variables.useAllPool }}:
      subPool: 'ALL'
    ${{ if not(variables.useAllPool)  }}:
      subPool: 'OFF'

  pool: 
    name: 'MyTestPool'
    demands: 
      - ${{ variables.subPool }}

  jobs:
  - job:

    steps:
    - checkout: none
    - pwsh: |
        Write-Host ("Value of useAllPool is: {0}" -f '$(useAllPool)')
        Write-Host ("Value of VG variable 'skipDeployOnStage' is {0} and 'skipDeployOffStage' is {1}" -f '$(skipDeployOnStage)', '$(skipDeployOffStage)')
        Write-Host ("Subpool is {0}" -f '$(subPool)')
      displayName: 'Determined SubPool'

当其中一个标志为假时的输出:

2020-08-02T18:39:05.5849160Z Value of useAllPool is: True
2020-08-02T18:39:05.5854283Z Value of VG variable 'skipDeployOnStage' is true and 'skipDeployOffStage' is false 
2020-08-02T18:39:05.5868711Z Subpool is ALL

当两者都为假时的输出:

2020-08-02T18:56:40.5371875Z Value of useAllPool is: False
2020-08-02T18:56:40.5383258Z Value of VG variable 'skipDeployOnStage' is false and 'skipDeployOffStage' is false
2020-08-02T18:56:40.5386626Z Subpool is ALL

我错过了什么?


@JaneMa-MSFT:非常抱歉,我并不是有意冒犯。感谢您的帮助。然而,您的解决方案并没有真正向我展示如何实现我想要完成的目标。因为编译时的值并不能解决我的问题。我将我的结论作为答案发布了,因为它作为评论太长了。 - Vyas Bharghava
2个回答

5

有两个问题导致你的代码运行不正确:

1. ${{if}}语法: 你写${{if}}的方式是错误的,正确的脚本如下:

${{ if eq(variables['useAllPool'], true)}}:
   subPool: 'ALL'
${{ if ne(variables['useAllPool'], true)}}:
   subPool: 'OFF'

2. 变量 useAllPool 的定义。

您使用了运行时表达式 ($[ <expression> ]),因此当 ${{if}} 运行时,变量 variables.useAllPool 的值为 '$[ or(eq( variables.skipDeployOnStage, true), eq( variables.skipDeployOffStage, true)) ]',而不是 truefalse

为解决这个问题,您需要使用编译时表达式 ${{ <expression> }}

但是,使用编译时表达式时,它不能包含来自变量组的变量。因此,您需要将变量 skipDeployOnStageskipDeployOffStage 从变量组移动到 YAML 文件中。

因此,您可以按照以下步骤解决该问题:

1. 从变量组 TEST_IF_VARIABLE_GROUP 中删除变量 skipDeployOnStageskipDeployOffStage

2. 修改 YAML 文件:

trigger: none
pr: none
 
 
pool: 'MyBuildPool'
 
variables:
  - group: TEST_IF_VARIABLE_GROUP
  - name: subPool
    value: 'ON'
  - name: skipDeployOnStage
    value: true
  - name: skipDeployOffStage
    value: false
  - name: useAllPool
value: ${{ or(eq( variables.skipDeployOnStage, true), eq( variables.skipDeployOffStage, true)) }}
    
stages:
- stage: DEPLOYOFF
  condition: ne(variables['skipDeployOffStage'], 'true')
 
  variables:
    # The test stage's subpool
    ${{ if eq(variables['useAllPool'], true)}}:
      subPool: 'ALL'
    ${{ if ne(variables['useAllPool'], true)}}:
      subPool: 'OFF'
  pool: 
    name: 'MyTestPool'
    demands: 
      - ${{ variables.subPool }}
 
  jobs:
  - job:
 
    steps:
    - checkout: none
    - pwsh: |
        Write-Host ("Value of useAllPool is: {0}" -f '$(useAllPool)')
        Write-Host ("Value of VG variable 'skipDeployOnStage' is {0} and 'skipDeployOffStage' is {1}" -f '$(skipDeployOnStage)', '$(skipDeployOffStage)')
        Write-Host ("Subpool is {0}" -f '$(subPool)')
      displayName: 'Determined SubPool'

您可以在 YAML 文件中修改 skipDeployOnStageskipDeployOffStage 的值来测试此解决方案是否有效。

我实际上需要在运行时完成这个任务。这些值将需要在运行时确定。怎么做呢?使用Powershell吗? - Vyas Bharghava
是的,您可以使用PowerShell或任何其他命令行任务来设置运行时变量。但是,我想知道您想在哪个作业中运行PowerShell任务?因为在运行作业之前,您需要决定使用哪个池。 - Jane Ma-MSFT

2

我的需求:

  • 拥有一个自托管的虚拟机池,例如20台机器
  • 其中10台具有“OFF”作为用户能力(名称为OFF和值为空白),另外10台具有“ON”作为用户能力(名称为ON和值为空白)
  • 所有机器都具有“ALL”作为附加用户能力
  • 该流水线基本上在池中的指定机器上安装2个产品变体并对其进行测试(ON / OFF)
  • 当用户想要运行OFF和ON部署时,我有阶段要求OFF或ON运行
  • 我想要做的是,当用户只想要ON或OFF部署时,为了节省时间,我想使用所有20台机器进行部署和测试,以便减少总体测试时间。

我曾经试图在运行时徒劳地替换池需求,因为我不想每次都在运行前更新20-50个VM的用户能力。如果使用传统的需求语法,那就是我必须做的事情:

  pool: 
    name: 'MyTestPool'
    demands: 
      # There's no OR or other syntax supported here
      # LVALUE must be a built-in variable such as Agent.Name OR a User capability
      # I will have to manually change the DeploymentType before the pipeline is run
      - DeploymentType -equals $(subPool)  

所以,我试图在运行时确定subPool的值,并使用以下语法,这样我就不必在运行之前手动配置用户功能。

pool:
  name: ${{ parameters.pool }}
  demands:
    - ${{ parameters.subPool}}

这是我的研究:
您绝对可以混合编译和运行时表达式。编译时表达式评估为编译时的值。如果它是一个表达式或变量(而不是常量),整个表达式或变量将被替换,正如Jane Ma-MSFT所指出的那样。
例如,我已经能够在编译时表达式中使用队列时间变量而没有问题。例如,我已经使用哪个池作为队列时间变量,然后将其传递给一个使用编译时语法的模板来使用该值。
parameters:
  - name: pool
    type: string  

jobs:
  - job: ExecAllPrerequisitesJob
    displayName: 'Run Stage prerequisites one time from a Single agent'

    pool:
      name: ${{ parameters.pool }}

然而,真正的问题在于您在哪里使用编译时表达式。 在上面的示例中,整个 ${{ parameters.pool }} 都被 $(buildPool) 替换为编译时的队列变量。 但是,pool 支持使用变量作为池名称。 这非常复杂且未经记录,您可以在其中使用表达式、变量(编译或运行)以及必须使用常量的位置。
一个这样的例子:
jobs:
- job: SliceItFourWays
  strategy:
    parallel: 4  # $[ variables['noOfVMs'] ] is the ONLY syntax that works to replace 4

在某些情况下,例如 Pool demands(池需求)等地方,Microsoft 的 YAML 解析器会尽职地替换变量。然而,运行时不支持将自定义变量作为 LVALUE。它只支持在需求的 RVALUE 部分中评估自定义运行时变量。
  pool: 
    name: ${{ parameters.buildPool }} # Run time supports variables here
    demands: 
      - ${{ parameters.subPool }}  # LVALUE: Must be resolved to a CONSTANT at compile time
      - poolToRunOn -equals '${{ parameters.subPool }}'  # RVALUE... custom user capability.  This evaluates and applies the demand correctly.

结论:

微软的 YAML 实现太差劲了!


非常有用,谢谢。但我认为代码中有个 bug - poolToRunOn -equals '${{ parameters.subPool }}' 无法使用引号。这样可以:- poolToRunOn -equals ${{ parameters.subPool }}。 - Rye bread
@Ryebread 这是必需的,以防 subPool 值中有一个或多个空格。 - Vyas Bharghava

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接