定义变量

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

变量为你提供了一种简便方法,可以将关键数据位导入管道的各个部分。 变量的最常见用途是定义一个值,然后可以在管道中使用该值。 所有变量都是字符串,并且是可变的。 变量的值可以针对管道的特定运行和作业更改。

在具有相同名称的多个位置定义同一变量时,最本地范围的变量优先。 因此,在作业级别定义的变量可以重写在阶段级别设置的变量。 在阶段级别定义的变量会重写在管道根级别设置的变量。 管道根级别中设置的变量会重写管道设置 UI 中设置的变量。 要详细了解如何使用在作业、阶段和根级别定义的变量,请参阅变量范围

可以将变量与表达式一起使用,以便根据条件进行赋值并进一步自定义管道。

变量不同于运行时参数。 运行时参数是类型化参数,在模板分析期间可用。

用户定义的变量

定义变量时,可以使用不同的语法(宏、模板表达式或运行时),所使用的语法决定了变量在管道中呈现的位置。

在 YAML 管道中,可以在根级别、阶段级别和作业级别设置变量。 还可以在 UI 中指定 YAML 管道外部的变量。 在 UI 中设置变量时,可以加密该变量并将其设置为机密。

用户定义的变量可以设置为只读。 需遵守变量的命名限制(例如:不能在变量名称的开头使用 secret)。

可以使用变量组以使变量在多个管道中可用。

使用模板可在多个管道中使用的一个文件中定义变量。

用户定义的多行变量

Azure DevOps 支持多行变量,但存在一些限制。

下游组件(如管道任务)可能无法正确处理变量值。

Azure DevOps 不会更改用户定义的变量值。 在作为多行变量传递之前,需要正确设置变量值的格式。 设置变量格式时,请避免使用特殊字符,不要使用受限名称,并确保使用适用于代理操作系统的行结束符格式。

多行变量的具体行为取决于操作系统。 要避免这种情况,请确保为目标操作系统正确设置多行变量的格式。

即使提供不受支持的格式设置,Azure DevOps 也不会更改变量值。

系统变量

除了用户定义的变量外,Azure Pipelines 还具有系统变量,系统变量包含预定义的值。 例如,预定义变量 Build.BuildId 会为每个生成提供 ID,并可用于标识不同的管道运行。 如果需要唯一值,可以在脚本或任务中使用 Build.BuildId 变量。

如果使用 YAML 或经典生成管道,请参阅预定义变量以获取系统变量的完整列表。

如果使用经典发布管道,请参阅发布变量

运行管道时,系统变量使用其当前值进行设置。 某些变量是自动设置的。 作为管道作者或最终用户,可以在管道运行之前更改系统变量的值。

系统变量是只读的。

环境变量

环境变量特定于正在使用的操作系统。 环境变量以特定于平台的方式注入到管道中。 格式对应于为特定脚本平台设置环境变量的格式的方式。

在 UNIX 系统上(macOS 和 Linux),环境变量的格式为 $NAME。 在 Windows 上,对于批处理,格式为 %NAME%,在 PowerShell 中,格式为 $env:NAME

系统变量和用户定义的变量也会作为平台的环境变量注入。 当变量转换为环境变量时,变量名称变为大写,句点变为下划线。 例如,变量名称 any.variable 将成为变量名称 $ANY_VARIABLE

环境变量需遵循变量命名限制(例如:不能在变量名称开头使用 secret)。

变量命名限制

用户定义的变量和环境变量可以包含字母、数字、._ 字符。 不要使用系统保留的变量前缀。 分别是 endpointinputsecretpathsecurefile。 任何以这些字符串开头的变量(无论大写)都不适用于任务和脚本。

了解变量语法

Azure Pipelines 支持三种不同的方式来引用变量:宏、模板表达式和运行时表达式。 可以将每个语法用于不同的目的,并且每个语法都有一些限制。

在管道中,模板表达式变量 (${{ variables.var }}) 在运行时开始之前,在编译时得到处理。 宏语法变量 ($(var)) 在任务运行之前得到处理。 运行时表达式 ($[variables.var]) 也在运行时处理,但旨在与条件表达式一起使用。 使用运行时表达式时,该表达式必须占据定义的整个右侧。

在此示例中,可以看到模板表达式在更新变量后仍具有变量的初始值。 宏语法变量的值将更新。 模板表达式值不会更改,因为在任务运行之前,所有模板表达式变量都会在编译时进行处理。 而宏语法变量在每个任务运行之前计算。

variables:
- name: one
  value: initialValue 

steps:
  - script: |
      echo ${{ variables.one }} # outputs initialValue
      echo $(one)
    displayName: First variable pass
  - bash: echo "##vso[task.setvariable variable=one]secondValue"
    displayName: Set new variable value
  - script: |
      echo ${{ variables.one }} # outputs initialValue
      echo $(one) # outputs secondValue
    displayName: Second variable pass

宏语法变量

大多数文档示例使用宏语法 ($(var))。 宏语法旨在将变量值内插到任务输入和其他变量中。

采用宏语法的变量在运行时进行处理(执行任务之前)。 运行时在模板扩展后发生。 系统遇到宏表达式时,会将表达式替换为变量的内容。 如果没有该名称的变量,则宏表达式不会更改。 例如,如果无法替换 $(var),则 $(var) 不会替换为任何内容。

宏语法变量保持不变,没有值,因为空值(如 $())可能对你正在运行的任务有意义,代理不应假定你希望替换该值。 例如,如果在 bash 任务中使用 $(foo) 来引用变量 foo,则替换任务输入中的所有 $() 表达式可能会破坏 bash 脚本。

宏变量仅在用于值时展开,而不是作为关键字。 值显示在管道定义的右侧。 以下内容有效:key: $(value)。 以下内容无效:$(key): value。 当用于以内联方式显示作业名称时,宏变量不会展开。 而是必须使用 displayName 属性。

注意

宏语法变量仅针对 stagesjobssteps 展开。 例如,不能在 resourcetrigger 中使用宏语法。

此示例将宏语法与 Bash、PowerShell 和脚本任务一起使用。 使用宏语法调用变量的语法对于这三者都是相同的。

variables:
 - name: projectName
   value: contoso

steps: 
- bash: echo $(projectName)
- powershell: echo $(projectName)
- script: echo $(projectName)

模板表达式语法

可以使用模板表达式语法展开模板参数和变量 (${{ variables.var }})。 模板变量在编译时进行处理,并在运行时启动之前被替换。 模板表达式旨在将 YAML 的某些部分重用为模板。

找不到替换值时,模板变量以无提示方式合并为空字符串。 模板表达式与宏和运行时表达式不同,可以显示为键(左侧)或值(右侧)。 以下内容有效:${{ variables.key }} : ${{ variables.value }}

运行时表达式语法

可以将运行时表达式语法用于在运行时扩展的变量 ($[variables.var])。 找不到替换值时,运行时表达式变量以无提示方式合并为空字符串。 在作业条件中使用运行时表达式,可支持按条件执行作业或执行整个阶段。

运行时表达式变量仅在用于值时展开,而不是作为关键字。 值显示在管道定义的右侧。 以下内容有效:key: $[variables.value]。 以下内容无效:$[variables.key]: value。 运行时表达式必须占据键值对的整个右侧。 例如,key: $[variables.value] 有效,但 key: $[variables.value] foo 无效。

语法 示例 何时处理? 在管道定义中的哪个位置扩展? 找不到时如何呈现?
$(var) 任务执行前的运行时 值(右侧) 打印 $(var)
模板表达式 ${{ variables.var }} 编译时间 (compile time) 键或值(左侧或右侧) 空字符串
运行时表达式 $[variables.var] Runtime — 运行时 值(右侧) 空字符串

我应使用哪种语法?

如果要为任务提供安全字符串或 预定义的变量 输入,请使用宏语法。

如果使用条件表达式,请选择运行时表达式。 但是,如果不希望空变量打印(例如 $[variables.var]),则不要使用运行时表达式。 例如,如果条件逻辑依赖于具有特定值或没有值的变量。 在这种情况下,应使用宏表达式。

通常,模板变量是要使用的标准。 利用模板变量,管道将在管道编译时将变量值完全注入管道。 尝试调试管道时,这非常有用。 可以下载日志文件并评估要替换的完全扩展值。 由于变量已替换,因此不应将模板语法用于敏感值。

在管道中设置变量

在最常见的情况下,需设置变量并在 YAML 文件中使用。 这种方法允许你跟踪版本控制系统中变量的更改。 还可以在管道设置 UI 中定义变量(请参阅经典选项卡),并在 YAML 中引用它们。

以下示例演示如何设置两个变量 configurationplatform,并在后续步骤中使用。 要在 YAML 语句中使用变量,请将其包装在 $() 中。 变量不能用于在 YAML 语句中定义 repository

# Set variables once
variables:
  configuration: debug
  platform: x64

steps:

# Use them once
- task: MSBuild@1
  inputs:
    solution: solution1.sln
    configuration: $(configuration) # Use the variable
    platform: $(platform)

# Use them again
- task: MSBuild@1
  inputs:
    solution: solution2.sln
    configuration: $(configuration) # Use the variable
    platform: $(platform)

变量范围

在 YAML 文件中,可以在各种范围内设置变量:

  • 在根级别,使其可用于管道中的所有作业。
  • 在阶段级别,使其仅可用于特定阶段。
  • 在作业级别,使其仅可用于特定作业。

在 YAML 顶部定义变量时,该变量可用于管道中的所有作业和阶段,并且是一个全局变量。 YAML 中定义的全局变量在管道设置 UI 中不可见。

作业级别的变量将重写根和阶段级别的变量。 阶段级别的变量重写根级别的变量。

variables:
  global_variable: value    # this is available to all jobs

jobs:
- job: job1
  pool:
    vmImage: 'ubuntu-latest'
  variables:
    job_variable1: value1    # this is only available in job1
  steps:
  - bash: echo $(global_variable)
  - bash: echo $(job_variable1)
  - bash: echo $JOB_VARIABLE1 # variables are available in the script environment too

- job: job2
  pool:
    vmImage: 'ubuntu-latest'
  variables:
    job_variable2: value2    # this is only available in job2
  steps:
  - bash: echo $(global_variable)
  - bash: echo $(job_variable2)
  - bash: echo $GLOBAL_VARIABLE

这两个作业的输出如下所示:

# job1
value 
value1
value1

# job2
value
value2
value

指定变量

在前面的示例中,variables 关键字后跟键值对列表。 键是变量名称,值是变量值。

还有另一种语法,适合于在希望使用变量模板变量组时使用。

利用模板,变量可以在一个 YAML 中定义,并包含在另一个 YAML 文件中。

变量组是一组可在多个管道中使用的变量。 它们允许你在一个位置中管理和组织各个阶段通用的变量。

将此语法用于管道根级别的变量模板和变量组。

在此替代语法中,variables 关键字接受变量说明符的列表。 变量说明符 name 表示常规变量,group 表示变量组,template 表示包含变量模板。 下面的示例演示了所有三种方法。

variables:
# a regular variable
- name: myvariable
  value: myvalue
# a variable group
- group: myvariablegroup
# a reference to a variable template
- template: myvariabletemplate.yml

详细了解使用模板重用变量

通过环境访问变量

请注意,变量也通过环境变量提供给脚本。 使用这些环境变量时需遵循的语法取决于脚本语言。

名称为大写,. 将被替换为 _。 这会自动插入到进程环境中。 下面是一些示例:

  • 批处理脚本:%VARIABLE_NAME%
  • PowerShell 脚本:$env:VARIABLE_NAME
  • Bash 脚本:$VARIABLE_NAME

重要

包含文件路径的预定义变量将被转换为基于代理主机类型和 shell 类型的相应样式(Windows 样式为 C:\foo\,而 Unix 样式为 /foo/)。 如果在 Windows 上运行 bash 脚本任务,则应使用环境变量方法来访问这些变量,而不是使用管道变量方法,以确保具有正确的文件路径样式。

设置机密变量

提示

系统不会自动将机密变量作为环境变量导出。 若要在脚本中使用机密变量,请将其显式映射到环境变量。 有关详细信息,请参阅设置机密变量

不要在 YAML 文件中设置机密变量。 操作系统通常会记录运行进程的命令,你不希望日志包含作为输入传入的机密。 使用脚本的环境或映射 variables 块中的变量以将机密传递给管道。

注意

Azure Pipelines 在向管道日志发出数据时会努力屏蔽机密,因此你可能会在输出和日志中看到未设置为机密的其他变量和数据掩码。

需要在管道的管道设置 UI 中设置机密变量。 这些变量的范围限定为设置它们的管道。 还可以在变量组中设置机密变量

要在 Web 界面中设置机密,请执行以下步骤:

  1. 转到管道页,选择适当的管道,然后选择编辑
  2. 找到该管道的变量
  3. 添加或更新该变量。
  4. 选择“将此值保密”选项,以加密方式存储变量。
  5. 保存管道。

机密变量使用 2048 位 RSA 密钥进行静态加密。 代理上提供机密供任务和脚本使用。 请注意谁有权更改管道。

重要

我们要尽量屏蔽机密,使其不出现在 Azure Pipelines 输出中,但你仍然需要采取预防措施。 切勿将机密作为输出进行回显。 某些操作系统记录命令行参数。 切勿在命令行上传递机密。 相反,我们建议将机密映射到环境变量中。

我们从不屏蔽机密的子字符串。 例如,如果将“abc123”设置为机密,则不会从日志中屏蔽“abc”。 这是为了避免在过于精细的级别屏蔽机密,从而使日志不可读。 因此,机密不应包含结构化数据。 例如,如果“{ "foo": "bar" }”设置为机密,则不会从日志中屏蔽“bar”。

与普通变量不同,它们不会自动解密为脚本的环境变量。 需要显式映射机密变量。

以下示例演示如何在 PowerShell 和 Bash 脚本中映射和使用名为 mySecret 的机密变量。 定义了两个全局变量。 GLOBAL_MYSECRET 被分配了机密变量 mySecret 的值,GLOBAL_MY_MAPPED_ENV_VAR 被分配了非机密变量 nonSecretVariable 的值。 与普通管道变量不同,没有名为 MYSECRET 的环境变量。

PowerShell 任务运行脚本来打印变量。

  • $(mySecret):这是对机密变量的直接引用,并且有效。
  • $env:MYSECRET:这会尝试访问环境变量形式的机密变量,这不起作用,因为机密变量不会自动映射到环境变量。
  • $env:GLOBAL_MYSECRET:这会尝试通过全局变量访问机密变量,这也不起作用,因为无法以这种方式映射机密变量。
  • $env:GLOBAL_MY_MAPPED_ENV_VAR:此操作通过全局变量访问非机密变量,这将起作用。
  • $env:MY_MAPPED_ENV_VAR:这会通过特定于任务的环境变量访问机密变量,这是将机密变量映射到环境变量的建议方法。
variables:
 GLOBAL_MYSECRET: $(mySecret) # this will not work because the secret variable needs to be mapped as env
 GLOBAL_MY_MAPPED_ENV_VAR: $(nonSecretVariable) # this works because it's not a secret.

steps:

- powershell: |
    Write-Host "Using an input-macro works: $(mySecret)"
    Write-Host "Using the env var directly does not work: $env:MYSECRET"
    Write-Host "Using a global secret var mapped in the pipeline does not work either: $env:GLOBAL_MYSECRET"
    Write-Host "Using a global non-secret var mapped in the pipeline works: $env:GLOBAL_MY_MAPPED_ENV_VAR" 
    Write-Host "Using the mapped env var for this task works and is recommended: $env:MY_MAPPED_ENV_VAR"
  env:
    MY_MAPPED_ENV_VAR: $(mySecret) # the recommended way to map to an env variable

- bash: |
    echo "Using an input-macro works: $(mySecret)"
    echo "Using the env var directly does not work: $MYSECRET"
    echo "Using a global secret var mapped in the pipeline does not work either: $GLOBAL_MYSECRET"
    echo "Using a global non-secret var mapped in the pipeline works: $GLOBAL_MY_MAPPED_ENV_VAR" 
    echo "Using the mapped env var for this task works and is recommended: $MY_MAPPED_ENV_VAR"
  env:
    MY_MAPPED_ENV_VAR: $(mySecret) # the recommended way to map to an env variable


上述脚本中这两个任务的输出如下所示:

Using an input-macro works: ***
Using the env var directly does not work:
Using a global secret var mapped in the pipeline does not work either:
Using a global non-secret var mapped in the pipeline works: foo
Using the mapped env var for this task works and is recommended: ***

还可以在脚本外部使用机密变量。 例如,可以使用 variables 定义将机密变量映射到任务。 此示例演示如何在 Azure 文件复制任务中使用机密变量 $(vmsUser)$(vmsAdminPass)

variables:
  VMS_USER: $(vmsUser)
  VMS_PASS: $(vmsAdminPass)

pool:
  vmImage: 'ubuntu-latest'

steps:
- task: AzureFileCopy@4
  inputs:
    SourcePath: 'my/path'
    azureSubscription: 'my-subscription'
    Destination: 'AzureVMs'
    storage: 'my-storage'
    resourceGroup: 'my-rg'
    vmsAdminUserName: $(VMS_USER)
    vmsAdminPassword: $(VMS_PASS)

引用变量组中的机密变量

此示例演示如何在 YAML 文件中引用变量组,以及如何在 YAML 中添加变量。 变量组中使用了两个变量:usertoken。 变量 token 是机密变量,并映射到环境变量 $env:MY_MAPPED_TOKEN,以便可以在 YAML 中引用后者。

此 YAML 进行 REST 调用以检索发布列表,并输出结果。

variables: 
- group: 'my-var-group' # variable group
- name: 'devopsAccount' # new variable defined in YAML
  value: 'contoso'
- name: 'projectName' # new variable defined in YAML
  value: 'contosoads'

steps:
- task: PowerShell@2
  inputs:
    targetType: 'inline'
    script: |
        # Encode the Personal Access Token (PAT)
        # $env:USER is a normal variable in the variable group
        # $env:MY_MAPPED_TOKEN is a mapped secret variable
        $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $env:USER,$env:MY_MAPPED_TOKEN)))

        # Get a list of releases
        $uri = "https://vsrm.dev.azure.com/$(devopsAccount)/$(projectName)/_apis/release/releases?api-version=5.1"

        # Invoke the REST call
        $result = Invoke-RestMethod -Uri $uri -Method Get -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)}

        # Output releases in JSON
        Write-Host $result.value
  env:
    MY_MAPPED_TOKEN: $(token) # Maps the secret variable $(token) from my-var-group

重要

默认情况下,在 GitHub 存储库中,与管道关联的机密变量不能用于提取分叉的请求构建。 有关详细信息,请参阅分叉的贡献

跨管道共享变量

要在项目中的多个管道之间共享变量,请使用 Web 界面。 在下面,使用变量组

使用任务的输出变量

某些任务定义输出变量,可在下游步骤、作业和阶段中使用。 在 YAML 中,可以使用依赖项跨作业和阶段访问变量。

在下游任务中引用矩阵作业时,需要使用不同的语法。 请参阅设置多作业输出变量。 还需要对部署作业中的变量使用不同的语法。 请参阅部署作业中对输出变量的支持

某些任务定义输出变量,可以在同一阶段的下游步骤和作业中使用。 在 YAML 中,可以使用依赖项跨作业访问变量。

  • 要从同一作业中的不同任务引用变量,请使用 TASK.VARIABLE
  • 要从其他作业的任务引用变量,请使用 dependencies.JOB.outputs['TASK.VARIABLE']

注意

默认情况下,管道中的每个阶段都依赖于 YAML 文件中与其紧邻的前面一个阶段。 如果需要引用不是紧邻当前阶段之前的阶段,可以通过向阶段添加 dependsOn 部分来重写此自动默认值。

注意

以下示例使用标准管道语法。 如果使用部署管道,变量和条件变量语法将有所不同。 有关要使用的特定语法的信息,请参阅部署作业

对于这些示例,假设我们有一个名为 MyTask 的任务,此任务设置一个名为 MyVar 的输出变量。 可在表达式 - 依赖项中详细了解语法。

在同一作业中使用输出

steps:
- task: MyTask@1  # this step generates the output variable
  name: ProduceVar  # because we're going to depend on it, we need to name the step
- script: echo $(ProduceVar.MyVar) # this step uses the output variable

在不同的作业中使用输出

jobs:
- job: A
  steps:
  # assume that MyTask generates an output variable called "MyVar"
  # (you would learn that from the task's documentation)
  - task: MyTask@1
    name: ProduceVar  # because we're going to depend on it, we need to name the step
- job: B
  dependsOn: A
  variables:
    # map the output variable from A into this job
    varFromA: $[ dependencies.A.outputs['ProduceVar.MyVar'] ]
  steps:
  - script: echo $(varFromA) # this step uses the mapped-in variable

在不同的阶段使用输出

要使用来自不同阶段的输出,引用变量的格式为 stageDependencies.STAGE.JOB.outputs['TASK.VARIABLE']。 在阶段级别(而不是工作级别)您可以在条件中使用这些变量。

输出变量仅在下一个下游阶段中可用。 如果多个阶段使用相同的输出变量,请使用 dependsOn 条件。

stages:
- stage: One
  jobs:
  - job: A
    steps:
    - task: MyTask@1  # this step generates the output variable
      name: ProduceVar  # because we're going to depend on it, we need to name the step

- stage: Two
  dependsOn:
  - One
  jobs:
  - job: B
    variables:
      # map the output variable from A into this job
      varFromA: $[ stageDependencies.One.A.outputs['ProduceVar.MyVar'] ]
    steps:
    - script: echo $(varFromA) # this step uses the mapped-in variable

- stage: Three
  dependsOn:
  - One
  - Two
  jobs:
  - job: C
    variables:
      # map the output variable from A into this job
      varFromA: $[ stageDependencies.One.A.outputs['ProduceVar.MyVar'] ]
    steps:
    - script: echo $(varFromA) # this step uses the mapped-in variable

还可以使用文件输入在阶段之间传递变量。 为此,需要在作业级别的第二阶段定义变量,然后将变量作为 env: 输入进行传递。

## script-a.sh
echo "##vso[task.setvariable variable=sauce;isOutput=true]crushed tomatoes"
## script-b.sh
echo 'Hello file version'
echo $skipMe
echo $StageSauce
## azure-pipelines.yml
stages:

- stage: one
  jobs:
  - job: A
    steps:
    - task: Bash@3
      inputs:
          filePath: 'script-a.sh'
      name: setvar
    - bash: |
       echo "##vso[task.setvariable variable=skipsubsequent;isOutput=true]true"
      name: skipstep

- stage: two
  jobs:
  - job: B
    variables:
      - name: StageSauce
        value: $[ stageDependencies.one.A.outputs['setvar.sauce'] ]
      - name: skipMe
        value: $[ stageDependencies.one.A.outputs['skipstep.skipsubsequent'] ]
    steps:
    - task: Bash@3
      inputs:
        filePath: 'script-b.sh'
      name: fileversion
      env:
        StageSauce: $(StageSauce) # predefined in variables section
        skipMe: $(skipMe) # predefined in variables section
    - task: Bash@3
      inputs:
        targetType: 'inline'
        script: |
          echo 'Hello inline version'
          echo $(skipMe) 
          echo $(StageSauce) 

上述管道中阶段的输出如下所示:

Hello inline version
true
crushed tomatoes

列出变量

可以使用 az pipelines variable list 命令列出管道中的所有变量。 要入门学习,请参阅 Azure DevOps CLI 入门

az pipelines variable list [--org]
                           [--pipeline-id]
                           [--pipeline-name]
                           [--project]

参数

  • org:Azure DevOps 组织 URL。 可以使用 配置默认组织 az devops configure -d organization=ORG_URL。 如果未配置为默认或使用 选取 git config,则为必需。 示例:--org https://dev.azure.com/MyOrganizationName/
  • pipeline-id:如果未提供 pipeline-name,则是必需的。 管道的 ID。
  • pipeline-name:如果未提供 pipeline-id,则是必需的;如果已提供 pipeline-id,则忽略。 管道的名称。
  • project:项目的名称或 ID。 可以使用 az devops configure -d project=NAME_OR_ID 配置默认项目。 如果未配置为默认或通过 git config 进行选取,则为必需。

示例

以下命令列出了 ID 为 12 的管道中的所有变量,并以表格式显示结果。

az pipelines variable list --pipeline-id 12 --output table

Name           Allow Override    Is Secret    Value
-------------  ----------------  -----------  ------------
MyVariable     False             False        platform
NextVariable   False             True         platform
Configuration  False             False        config.debug

在脚本中设置变量

脚本可以定义稍后在管道的后续步骤中使用的变量。 此方法设置的所有变量都被视为字符串。 要从脚本设置变量,可使用命令语法并打印到标准输出。

从脚本设置作业范围的变量

要从脚本设置变量,可使用task.setvariable日志记录命令。 这会更新后续作业的环境变量。 后续作业有权访问具有宏语法的新变量和任务中作为环境变量。

issecret 为 true 时,变量的值将保存为机密并从日志中屏蔽。 有关机密变量的详细信息,请参阅日志记录命令

steps:
# Create a variable
- bash: |
    echo "##vso[task.setvariable variable=sauce]crushed tomatoes" # remember to use double quotes

# Use the variable
# "$(sauce)" is replaced by the contents of the `sauce` variable by Azure Pipelines
# before handing the body of the script to the shell.
- bash: |
    echo my pipeline variable is $(sauce)

后续步骤还将将管道变量添加到其环境中。 不能在定义变量的步骤中使用变量。

steps:
# Create a variable
# Note that this does not update the environment of the current script.
- bash: |
    echo "##vso[task.setvariable variable=sauce]crushed tomatoes"

# An environment variable called `SAUCE` has been added to all downstream steps
- bash: |
    echo "my environment variable is $SAUCE"
- pwsh: |
    Write-Host "my environment variable is $env:SAUCE"

上一管道的输出。

my environment variable is crushed tomatoes
my environment variable is crushed tomatoes

设置多作业输出变量

如果要使变量可供将来的作业使用,则必须使用 isOutput=true 将其标记为输出变量。 然后,可以将其映射到将来的作业,方法是使用 $[] 语法并包括用于设置变量的步骤名称。 多作业输出变量仅适用于同一阶段的作业。

要将变量传递到不同阶段的作业,可使用阶段依赖项语法。

注意

默认情况下,管道中的每个阶段都依赖于 YAML 文件中与其紧邻的前面一个阶段。 因此,每个阶段都可以使用上一阶段的输出变量。 要访问其他阶段,需要更改依赖项关系图,例如,如果阶段 3 需要阶段 1 中的变量,则需要在阶段 1 上声明显式依赖项。

创建多作业输出变量时,应将表达式分配给变量。 在此 YAML 中,$[ dependencies.A.outputs['setvarStep.myOutputVar'] ] 分配给变量 $(myVarFromJobA)

jobs:
# Set an output variable from job A
- job: A
  pool:
    vmImage: 'windows-latest'
  steps:
  - powershell: echo "##vso[task.setvariable variable=myOutputVar;isOutput=true]this is the value"
    name: setvarStep
  - script: echo $(setvarStep.myOutputVar)
    name: echovar

# Map the variable into job B
- job: B
  dependsOn: A
  pool:
    vmImage: 'ubuntu-latest'
  variables:
    myVarFromJobA: $[ dependencies.A.outputs['setvarStep.myOutputVar'] ]  # map in the variable
                                                                          # remember, expressions require single quotes
  steps:
  - script: echo $(myVarFromJobA)
    name: echovar

上一管道的输出。

this is the value
this is the value

要将变量从一个阶段设置为另一个阶段,请使用 stageDependencies

stages:
- stage: A
  jobs:
  - job: A1
    steps:
     - bash: echo "##vso[task.setvariable variable=myStageOutputVar;isOutput=true]this is a stage output var"
       name: printvar

- stage: B
  dependsOn: A
  variables:
    myVarfromStageA: $[ stageDependencies.A.A1.outputs['printvar.myStageOutputVar'] ]
  jobs:
  - job: B1
    steps:
    - script: echo $(myVarfromStageA)

如果从矩阵切片设置变量,然后从下游作业访问变量时引用该变量,则必须包括:

  • 作业的名称。
  • 步骤。
jobs:

# Set an output variable from a job with a matrix
- job: A
  pool:
    vmImage: 'ubuntu-latest'
  strategy:
    maxParallel: 2
    matrix:
      debugJob:
        configuration: debug
        platform: x64
      releaseJob:
        configuration: release
        platform: x64
  steps:
  - bash: echo "##vso[task.setvariable variable=myOutputVar;isOutput=true]this is the $(configuration) value"
    name: setvarStep
  - bash: echo $(setvarStep.myOutputVar)
    name: echovar

# Map the variable from the debug job
- job: B
  dependsOn: A
  pool:
    vmImage: 'ubuntu-latest'
  variables:
    myVarFromJobADebug: $[ dependencies.A.outputs['debugJob.setvarStep.myOutputVar'] ]
  steps:
  - script: echo $(myVarFromJobADebug)
    name: echovar
jobs:

# Set an output variable from a job with slicing
- job: A
  pool:
    vmImage: 'ubuntu-latest'
    parallel: 2 # Two slices
  steps:
  - bash: echo "##vso[task.setvariable variable=myOutputVar;isOutput=true]this is the slice $(system.jobPositionInPhase) value"
    name: setvarStep
  - script: echo $(setvarStep.myOutputVar)
    name: echovar

# Map the variable from the job for the first slice
- job: B
  dependsOn: A
  pool:
    vmImage: 'ubuntu-latest'
  variables:
    myVarFromJobsA1: $[ dependencies.A.outputs['job1.setvarStep.myOutputVar'] ]
  steps:
  - script: "echo $(myVarFromJobsA1)"
    name: echovar

请确保将作业名称作为部署作业的输出变量的前缀。 在这种情况下,作业名为 A

jobs:

# Set an output variable from a deployment
- deployment: A
  pool:
    vmImage: 'ubuntu-latest'
  environment: staging
  strategy:
    runOnce:
      deploy:
        steps:
        - bash: echo "##vso[task.setvariable variable=myOutputVar;isOutput=true]this is the deployment variable value"
          name: setvarStep
        - bash: echo $(setvarStep.myOutputVar)
          name: echovar

# Map the variable from the job for the first slice
- job: B
  dependsOn: A
  pool:
    vmImage: 'ubuntu-latest'
  variables:
    myVarFromDeploymentJob: $[ dependencies.A.outputs['A.setvarStep.myOutputVar'] ]
  steps:
  - bash: "echo $(myVarFromDeploymentJob)"
    name: echovar

使用表达式设置变量

可以使用表达式设置变量。 我们已遇到这种情况的一种情况,即将变量设置为上一作业中另一个变量的输出。

- job: B
  dependsOn: A
  variables:
    myVarFromJobsA1: $[ dependencies.A.outputs['job1.setvarStep.myOutputVar'] ] # remember to use single quotes

可以使用任何受支持的表达式来设置变量。 下面是设置变量充当计数器的示例,该计数器从 100 开始,每次运行递增 1,每天重置为 100。

jobs:
- job:
  variables:
    a: $[counter(format('{0:yyyyMMdd}', pipeline.startTime), 100)]
  steps:
  - bash: echo $(a)

有关计数器、依赖项和其他表达式的详细信息,请参阅表达式

为步骤配置可设置的变量

可以在步骤中定义 settableVariables,也可以指定不能设置任何变量。

在此示例中,脚本无法设置变量。

steps:
- script: echo This is a step
  target:
    settableVariables: none

在此示例中,脚本允许变量 sauce,但不允许变量 secretSauce。 管道运行页上会显示一条警告。

告你无法设置 secretSauce。

steps:
  - bash: |
      echo "##vso[task.setvariable variable=Sauce;]crushed tomatoes"
      echo "##vso[task.setvariable variable=secretSauce;]crushed tomatoes with garlic"
    target:
     settableVariables:
      - sauce
    name: SetVars
  - bash: 
      echo "Sauce is $(sauce)"
      echo "secretSauce is $(secretSauce)"
    name: OutputVars

排队时允许

如果变量出现在 YAML 文件的块中 variables,则其值是固定的,无法在队列时重写。 最佳实践是在 YAML 文件中定义变量,但有时这没有意义。 例如,你可能想要定义一个机密变量,而不是在 YAML 中公开该变量。 或者,可能需要在管道运行期间手动设置变量值。

要定义队列时值,有两种选择。 可以在 UI 中定义变量,并选择允许用户在运行此管道时替代此值选项,也可以改为使用运行时参数。 如果变量不是机密,最佳做法是使用运行时参数

要在队列时设置变量,请在管道中添加新变量,然后选择重写选项。

在队列时间设置变量。

要允许在队列时设置变量,请确保该变量不会也出现在管道或作业的 variables 块中。 如果同时在 YAML 的变量块和 UI 中定义变量,则 YAML 中的值优先。

变量的扩展

在多个范围设置同名变量时,将应用以下优先级(最高优先级排在首位)。

  1. 在 YAML 文件中设置的作业级别变量
  2. 在 YAML 文件中设置的阶段级别变量
  3. 在 YAML 文件中设置的管道级别变量
  4. 在排队时设置的变量
  5. 在管道设置 UI 中设置的管道变量

在以下示例中,在 YAML 文件的管道级别和作业级别设置了相同变量 a。 还在变量组 G 中设置了此变量,并在管道设置 UI 中将其设置为变量。

variables:
  a: 'pipeline yaml'

stages:
- stage: one
  displayName: one
  variables:
  - name: a
    value: 'stage yaml'

  jobs:
  - job: A
    variables:
    - name: a
      value: 'job yaml'
    steps:
    - bash: echo $(a)        # This will be 'job yaml'

在同一范围内设置同名变量时,最后一个设定的值优先。

stages:
- stage: one
  displayName: Stage One
  variables: 
    - name: a
      value: alpha
    - name: a
      value: beta
  jobs: 
  - job: I
    displayName: Job I
    variables:
      - name: b
        value: uno
      - name: b
        value: dos
    steps: 
    - script: echo $(a) #outputs beta
    - script: echo $(b) #outputs dos

注意

在 YAML 文件中设置了某个变量时,不要在 Web 编辑器中将此变量定义为队列时可设置。 当前无法更改队列时间 YAML 文件中设置的变量。 如果希望某个变量可在排队时设置,请不要在 YAML 文件中设置此变量。

启动运行时,变量将展开一次,并在每个步骤开始时再次展开。 例如:

jobs:
- job: A
  variables:
    a: 10
  steps:
  - bash: |
      echo $(a)            # This will be 10
      echo '##vso[task.setvariable variable=a]20'
      echo $(a)            # This will also be 10, since the expansion of $(a) happens before the step
  - bash: echo $(a)        # This will be 20, since the variables are expanded just before the step

前面的示例中有两个步骤。 在作业开始时展开一次 $(a),在两个步骤的开头再次展开一次。

由于变量是在作业开始时展开的,因此不能在策略中使用变量。 在以下示例中,不能使用变量 a 来扩展作业矩阵,因为变量仅在每个展开作业的开头可用。

jobs:
- job: A
  variables:
    a: 10
  strategy:
    matrix:
      x:
        some_variable: $(a)    # This does not work

如果变量 a 是上一个作业的输出变量,则可以在将来的作业中使用此变量。

- job: A
  steps:
  - powershell: echo "##vso[task.setvariable variable=a;isOutput=true]10"
    name: a_step

# Map the variable into job B
- job: B
  dependsOn: A
  variables:
    some_variable: $[ dependencies.A.outputs['a_step.a'] ]

递归扩展

在代理上,使用 $( ) 语法引用的变量以递归方式展开。 例如:

variables:
  myInner: someValue
  myOuter: $(myInner)

steps:
- script: echo $(myOuter)  # prints "someValue"
  displayName: Variable is $(myOuter)  # display name is "Variable is someValue"