GitLab CI ユーザーのための YAML 入門

GitLab Advent Calendar 2017 四日目の記事です。

GitLab CI では Travis CICircleCI と同じく YAML ファイルで処理を記述します。

以下は、ウェブアプリケーションをリントやテストにかけ、ビルドした成果物を保存する .gitlab-ci.yml ファイルです。

.gitlab-ci.yml
build:
  script:
    - npm install
    - npm run lint
    - npm run test
    - npm run build
  artifacts:
    paths:
      - dist
      - reports

hoge: がハッシュで - がリストに変換されるのは何となくわかるのですが、書いてみるとうまく動かないことがあります。ヘルプでは YAML の書き方について詳しく書いているわけではないため、結構はまりました。調べたことをまとめました。

ハッシュとリスト

リストを書くとき、- ではなく [] で囲むこともできます。

# - を使う
hoge:
  - a
  - b
  - c

# [] を使う
hoge: [a, b, c]

ハッシュも同様に、{} で囲むこともできます。

# `:` を使う
hoge:
  a: aaa
  b: bbb
  c: ccc

# {} を使う
hoge: { a: aaa, b: bbb, c: ccc }

おそらく、[]{} を使うことはないと思いますが、これを知らないとはまるので紹介しました。

[ (test コマンド) を使う

YAML では [ で始まるとリストとみなします。test コマンドの [ を使うとはまります。

例えば、docker コマンドがあったらログインするような処理を以下のように書くとエラーになります。

.gitlab-ci.yml
build:
  script:
    - [ -x /usr/bin/docker ] && docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}"

こういう場合はシングルクォートで囲みます。

.gitlab-ci.yml
build:
  script:
    - '[ -x /usr/bin/docker ] && docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}"'

先頭が [ でなければ問題はないので、解決方法はたくさんあります。

.gitlab-ci.yml
# `test` を使う
build:
  script:
    - test -x /usr/bin/docker && docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}"

# `\` を付ける
build:
  script:
    - \[ -x /usr/bin/docker ] && docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}"

# `true` を使う
build:
  script:
    - true && [ -x /usr/bin/docker ] && docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}"

長いコマンドを書く

一行にたくさんのコマンドと詰め込むと見づらくなります。そういう時は >- を使うと複数行のテキストを一行にまとめることができます。

.gitlab-ci.yml
build:
  script:
    - >-
      test -x /usr/bin/docker &&
      docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}"

また、|- を使うと複数行のテキストを書くことができます。

.gitlab-ci.yml
build:
  script:
    - |-
      test -x /usr/bin/docker && \
      docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}"

|- を使うと if 文なども書きやすくなります。

.gitlab-ci.yml
build:
  script:
    - |-
      if [ -x /usr/bin/docker ]; then
        docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}"
      fi

ここまで書いておいてなんですが、GitLab CI では script のリストの内容を結合したシェルスクリプトを実行していますので、>-|- でなくても特に問題はありません。

.gitlab-ci.yml
build:
  script:
    - if [ -x /usr/bin/docker ]; then
    -   docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}"
    - fi

注) ジョブの実行レポートに違いが出るようです

アンカーとエイリアス

GitLab CI のヘルプではテンプレートとなっていますが、YAML のアンカーとエイリアスを使っています。

.gitlab-ci.yml
build:
  script:
    - echo hoge
    - echo hoge
    - echo hoge

上記スクリプトの代わりに以下のように書くこともできます。

.gitlab-ci.yml
build:
  script:
# `echo hoge` をリストの最初にセットしつつ、`hoge` 変数にもセット
    - &hoge echo hoge
# `hoge` 変数を展開
    - *hoge
    - *hoge

最初の &hoge echo hoge も使われることに注意してください。

また、GitLab CI では . で始まるジョブは無視されます。これを使って、以下のように書くこともできます。

.gitlab-ci.yml
# `.` で始まるので、このジョブは実行されない
.dontrun:
# hoge 変数に `echo hoge` を代入
  - &hoge echo hoge

build:
  script:
# hoge 変数を展開
    - *hoge
    - *hoge
    - *hoge

ハッシュは << を使ってマージができます。これが、GitLab CI におけるテンプレートです。

.gitlab-ci.yml
.template: &template
  script:
    - echo foo
    - echo bar

job1:
  <<: *template

job2:
  <<: *template

参考資料

1473709167