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

# GitLab CI ユーザーのための YAML 入門
[GitLab Advent Calendar 2017](https://qiita.com/advent-calendar/2017/gitlab) 四日目の記事です。

GitLab CI では [Travis CI](https://travis-ci.org/) や [CircleCI](https://circleci.com/) と同じく YAML ファイルで処理を記述します。

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

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

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


## ハッシュとリスト
リストを書くとき、`-` ではなく `[]` で囲むこともできます。

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

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

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

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

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

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


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

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

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

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

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

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

```yaml:.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}"
```


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

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

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

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

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

```yaml:.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` のリストの内容を結合したシェルスクリプトを実行していますので、`>-` や `|-` でなくても特に問題はありません。

```yaml:.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 のアンカーとエイリアスを使っています。

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

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

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

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

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

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

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

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

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

job1:
  <<: *template

job2:
  <<: *template
```

## 参考資料
* [Configuration of your jobs with .gitlab-ci.yml ](https://docs.gitlab.com/ce/ci/yaml/) - 公式のマニュアル。
* [.gitlab-ci.yml によるジョブの設定方法(日本語訳)](https://qiita.com/ynott/items/1ff698868ef85e50f5a1) @ynott さんによる日本語訳。
* [Check your .gitlab-ci.yml](https://gitlab.com/ci/lint) - `.gitlab-ci.yml` の文法チェックだけでなく、どういう風に解釈されたまでレポートしてくれます。
* [プログラマーのための YAML 入門 (初級編)](http://magazine.rubyist.net/?0009-YAML) - るびまの YAML 解説です。おすすめ!
* [YAML 基本記法まとめ](https://qiita.com/gcfuji/items/5f8e4c5795ce41b214d1) - @gcfuji さんによる YAML 解説。短くまとまってていい感じです。