理系学生日記

おまえはいつまで学生気分なのか

Azure Pipelinesのscriptではset -eする

Azure Pipelinesでは様々なPipeline用のタスクが用意されています。例えばMaven taskだったり、 Docker taskだったりです。

この中で柔軟性が高いのはCommand Line taskBask taskでしょう。

例えばCommand Line taskでは、以下のようにしてスクリプトを自由に記述できます。

stages:
  - stage: Lint
    jobs:
      - job: textlint
        displayName: Textlint
        container: lint_cli
        steps:
          - script: |
              npx textlint '**/*.md'

問題

しかしここで問題が出てきました。なんとscriptで指定したスクリプトが異常終了しても、パイプラインが失敗にならない。

Starting: CmdLine
==============================================================================
Task         : Command line
Description  : Run a command line script using Bash on Linux and macOS and cmd.exe on Windows
Version      : 2.182.0
Author       : Microsoft Corporation
Help         : https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/command-line

(snip)

/__w/1/s/guide/how_to/azure/azure_pipelines_ci.md
   5:15  ✓ error  Azure Pipeline => Azure Pipelines

(snip)

✖ 14 problems (14 errors, 0 warnings)
✓ 8 fixable problems.
Try to run: $ textlint --fix [file]

Finishing: CmdLine

解決法

set -eしましょう。

シェルスクリプトではset -euしようというのがよく言われますが、これがAzure Pipelinesでも当てはまります。 Azure Pipelinesでは、scriptで指定した一連のコマンドを1つのファイルにした上で、当該ファイルを実行する形になっています。 このためset -eを明示的に記述しない限り、一連のスクリプトは途中で止まることなく全て実行されます。 おそらく最後のコマンドが正常終了する限り、Azure Pipelines上のビルドジョブはFailしないでしょう。

$ man bash
(snip)
-e      Exit immediately if a simple command (see SHELL GRAMMAR above) exits with a non-zero      status.  The shell does not exit if the command that fails is part of
        the command list immediately following a while or until keyword, part of the test in an if statement, part of a && or || list, or if the command's  return
        value is being inverted via !.  A trap on ERR, if set, is executed before the shell exits.

というわけで、Azure Pipelinesでスクリプトを書くときはset -eしましょう。

stages:
  - stage: Lint
    jobs:
      - job: textlint
        displayName: Textlint
        container: lint_cli
        steps:
          - script: |
              set -eu
              npx textlint '**/*.md'
✖ 14 problems (14 errors, 0 warnings)
✓ 8 fixable problems.
Try to run: $ textlint --fix [file]

##[error]Bash exited with code '1'.
Finishing: CmdLine