yml-sorter を使って YAML ファイルの属性情報をソートする

2021-04-12Bash,JavaScript

はじめに

最近 KubernetesDocker ComposeOpenAPI といったツールで YAML ファイルを触ることが多いです。

参加したプロジェクトでは、この設定ファイルが環境別に管理されていました。
環境は以下のものがあり、それぞれに YAML ファイルが用意されています。

  • 本番環境
  • ステージング環境
  • 開発環境

設定ファイルが多重管理されているという問題に対処するために、
まずはそれぞれの環境の設定ファイルの違いを diff で確認しようと思いました。

しかし、そもそもそれらの設定ファイルの属性がきれいに並べられておらず、 diff が大変です。

なんとかならないものでしょうか?

検証環境

$ node --version
v15.14.0

$ yarn --version
1.22.5

YAML ファイルの各フィールドをソートするために yml-sorter を使う

これに対処するために YAML の内容を属性名でソートさせてから diff すれば良さそうです。

探してみたところ、YAML ファイルの各フィールド名でソートするためのツールを見つけました。

こちらのツールは、 js-yaml という別のツールのラッパーということです。

インストール

npm なら以下の通り。

npm i -g yml-sorter

yarn なら以下の通り。

yarn global add yml-sorter

使い方

YAML ファイルを引数に指定して実行するだけです。

適当な docker-compose.yaml サンプルがほしかったので、以下の Github リポジトリのものを拝借します。

$ git clone https://github.com/DataDog/docker-compose-example

$ cd docker-compose-example/

$ cat docker-compose.yml
version: "3"
services:
  web:
    build: web
    command: python app.py
    ports:
     - "5000:5000"
    volumes:
     - ./web:/code # modified here to take into account the new app path
    links:
     - redis
    environment:
     - DATADOG_HOST=datadog # used by the web app to initialize the Datadog library
  redis:
    image: redis
  # agent section
  datadog:
    build: datadog
    links:
     - redis # ensures that redis is a host that the container can find
     - web # ensures that the web app can send metrics
    environment:
     - DD_API_KEY=__your_datadog_api_key_here__
     - DD_DOGSTATSD_NON_LOCAL_TRAFFIC=true
    volumes:
     - /var/run/docker.sock:/var/run/docker.sock
     - /proc/:/host/proc/:ro
     - /sys/fs/cgroup:/host/sys/fs/cgroup:ro

ソートしてみます。

$ yml-sorter -i docker-compose.yml

実行しても何も表示されません。
指定したファイルがそのまま上書きされてしまったので、その点だけ注意が必要です。

Git で diff を見てみます。

$ git diff --ignore-all-space
diff --git docker-compose.yml docker-compose.yml
index 1f99d1a..d98c5f4 100644
--- docker-compose.yml
+++ docker-compose.yml
@@ -1,28 +1,27 @@
-version: "3"
 services:
-  web:
-    build: web
-    command: python app.py
-    ports:
-     - "5000:5000"
-    volumes:
-     - ./web:/code # modified here to take into account the new app path
-    links:
-     - redis
-    environment:
-     - DATADOG_HOST=datadog # used by the web app to initialize the Datadog library
-  redis:
-    image: redis
-  # agent section
   datadog:
     build: datadog
-    links:
-     - redis # ensures that redis is a host that the container can find
-     - web # ensures that the web app can send metrics
     environment:
       - DD_API_KEY=__your_datadog_api_key_here__
       - DD_DOGSTATSD_NON_LOCAL_TRAFFIC=true
+    links:
+      - redis
+      - web
     volumes:
-     - /var/run/docker.sock:/var/run/docker.sock
-     - /proc/:/host/proc/:ro
-     - /sys/fs/cgroup:/host/sys/fs/cgroup:ro
+      - '/var/run/docker.sock:/var/run/docker.sock'
+      - '/proc/:/host/proc/:ro'
+      - '/sys/fs/cgroup:/host/sys/fs/cgroup:ro'
+  redis:
+    image: redis
+  web:
+    build: web
+    command: python app.py
+    environment:
+      - DATADOG_HOST=datadog
+    links:
+      - redis
+    ports:
+      - '5000:5000'
+    volumes:
+      - './web:/code'
+version: '3'

確かにフィールドがアルファベット順にソートされています。
ソートだけではなく、インデントも修正されていますが、今回は yml-sorter でぞれぞれソートしたファイルを diff するため問題ないと考えています。

ファイルを上書きしたくない場合(標準出力に出力したい)

2021-04-12追記 : 開発元にバグ報告 + プルリクエストをあげ、修正を取り込んでいただきました!最新版を取得すれば修正されています。

--dry-run オプションを使えば、ソート結果でファイルを上書きせずに標準出力に出力できるということなので試してみました。

$ yml-sorter -i docker-compose.yml --dry-run

実行した結果、何も表示されません。
ファイルを見てみると、上書きされてしまっていました。

バグのようですね。以下のようにすると上書きされずに正しく出力されました。

$ yml-sorter -i docker-compose.yml --dry-run true

またプルリクエスト上げておきたいと思います。

ひとこと

また後日投稿しますが、発端は GKE 上の複数のクラスタの設定が異なっている、という問題に対処するためでした。
GKE のクラスタ設定を YAML 形式で出力して、diff したいというものでした。

2021-04-12Bash,JavaScript