YAML diff: 2つのYAMLファイルをオンラインで比較
2つのYAMLドキュメントを貼り付けて、正確な左右比較を取得。Kubernetesマニフェスト、GitHub Actionsワークフロー、Helm values、docker-composeファイルに対応。
YAML diffツールとは?
2つのYAMLドキュメントを比較するための無料のブラウザ内ツールです。古いバージョンを左に、新しいバージョンを右に貼り付けると、違いが文字単位でハイライトされます。テキストはブラウザの外に出ません。シークレット参照や内部ホスト名を含むマニフェストをdiffする際にこれは重要です。
diffは文字レベルで動作し、テキストdiffツールと同じエンジンを使っています。エディタのYAMLモードはYAML 1.2.2 specificationに従ってシンタックスハイライトを処理するので、block scalars、anchors、flow collectionsはすべて正しく色付けされます。
Helmのvalues.yamlのpull requestで400行のdiffを見つめ、chartを壊した1つのインデントずれを探した経験があるなら、このツールがそれを数秒で見つけます。Slackとエディタの間でコピペしてスペースがタブに変換された場合にも便利です。YAMLはタブを受け付けません。
YAML diffの実際の仕組み
diffは文字レベルで動作し、その後セマンティッククリーンアップのパスがハイライトを意味のある塊にまとめます。バラバラの単独文字ではなくなります。挿入は右ペインに緑、削除は左ペインに赤で表示され、各ヘッダーの行カウントは検出された個別の編集数を示します。
YAMLには寛容な形式と勘違いした人を噛む解析ルールがあります。インデントはYAML 1.2.2 specに従い構造的なので、空白1つの位置ずれがドキュメントツリーを変えます。タブはインデントとして禁止されており、パーサーはそれをきっぱり拒否します。implicit typingはYAML 1.1で引用符のないトークンNOを真偽値falseに変換します。これが有名なNorway problemです: 国コードリストからノルウェーが密かに消えます。YAML 1.2はルールを絞り、true、false、nullと数値形式のみが引用符なしで変換されるようにしましたが、まだ多くのツールが1.1で解析しています。
下流のコンシューマー向けにYAMLをすでにJSONに変換しているなら、JSON diffツールがキー順序や正規化のような構造的な問題を扱います。JSONはYAML 1.2の厳密な部分集合なので、有効なJSONドキュメントはすべて有効なYAMLでもあります。この互換性はspecに記載されており、js-yamlとlibyamlの両方が驚きなくJSONをround-tripできる理由です。
3ステップでYAMLを比較する方法
テキストパネル2つ、diff 1つ。登録なし、アップロードなし、サーバーへの往復なし。
- 1
YAMLを貼り付けるかアップロード
古いYAMLを左、新しいYAMLを右に貼り付けます。あるいはどちらか一方のアップロードをクリックして、.yamlまたは.ymlファイルを直接読み込みます。サンプルボタンを押すと、両方のペインに小さなKubernetes Deploymentが入り、ツールの動作を先に確認できます。
- 2
インデントが意図通りか確認
YAMLはインデントにスペースのみを使い、タブは使いません。スペースをタブに変換するチャットクライアントやターミナルから貼り付けた場合、パーサーはファイルを拒否します。エディタはタブと行末の空白をハイライトするので、デプロイ失敗の原因になる前に発見できます。
- 3
diffを読む
削除は左に赤、挿入は右に緑で表示されます。両方のペインは同期してスクロールするので、長いマニフェストでも場所を見失わずに追えます。各ヘッダーの変更数は、diffが見つけた個別の編集数を要約しています。
YAML diffが正しいツールになるとき
staging とprodでKubernetes Deploymentのspecを比較
両方のクラスターでkubectl get deployment web -o yamlを実行し、出力をdiffします。スプリント終わりのロールアウトが届かなかったため、prodがまだreplicas: 2と古いイメージタグのままになっていることがよくあります。再度kubectl applyを実行する前に確認する最速の方法はテキストdiffです。KubernetesのオブジェクトモデルはYAMLそのものなので、これは日常的なケースです。
GitHub ActionsワークフローYAMLのdiff
ブランチ名変更後にワークフローがトリガーされなくなったり、ジョブが急に8分長くなったりしたら、.github/workflows/ci.ymlを直前のグリーンコミットとdiffします。原因はたいていon:フィルタの変更、actions/setup-nodeのcache:キーの削除、あるいはmatrixのエントリがnode-version: "18"(string)からnode-version: 18(number)に静かに変わって型チェッカーを引っかけたかのいずれかです。
デプロイ前のdocker-compose env変更レビュー
docker-compose.ymlをmainのバージョンとdiffし、environment:のどのエントリを実際に変更したか確認します。新しい環境変数のリストを貼り付けて、その1つが別のサービスですでに設定されていたことを忘れる人がいます。すると上書きが他の場所のフラグを静かに切り替えます。diffはそれを明白にします。
リリース間でのHelm chart values.yamlの追跡
chartを1.8.0から2.0.0に上げる際、values.yamlをmaintainerが公開した新しいデフォルトとdiffします。Helmは値をキー単位でマージするので、トップレベルキーの名前変更(image.tagがimage.repositoryの下に移動)は静かにchartのデフォルトにフォールバックします。helm upgradeがregressionをロールアウトする前に、diffがリネームを浮き上がらせます。
OpenAPIとSwagger YAMLスキーマレビュー
コードジェネレーターがpathsをアルファベット順に並べ替えると、3,000行のopenapi.yamlのdiffは読めません。バージョンを左右に並べると、実際の変更が浮かび上がります: requestスキーマに追加されたrequiredフィールドや、型がstringからintegerに静かに変わったresponseです。生成されたSDKを掘ってビルドが壊れた理由を探すより簡単です。
環境間のAnsibleプレイブックdiff
プレイブックがdevで動作しprodで失敗するとき、両者間でinventoryまたはroleのdefaults/main.ymlをdiffします。よくある原因は、コピーされなかったhostvar、あるいはdevではroleに、prodでは1つのtaskに設定されたbecome: yesです。diffがそれを数秒で見つけます。
YAMLクイックリファレンス
このツールが最もよく表面化させる解析のエッジケースについての短いカンニングペーパー。すべてYAML仕様と実際のパーサーの動作に基づいています。
| Topic | What this tool does |
|---|
| インデント | スペースのみで、その数は構造的です。2スペースと4スペースは両方とも一般的です。ファイル単位でどちらか1つに決めて貫いてください。歴史を知りたい場合はWikipediaの YAML 概要に良いまとめがあります。 |
|---|
| タブ | specによりインデントとして禁止。スカラー値の中では許可されています。エディタがEnter時にタブを挿入する場合、.yamlと.ymlファイルではスペースを使うように設定してください。 |
|---|
| anchorsとaliases | &nameがanchorを定義し、*nameがそれを参照します。コピペなしでcontainerのenv varsやデフォルトのservice configなど大きなブロックを繰り返すのに便利です。 |
|---|
| merge keys | <<: *baseは参照されたmappingを現在のmappingにマージします。YAML 1.1の機能です。libyamlを含むほとんどのパーサーはまだ受け入れます。YAML 1.2 specは廃止しました。 |
|---|
| マルチドキュメントファイル | ハイフン3つ(---)が単一ストリーム内のドキュメントを区切ります。複数のKubernetesオブジェクトを1つのkubectl apply -fに通すのに便利です。...はドキュメントを終了します。 |
|---|
| block scalars | |は改行を保持(literal)、>は改行をスペースに折りたたみます。修飾子-と+は末尾の改行を制御します。シェルスクリプトには|、長い人間向けの文章には>を使ってください。 |
|---|
| Norway problem | 引用符のないNO、YES、ON、OFFはYAML 1.1で真偽値になります。引用符でくくるか、1.2のパーサーを使ってください。どの文字列が変換されるかはYAMLの型定義を参照してください。 |
|---|
| エンコーディング | YAML 1.2 specはUTF-8を要求します。UTF-16はBOM付きで許可されています。実際のツールはBOMなしのUTF-8を期待するので、驚きを避けるためにそのように保存してください。 |
|---|
YAML diff: よくある質問
YAMLの空白への敏感さはdiffにとって有利ですか不利ですか?
YAMLは空白に敏感なので、普通のテキストdiffでもすでに有用です: インデントの変更はすべて構造的な変更で、diffがそれを捕まえます。違いは見せ方にあります。YAMLモードはanchors、tags、block scalars、flow collectionsをシンタックスの色でハイライトするので、変更がキー、文字列値、リスト要素のどれに対するものかが一目でわかります。背後のdiffアルゴリズムはテキストdiffツールと同じです。
なぜYAMLはインデントとスペースにそんなに厳しいのですか?
インデントだけが、どのキーがどのmappingに属すかをパーサーに伝えるからです。YAML 1.2.2 specはノードのインデントレベルを先頭スペースの数で定義し、タブをインデントとして禁止しています。スペース1つ追加するだけで、キーがサブmappingに昇格します。その厳格さは、波括弧やカンマを必要としない形式の代償であり、JSONよりYAMLでインデントバグをよく見る理由です。
Norway problemとは何ですか?
YAML 1.1のimplicit typingは、引用符のないトークンNOを真偽値falseに変換します。なので、ノルウェーを表すNOを含む国コードのリストは、静かに1つのエントリがfalseに置き換わったリストになります。YES、ON、OFFなどにも同じことが当てはまります。StrictYAMLが詳細に文書化しています。修正は値を引用符でくくる("NO")か、YAML 1.2に従うパーサーを使うことです。1.2はtrue、false、nullのみを暗黙的に変換します。
anchors、aliases、merge keysはどう動きますか?
anchor (&name)はノードに印を付け、後でalias (*name)で参照できるようにし、長いファイルでの重複を避けます。merge key (<<: *name)はYAML 1.1の拡張で、参照されたmappingのすべてのキーを現在のmappingにコピーするもので、サービス間で共通設定を共有するのに便利です。merge keysはYAML 1.2の一部ではありませんが、js-yamlを含むほとんどのパーサーは互換性のためにまだサポートしています。diffはanchorsとaliasesをプレーンテキストとして扱うので、リネームされたanchorはきれいに見えます。
YAML diffツールにJSONを貼り付けられますか?
はい。JSONはYAML 1.2の厳密な部分集合なので、有効なJSONドキュメントは有効なYAMLドキュメントでもあります。本当に望むなら2つを混ぜることもでき、ブロックスタイルのファイルにJSONスタイルのflow collectionを落とすこともできます。純粋なJSON作業には、JSON diffツールにJSON対応のformatとvalidateボタンがあり、pretty-printとsort-keysも含まれます。
タブを使ったときにパーサーがファイルを拒否するのはなぜですか?
YAML specがインデントとしてのタブを禁止しているからです。1.2.2 specからの引用: "To maintain portability, tab characters must not be used in indentation"。タブはスカラー値の中では許可されています(文字列にタブを含められます)、ただインデントが測定される行頭ではダメです。修正方法は、ファイルがすでに使っている慣例に従って、タブから2スペースまたは4スペースに素早く検索置換することです。
プライバシーと仕組み
あなたのYAMLはブラウザの外に出ません。エディタ、シンタックスハイライター、diffはすべてあなたのマシン上、ローカルで動作します。入力に対する分析もログもクラウドへの往復もありません。私たちが従う形式はYAML 1.2.2 specificationです。何もアップロードされていないことを確認するには、比較中にDevToolsを開いてNetworkタブを見てください。