运行跨平台脚本
Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019
借助 Azure Pipelines,可以在 macOS、Linux 和 Windows 计算机上运行你的生成。 如果使用跨平台技术(例如 .NET Core、Node.js 和 Python)进行开发,这些功能既会带来优势,也会带来挑战。
例如,大多数管道包含一个或多个要在生成过程中运行的脚本。
但是,脚本在不同平台上的运行方式往往不同。 可以使用 script
关键字快捷方式简化写入脚本,还可以使用条件来确定脚本的具体平台目标。
使用脚本步骤运行跨平台工具
script 关键字是命令行任务的捷径。 script
关键字在 Linux 和 macOS 上运行 Bash,在 Windows 上运行 cmd.exe。
当任务只是将参数传递给跨平台工具时,使用 script
会很有帮助。 例如,结合一组参数调用 npm
可以通过一个 script
步骤来轻松完成。
script
在每个平台的本机脚本解释器中运行:macOS 和 Linux 上的 Bash,Windows 上的 cmd.exe。
处理环境变量
环境变量是编写跨平台脚本时面临的第一个难题。 命令行、PowerShell 和 Bash 各自有不同的环境变量读取方法。 如果你需要访问操作系统提供的值(例如 PATH),则需要在每个平台上采用不同的方法。
但是,Azure Pipelines 提供了一种跨平台方式来引用它所知道的变量,这种方式称为宏语法。 将变量名称括在 $( )
中后,该名称就会扩展,然后平台的 shell 就能识别到它。 例如,如果你要回显管道的 ID,可以使用以下跨平台友好的脚本:
steps:
- script: echo This is pipeline $(System.DefinitionId)
这也适用于在管道中指定的变量。
variables:
Example: 'myValue'
steps:
- script: echo The value passed in is $(Example)
考虑使用 Bash 还是 pwsh
如果你的脚本需求比上面的示例更复杂,请考虑使用 Bash 编写脚本。 大多数 macOS 和 Linux 代理都提供 Bash 作为可用的 shell,而 Windows 代理则提供 Git Bash 或适用于 Linux 的 Windows 子系统 Bash。
对于 Azure Pipelines,Microsoft 托管的代理始终提供 Bash。
例如,如果你需要决定生成是否由拉取请求触发,请执行以下操作:
trigger:
batch: true
branches:
include:
- main
steps:
- bash: |
echo "Hello world from $AGENT_NAME running on $AGENT_OS"
case $BUILD_REASON in
"Manual") echo "$BUILD_REQUESTEDFOR manually queued the build." ;;
"IndividualCI") echo "This is a CI build for $BUILD_REQUESTEDFOR." ;;
"BatchedCI") echo "This is a batched CI build for $BUILD_REQUESTEDFOR." ;;
*) $BUILD_REASON ;;
esac
displayName: Hello world
PowerShell Core (pwsh
) 也是一个选择。
它要求在每个代理上安装 PowerShell Core。
根据平台切换
一般情况下,我们建议避免使用特定于平台的脚本,以避免出现管道逻辑重复等问题。 重复会导致额外的工作和额外的 bug 风险。
但是,如果无法避免特定于平台的脚本,则可以使用 condition
来检测所在的平台。
例如,假设出于某种原因需要获取生成代理的 IP 地址。
在 Windows 上,ipconfig
可获取该信息。
在 macOS 上,相应的命令是 ifconfig
。
在 Ubuntu Linux 上,相应的命令是 ip addr
。
设置以下管道,然后尝试针对不同平台上的代理运行它。
steps:
# Linux
- bash: |
export IPADDR=$(ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d'/')
echo "##vso[task.setvariable variable=IP_ADDR]$IPADDR"
condition: eq( variables['Agent.OS'], 'Linux' )
displayName: Get IP on Linux
# macOS
- bash: |
export IPADDR=$(ifconfig | grep 'en0' -A3 | grep inet | tail -n1 | awk '{print $2}')
echo "##vso[task.setvariable variable=IP_ADDR]$IPADDR"
condition: eq( variables['Agent.OS'], 'Darwin' )
displayName: Get IP on macOS
# Windows
- powershell: |
Set-Variable -Name IPADDR -Value ((Get-NetIPAddress | ?{ $_.AddressFamily -eq "IPv4" -and !($_.IPAddress -match "169") -and !($_.IPaddress -match "127") } | Select-Object -First 1).IPAddress)
Write-Host "##vso[task.setvariable variable=IP_ADDR]$IPADDR"
condition: eq( variables['Agent.OS'], 'Windows_NT' )
displayName: Get IP on Windows
# now we use the value, no matter where we got it
- script: |
echo The IP address is $(IP_ADDR)