【问题标题】:Azure pipeline expression does not work in templateAzure 管道表达式在模板中不起作用
【发布时间】:2021-03-01 20:17:47
【问题描述】:

我有一些模板,我想检查是否设置了变量。 所以我尝试了这个:

包含的模板:

 - ${{if not(variables.assemblyVersion)}}:
   - task: PowerShell@2
     inputs:
       targetType: 'inline'
       script: |
         Write-Host $(assemblyVersion)
         throw "assemblyVersion was not set"

但即使将 assemblyVersion 设置为某个值(例如 1.2.3.4),该任务仍在运行。 我做错了什么?

编辑:尝试了 Krzysztof Madej 的答案,我得到了误报:

输出:

2020-11-19T09:36:30.7383677Z ##[section]Starting: PowerShell
2020-11-19T09:36:30.7500976Z ==============================================================================
2020-11-19T09:36:30.7501272Z Task         : PowerShell
2020-11-19T09:36:30.7501523Z Description  : Run a PowerShell script on Linux, macOS, or Windows
2020-11-19T09:36:30.7501778Z Version      : 2.170.1
2020-11-19T09:36:30.7501984Z Author       : Microsoft Corporation
2020-11-19T09:36:30.7502296Z Help         : https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/powershell
2020-11-19T09:36:30.7502761Z ==============================================================================
2020-11-19T09:36:31.9944831Z Generating script.
2020-11-19T09:36:32.1228113Z ========================== Starting Command Output ===========================
2020-11-19T09:36:32.1504771Z ##[command]"C:\windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command ". 'D:\a\_temp\2af656c2-be5b-4a73-8812-17185fff83cc.ps1'"
2020-11-19T09:36:32.4080866Z 1.2.3.4
2020-11-19T09:36:32.7066175Z assemblyVersion was not set
2020-11-19T09:36:32.7066649Z At D:\a\_temp\2af656c2-be5b-4a73-8812-17185fff83cc.ps1:4 char:1
2020-11-19T09:36:32.7067329Z + throw "assemblyVersion was not set"
2020-11-19T09:36:32.7068304Z + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2020-11-19T09:36:32.7069103Z     + CategoryInfo          : OperationStopped: (assemblyVersion was not set:String) [], RuntimeException
2020-11-19T09:36:32.7069840Z     + FullyQualifiedErrorId : assemblyVersion was not set
2020-11-19T09:36:32.7070536Z  
2020-11-19T09:36:32.8288504Z ##[error]PowerShell exited with code '1'.
2020-11-19T09:36:32.8929792Z ##[section]Finishing: PowerShell

设置yaml的主管道:

trigger:
- master
- feature/*

pool:
  vmImage: 'windows-latest'

variables:
- group: HmiSulis
- name: solution
  value:  AllProjects.sln
- name: buildPlatform
  value: x86
- name: buildConfiguration
  value:  Debug
- name: assemblyVersion
  value: 1.2.3.4
- name: fileVersion
  value: 5.6.7.8
- name: informationalVersion
  value: 9.10.11.12

resources:
  repositories:
    - repository: BuildTemplates
      type: git
      name: HMI/BuildTemplates

extends:
  template: netFx/Jobs/netFx.Build.yml@BuildTemplates

使用的工作:

jobs:
- job: Build
  steps:
  - template: ../../NuGet/Steps/NuGet.Restore.yml
  - template: ../Steps/netFx.Build.Version.yml
  - template: ../Steps/netFx.Build.yml

检查步骤 (netFx.Build.Version.yml):

steps:
- ${{if not(variables['assemblyVersion'])}}:
  - task: PowerShell@2
    inputs:
      targetType: 'inline'
      script: |
        Write-Host $(assemblyVersion)
        throw "assemblyVersion was not set"
- ${{if not(variables['fileVersion'])}}:
  - task: PowerShell@2
    inputs:
      targetType: 'inline'
      script: |
        throw "fileVersion was not set"
- ${{if not(variables['informationalVersion'])}}:
  - task: PowerShell@2
    inputs:
      targetType: 'inline'
      script: |
        throw "informationalVersion was not set"                
- task: Assembly-Info-NetFramework@2
  inputs:
    Path: '$(Build.SourcesDirectory)'
    FileNames: |
      **\AssemblyInfo.cs
      **\AssemblyInfo.vb
    InsertAttributes: true
    FileEncoding: 'auto'
    WriteBOM: false
    VersionNumber: '$(assemblyVersion)'
    # File version in windows explorer
    FileVersionNumber: '$(fileVersion)'
    # Product version in windows explorer
    InformationalVersion: '$(informationalVersion)'
    LogLevel: 'verbose'
    FailOnWarning: false
    DisableTelemetry: false

【问题讨论】:

    标签: azure-devops azure-pipelines


    【解决方案1】:

    请使用正确的语法,如here所示:

    variables:
      ${{ if eq(variables['Build.SourceBranchName'], 'master') }}: # only works if you have a master branch
        stageName: prod
    
    pool:
      vmImage: 'ubuntu-latest'
    
    steps:
    - script: echo ${{variables.stageName}}
    
    

    所以在你的情况下它会是

     - ${{if not(variables['assemblyVersion'])}}:
       - task: PowerShell@2
         inputs:
           targetType: 'inline'
           script: |
             Write-Host $(assemblyVersion)
             throw "assemblyVersion was not set"
    

    您可以使用 if 子句有条件地分配值或变量或设置任务的输入。条件仅在使用模板语法时有效。

    我简化了你的情况,它有效:

    variables:
    - name: solution
      value:  AllProjects.sln
    - name: buildPlatform
      value: x86
    - name: buildConfiguration
      value:  Debug
    - name: assemblyVersion
      value: ''
    #  value: 1.2.3.4
    - name: fileVersion
      value: 5.6.7.8
    - name: informationalVersion
      value: 9.10.11.12
    
    pool:
      vmImage: 'ubuntu-latest'
    
    jobs:
    - job: Build
      variables: 
      - name: test
        value: $[not(variables['assemblyVersion'])]
      steps:
      - ${{if not(variables['assemblyVersion'])}}:
        - task: PowerShell@2
          continueOnError: true
          inputs:
            targetType: 'inline'
            script: |
              Write-Host $(assemblyVersion)
              throw "assemblyVersion was not set"
      - task: PowerShell@2
        continueOnError: true
        inputs:
          targetType: 'inline'
          script: |
            Write-Host $(assemblyVersion)
            Write-Host $(test)
    

    所以当给定assemblyVersion 时,任务被跳过。并且当没有给出任务时运行并失败。请注意$(assemblyVersion) 这意味着即使未设置变量也必须可用。

    我做了进一步的测试,将逻辑转移到模板。所以这是我的模板:

    jobs:
    - job: BuildFromTemplate
      dependsOn: []
      variables: 
      - name: test
        value: $[not(variables['assemblyVersion'])]
      steps:
      - ${{if not(variables['assemblyVersion'])}}:
        - task: PowerShell@2
          continueOnError: true
          inputs:
            targetType: 'inline'
            script: |
              Write-Host $(assemblyVersion)
              throw "assemblyVersion was not set"
      - task: PowerShell@2
        continueOnError: true
        inputs:
          targetType: 'inline'
          script: |
            Write-Host $(assemblyVersion)
            Write-Host $(test)
    

    这是管道:

    variables:
    - name: assemblyVersion
    #  value: ''
      value: 1.2.3.4
    
    
    pool:
      vmImage: 'ubuntu-latest'
    
    stages:
    - stage: A
      jobs:
      - job: Build
        variables: 
        - name: test
          value: $[not(variables['assemblyVersion'])]
        steps:
        - ${{if not(variables['assemblyVersion'])}}:
          - task: PowerShell@2
            continueOnError: true
            inputs:
              targetType: 'inline'
              script: |
                Write-Host $(assemblyVersion)
                throw "assemblyVersion was not set"
        - task: PowerShell@2
          continueOnError: true
          inputs:
            targetType: 'inline'
            script: |
              Write-Host $(assemblyVersion)
              Write-Host $(test)
      - template: template.yaml
    

    是的,模板中的作业失败:

    看起来很奇怪,because

    运行时和编译时表达式语法之间的区别主要在于可用的上下文。在编译时表达式 (${{ }}) 中,您可以访问参数和静态定义的变量。在运行时表达式 ($[ ]) 中,您可以访问更多变量,但不能访问参数。

    assemblyVersion 是静态定义的变量。

    看起来我们只能在模板中使用模板表达式中的参数而不是变量。

    我为此在开发者社区创建了一个bug

    恕我直言,如果您想使用模板,您需要将此条件移动到任务中并跳过逻辑。

      - task: PowerShell@2
        continueOnError: true
        inputs:
          targetType: 'inline'
          script: |
            $ver = '$(assemblyVersion)'
            Write-Host "Ver: $($ver)"
            if (!$ver)
            {
              throw "assemblyVersion was not set"
            }
    

    或者使用模板变量并在主文件和模板文件中重复使用:

    parameters:
    - name: 'variabaleTemplate'
      default: 'variables.yaml'
      type: string
    
    jobs:
    - job: BuildFromTemplate
      dependsOn: []
      variables:
      - template: ${{parameters.variabaleTemplate}}
      - name: test
        value: $[not(variables['assemblyVersion'])]
      steps:
      - ${{if not(variables['assemblyVersion'])}}:
        - task: PowerShell@2
          continueOnError: true
          inputs:
            targetType: 'inline'
            script: |
              Write-Host $(assemblyVersion)
              throw "assemblyVersion was not set"
    

    variables.yaml 一样

    variables:
    - name: assemblyVersion
    #  value: ''
      value: 1.2.3.4
    

    主文件如下:

    stages:
    - stage: A
      variables:
      - template: variables.yaml
      jobs:
      - template: template2.yaml
    

    所以我得到了回复from MS

    出于安全原因,我们只允许您通过显式参数将信息传递到模板代码中。 https://docs.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops

    这意味着使用您的模板的管道的作者需要提交更改,他们明确地将所需的信息传递到您的模板代码中。

    这有一些例外,变量是在同一个文件中或在管道编译时静态定义的,但一般来说,最好对不涉及系统定义的只读动态变量的所有内容使用参数和自定义的动态输出变量。

    因此,我认为使用单独的变量模板 yaml 的解决方案是最好的。否则,您需要通过模板参数传递所有值。

    【讨论】:

    • "恕我直言,如果您想使用模板,您需要将此条件移动到任务中并跳过逻辑。"我猜你是对的,尽管文档真的让我相信这是可能的,另外还有一个好处是,如果检查成功,任务甚至根本不会运行或出现。不管怎样,我正在看你发布的错误报告。
    • 您仍然可以使用原来的方法,但您需要将变量声明移动到模板并在作业模板上重复使用。
    • @sommmen 你有机会用变量模板检查解决方案吗?
    • 嗨,一个单独的模板文件的缺点是现在必须在 2 个地方配置管道,但它似乎可以工作。您提到的另一条路线也是一个不错的选择。不幸的是,我仍然很忙,但在适当的时候我会决定使用其中一个。仍在监视您的错误报告,尽管 Microsoft 似乎还不急于回答。无论如何,非常感谢您坚持这一点,我学到了很多 - 我已将赏金奖励给您的努力。
    • 不要失去希望。上次我报告了一个错误并收到通知说需要一个适当的团队进行检查时,我收到的下一条消息是该错误已修复,并将在接下来的几周内推出。
    猜你喜欢
    • 1970-01-01
    • 2018-02-14
    • 2019-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-31
    • 2021-12-08
    • 2016-06-06
    相关资源
    最近更新 更多