クロスプラットフォーム スクリプトを実行する

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

Azure Pipelines を使うと、macOS、Linux、Windows マシン上でビルドを実行できます。 .NET Core、Node.js、Python などのクロスプラットフォーム テクノロジで開発する場合、これらの機能には利点と課題の両方があります。

たとえば、ほとんどのパイプラインには、ビルド プロセス中に実行したいスクリプトが 1 つまたは複数含まれています。 ただし、多くの場合、スクリプトは、プラットフォームが異なるとその実行方法も異なります。 script キーワード (keyword) ショートカットを使用すると、スクリプトの記述を容易にしたり、条件を使用してスクリプトを使用して特定のプラットフォームをターゲットにしたりできます。

スクリプトのステップを使用してクロスプラットフォーム ツールを実行する

スクリプト キーワードは、コマンド ライン タスクに対するショートカットです。 script キーワードを使用すると、Linux および macOS 上では Bash が実行され、Windows 上では cmd.exe が実行されます。

自身のタスクでクロスプラットフォーム ツールに引数を渡すだけの場合は、script を使用すると便利です。 たとえば、一連の引数を使用して npm を呼び出す場合は、script ステップを使用すると簡単に実行できます。 script は、次に示す各プラットフォームのネイティブ スクリプト インタープリターで実行されます: macOS と Linux では Bash、Windows では cmd.exe。

steps:
- script: |
    npm install
    npm test

環境変数を処理する

クロスプラットフォーム スクリプトの作成では、環境変数が最初の問題となります。 コマンド ライン、PowerShell、Bash では、環境変数を読み取る方法がそれぞれ異なります。 PATH などのオペレーティング システムで提供される値にアクセスする必要がある場合は、プラットフォームごとに異なる手法が必要になります。

ただし、Azure Pipelines には、マクロ構文と呼ばれる、既知の変数を参照するクロスプラットフォームの方法が用意されています。 変数名を $( ) で囲むと、それは展開されてから、プラットフォームのシェルによって認識されます。 たとえば、パイプラインの 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 が用意されています。Windows エージェントには Git Bash または Linux 用 Windows サブシステム Bash が含まれます。

Azure Pipelines の場合、Microsoft によってホストされるエージェントでは常に Bash を使用できます。

たとえば、ビルドが pull request によってトリガーされるようにするかどうかを決定する場合は、次のようにします。

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 がインストールされている必要があります。

プラットフォームに基づいて切り替える

一般に、パイプライン ロジックの重複などの問題を回避するために、プラットフォーム固有のスクリプトは使用しないことをお勧めします。 重複すると、余分な作業が発生し、バグのリスクが高まります。 ただし、プラットフォーム固有のスクリプトの作成を回避する方法がない場合は、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)