📌

RailsのYAMLファイルの書き間違いに気づきたい

2024/05/30に公開

最近、自作のWebフレームワーク開発を断念したyosiです。

暇を持て余して公開していたGemのメンテナンスを久々にしたついでに、そのGemを紹介しようとキーボードをたたきました。

yaml_structure_checker といいます。基本的にRails専用のGemで、configフォルダのYAMLファイルのKeyをチェックするGemです。

https://github.com/yosipy/yaml_structure_checker

https://rubygems.org/gems/yaml_structure_checker

解決する課題

Railsでプロダクト開発をしているとconfig/database.ymlのように大量のYAMLファイルを見ると思います。それぞれのYAMLファイル内では環境ごとにKey-Valueが設定されています。
config/database.ymlの例を示します。

config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: <%= ENV.fetch("DATABASE_HOST", 'localhost') %>
  port: <%= ENV.fetch("DATABASE_PORT", 5432) %>
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  <<: *default
  database: app_development
  username: pguser
  password: password

test:
  <<: *default
  database: app_test
  username: pguser
  password: password

production:
  <<: *default
  database: app_production
  username: <%= ENV['DATABASE_UERNAME'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>

上に示したコードで一部のインデントがズレてしまうと、当然その部分の値が読めなくなってしまいます。
例えばproductionpasswordの部分のインデントがズレたとします。

config/database.yml
production:
  <<: *default
  database: app_production
  username: <%= ENV['DATABASE_UERNAME'] %>
password: <%= ENV['DATABASE_PASSWORD'] %>  # 本番環境だけ読み込めない

こうなった時、passwordが読み込めなくなるので、このコードを本番環境にデプロイするとデータベースにアクセスできなくなります。
また、文法的に問題が無いためYAMLの文法をチェックしても、このインデントのズレは見つけられません。
さらに悪いことにdevelopmenttestpassword部分のインデントはずれていないため、開発環境やRailsの各テストでも見つかりません。

これは単純なミスです。開発者が気を付けて注意深くレビューを行えば防ぐことができますが、実際のRailsプロダクトではYAMLファイルは巨大で深いインデントに育つことがあるので人間が見落としやすくなります。

yaml_structure_checker GemはYAMLファイル内のKeyが各環境で一致していない場合に警告します。これにより、本番環境でのみ発生するエラーを事前に回避できます。
環境ごとのKey構造を比較するというシンプルな仕様にすることで簡単に導入できます。

kwalifyを使うとKeyだけでなくValueの検証もできますが、スキーマファイルを定義するのは大変です。何よりkwalify Gemはメンテされてないのが致命的です。

使い方

インストール

$ gem install yaml_structure_checker

yaml_structure_checker用の設定ファイルを追加

config/yaml_structure_checker.ymlを追加します。

対象ファイルのパターンをinclude_patternsに書き、その中から除外するパターンをexclude_patternsに書きます。翻訳用のファイルなどが除外する対象になるでしょう。
envsは環境名の一覧です。
理由があって環境ごとに違うKeyがあるファイルがあるかもしれません。そういった場合はskip_pathsに追加することで検証を飛ばすことができます。

config/yaml_structure_checker.yml
# config/yaml_structure_checker.yml
include_patterns:
  - config/**/*.yml
exclude_patterns:
  - config/locales/**/*.yml
envs:
  - development
  - test
  - integration
  - production
skip_paths:
  - config/gcp.yml

Key検証を実行する

以下のコマンドで実行できます。

$ bundle exec yaml_structure_checker

設定ファイルのファイル名をconfig/yaml_structure_checker.yml以外にしたときは、第一引数にファイル名を与えてください。

$ bundle exec yaml_structure_checker config/other_yaml_faile_path.yml

CI

Github Action等を使い、CIで自動的に検証できます。

name: CI

on: push

jobs:
  ci:
    name: CI
    runs-on: ubuntu-latest
    container:
      image: ruby:3.2.2
    steps:
      - uses: actions/checkout@v2
      - name: Bundle install
        run: bundle install --path=vendor/bundle --jobs 4 --retry 3
      - name: YAML structure checker
        run: bundle exec yaml_structure_checker

最後に

機能を絞った小さなGemですが細々とメンテを続けていこうと思います。
スターください。

https://github.com/yosipy/yaml_structure_checker

Discussion