🤖

エラー逃さずYARDドキュメントをCIで検証する

2024/02/13に公開

この記事について

こんにちは、okumudです。Rubyのドキュメンテーションに使われるYARDをCIチェックするヒントをお伝えします。執筆時のYARDバージョンは0.9.34です。

ソースコードを読むことが多いため、YARDドキュメントを記載しています。しかし、記載ミスなどがよくあるため、CIでチェックしたいと考えていました。

課題1: CIでYARDエラーを検知できない

ありがちな間違いを含むコードでチェックを試みます。

person.rb
# frozen_string_literal: true

# Personクラスは人の情報を表します
class Person
  # Personオブジェクトを初期化します
  #
  # @params name [String] 人の名前 <= 誤ってsをつけてしまっている
  # @param [Integer] 人の年齢 <= 変数名の記載漏れ
  def initialize(name, age)
    @name = name
    @age = age
  end

  # @!attribute [r] name
  #   @returns [String] 人の名前 <= 誤ってsをつけてしまっている
  # @!attribute [r] age
  #   @return [Integer] 人の年齢
  attr_reader :name, :age

  # 人の情報を文字列で返します
  #
  # @return [String] 人の名前と年齢を含む文字列
  def to_s
    "#{@name}, #{@age}歳"
  end
end

警告があるにも関わらず、exit codeが0(正常)となり、CIがエラーになりません。

$ bundle exec yard stats ./person.rb
[warn]: Unknown tag @params in file `person.rb` near line 9
[warn]: @param tag has unknown parameter name: 人の年齢
    in file `person.rb' near line 9
[warn]: Unknown tag @returns in file `person.rb` near line 18
[warn]: Unknown tag @returns in file `person.rb` near line 18
...中略...
 80.00% documented
$ echo $?
0

解決方法: --fail-on-warning オプションを使い、YARDエラーを検知する

--fail-on-warningを付与してチェックを行うと、exit codeが1となり、エラーを検知できます。

$ bundle exec yard stats ./person.rb --fail-on-warning
...中略...
$ echo $?
1
参考: `yard stats`のヘルプに`--fail-on-warning`オプションの記載がありました
$ bundle exec yard stats --help
Usage: yard stats [options] [source_files]
(if a list of source files is omitted, lib/**/*.rb ext/**/*.{c,rb} is used.)

General Options:
    -b, --db FILE                    Use a specified .yardoc db to load from or save to
                                       (defaults to .yardoc)
        --[no-]single-db             Whether code objects should be stored to single
                                       database file (advanced)
    -n, --no-output                  Only generate .yardoc database, no documentation.
    -c, --use-cache [FILE]           Use the cached .yardoc db to generate documentation.
                                       (defaults to no cache)
        --no-cache                   Clear .yardoc db before parsing source.
        --[no-]yardopts [FILE]       If arguments should be read from FILE
                                       (defaults to yes, FILE defaults to .yardopts)
        --[no-]document              If arguments should be read from .document file.
                                       (defaults to yes)
        --no-save                    Do not save the parsed data to the yardoc db
        --exclude REGEXP             Ignores a file if it matches path match (regexp)
        --fail-on-warning            Exit with error status code if a warning occurs
        --list-undoc                 List all undocumented objects
        --compact                    Compact undocumented objects listing

課題2: Rails.application.routes.url_helpers 等でYARDエラーとなる

前述の例では問題の箇所を修正することで対応できますが、エラーとなることをわかっていて無視したいことがあります。特にシリアライザ等で、 Rails.application.routes.url_helpers を使っている場合、エラーとなって、CIが通らない状態となってしまいます。

class StatusUrlSerializer < ActiveModel::Serializer
  include Rails.application.routes.url_helpers

  attributes :identifier, :status_url

  def status_url
    external_service_status_url(identifier: object.identifier)
  end
end
[warn]: in YARD::Handlers::Ruby::MixinHandler: Undocumentable mixin: YARD::Parser::UndocumentableError for class StatusUrlSerializer
        in file 'app/serializers/status_url_serializer.rb':4:

        4: include Rails.application.routes.url_helpers

解決方法: findsedで無視したい行を削除する

設定等では回避することが難しいので、 該当行のコメントで、# yard:ignoreなどを記述し、 YARD のチェックを行う時は該当行を削除した状態にする方法があります。

find . -type f -name "*.rb" -print0 | xargs -0 sed -i -e '/ yard:ignore/s/.*//'

注意: 上記コマンドを実行した後は該当行が消えてしまうので、後続の処理が無いことを確認してから組み込むようにしてください。

まとめ

yard stats --fail-on-warningのように、--fail-on-warningを指定すると、コマンドの実行結果がエラーとして返ってきます。# yard:ignore などが含まれる行を除外してからチェックすると、YARDのエラーを許容することができます。

付録

GitHub ActionsでYARDドキュメントをチェックする

ほぼGitHub Actionsのサンプル通りですが、次のように記述することで、確認が可能になります。

name: Ruby

on:
  push:
  pull_request:
    branches: [ "main" ]

permissions:
  contents: read

jobs:
  yard:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Set up Ruby
      uses: ruby/setup-ruby@v1.147.0
      with:
        ruby-version: '3.2'
        bundler-cache: true # runs 'bundle install' and caches installed gems automatically
    - name: Clean up ignored yard
      run: find . -type f -name "*.rb" -print0 | xargs -0 sed -i -e '/ yard:ignore/s/.*//'
    - name: Run tests
      run: bundle exec yard stats --fail-on-warning ./*.rb
ワークフローの実行結果

失敗時の結果:ワークフローがエラーとなっている
失敗時

成功時の結果:ワークフローが成功している
成功時

よく使用するオプションは設定ファイル.yardoptsへ記載する

YARD ドキュメントを生成するときにprivateメソッドも常に出力したい場合は、オプションに ---private等を追加しますが、毎回書くには長すぎるので、 .yardopts へ記載しましょう。

.yardopts
--private
--markup markdown
--plugin activesupport-concern
--tag override:Overridden Method
-
README.md

参考文献

SocialPLUS Tech Blog

Discussion