0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Github Actions に RuboCop, Erb Lint, RSpec( Model, System ) を 導入 (Docker + Rails 8.0.0 環境)

Posted at

概要

今回は、現在開発中のWebアプリにGithub ActionsによるCIを実装した際、Rubocop, Erb Lint, RSpecの導入に2日ほど費やしてしまったため、今後のために備忘録としてまとめたものになります。
初学者の身であり、Github Actionsへの理解も甘いため、間違って認識している点もあるかと思いますので、ご指摘いただけると幸いです。

Github ActionsによるRuboCop, Erb LintのCI設定

作成したファイル

  • .github/workflows/ci.yml
  • .erb_lint.yml
  • .rubocop.yml
  • .rubocop_todo.yml

使用したGem

  • rubocop-rails-omakase
  • rubocop
  • rubocop-performance
  • rubocop-rails
  • rubocop-rspec
  • erb_lint
.github/workflows/ci.yml

  lint:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: .ruby-version
          bundler-cache: true
       
      - name: RuboCop
        run: bundle exec rubocop --fail-level W
        
      - name: ERB Lint
        run: bundle exec erb_lint --lint-all

ci.ymlはRails7以上であればrails newで自動生成されるかと思います。
ここでは、lintというjobの一つのstepとしてRuboCopERB Lintというテストを実行するよう設定しています。

- name: RuboCop
        run: bundle exec rubocop --fail-level W

RuboCopを実行するよう指示しています。
--fail-level W:これはテスト実行後にfailを判定する基準を指定しています。ここではW(Worning)を指定しているので、 Worning以上の違反がある場合のみテストが通らないようになっています。(W未満の違反でも検知はしてくれるので、適宜確認して修正することは可能です)

- name: ERB Lint
        run: bundle exec erb_lint --lint-all

Erb Lint(erbファイルのリントチェック)の実行を指示しています。
erblint --lint-allのように_がなくても実行はできますが、今は警告が出てしまうみたいなのでerb_lintとしました。

.erb_lint.yml
---
EnableDefaultLinters: true
glob: "**/*.{html,text,js}{+*,}.erb"
exclude:
  - '**/vendor/**/*'
  - '**/node_modules/**/*'
linters:
  ErbSafety:
    enabled: true
  Rubocop:
    enabled: true
    rubocop_config:
      inherit_from:
        - .rubocop.yml
      Style/FrozenStringLiteralComment:
        Enabled: false
      Layout/InitialIndentation:
        Enabled: false

Erb Lintの設定ファイルになります。
Rubocop: 以下の記述があることで、RuboCopによる解析と連動させることができます。

Style/FrozenStringLiteralComment:
        Enabled: false
      Layout/InitialIndentation:
        Enabled: false
Layout/InitialIndentation:
        Enabled: false

この部分ではRuboCopのルール設定をしています。これに関しては、私自身まだ何が必要で何が不要なのかの判断はつかないため、各々の環境に合わせて設定していただくのがいいと思います。
おすすめの設定があれば教えていただきたいです。

.rubocop.yml
inherit_from: .rubocop_todo.yml

inherit_gem: { rubocop-rails-omakase: rubocop.yml }

RuboCopの設定ファイルになります。bundle exec rubocop --auto-gen-configを実行すると自動で生成されます。
ここに必要なルールを設定していくことで現場にあったテストを実行できるようになります。

.rubocop_todo.ymlは空のままで大丈夫です。

以上でGihub ActionsにRuboCop、Erb Lintを導入するためのCI設定は完了です。
続いてRSpecを導入していきますが、まずはローカル(docker)環境でRSpecを実行するための環境づくりから見ていきましょう。

RSpecの導入

ここではまず、ローカルでRSpecを実行するための環境づくりから始めていきます。

作成したファイル

  • rails_helper.rb
  • spec_helper.rb
  • .rspec
  • capybara.rb
  • database.ci.yml

追加したGem

  • deveopment, test環境
    • factory_bot_rails
    • database_cleaner"
    • faker
    • rspec_rails

  • development環境
    • spec_rails

  • test環境
    • capybara
    • selenium_webdrivers
    • webdrivers

RSpecの導入

bundle installで必要なgemをインストールしたら、下記のコマンドを実行しましょう。

bundle exec rails g rspec:install

これによりRSpecの設定に必要な以下のファイルが自動で生成されます。
.rspec
spec/spec_helper.rb
spec/rails_helper.rb

まずはDockerの設定にRSpec SystemでCapybaraを使用するための設定を追加していきます。

docker-compose.yml
web:
    container_name: rails_app
    build:
      context: .
      dockerfile: Dockerfile.prod
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    tty: true
    stdin_open: true
    volumes:
      - .:/myapp
      - bundle_data:/usr/local/bundle:cached
      - node_modules:/myapp/node_modules
    environment:
      TZ: Asia/Tokyo
      SELENIUM_DRIVER_URL: http://chrome:4444/wd/hub # この行を追加
    ports:
      - "3000:3000"
    depends_on:
      db:
        condition: service_healthy
  chrome: # このセクションを追加
    image: seleniarm/standalone-chromium:latest
    ports:
      - 4444:4444

docker-compose.ymlにSELENIUM_DRIVER_URL:の一行とchrome:のセクションを追加します。この設定によりDocker環境でCapybaraを使用したブラウザ操作を自動化したテストが可能になります。

では続いて、生成されたrails_helper.rb .rspecに設定を追加していきます。

spec/rails_helper.rb
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }
# この行はコメントアウトを解除するだけで大丈夫です
    ...
RSpec.configure do |config|
    ...
    config.include FactoryBot::Syntax::Methods # この行を追加
    ...
    config.before(:each, type: :system) do # このブロックを追加
    if ENV['SELENIUM_DRIVER_URL']
      driven_by :remote_chrome
      Capybara.server_host = IPSocket.getaddress(Socket.gethostname)
      Capybara.server_port = 4444
      Capybara.app_host = "http://#{Capybara.server_host}:#{Capybara.server_port}"
      Capybara.ignore_hidden_elements = false
    else
      driven_by :selenium_chrome_headless
    end
  end
end

config.include FactoryBot::Syntax::Methods
この設定により、FactoryBotをspec内で簡単に使用できるようになります。
例)設定なしの場合
user = FactoryBot.create(:user)

例)設定ありの場合
user = create(:user)

config.before(:each, type: :system) do
このブロックでは、Capybaraによるブラウザ操作を行う際のホスト、ポートなどを指定しています。if ENV['SELENIUM_DRIVER_URL']の条件により、環境変数が指定されている場合、つまりDockerコンテナ内でRSpecを実行する場合にはSelenium(remote_chrome)を使用し(ローカルでのDocker開発環境でRSpecを実行する場合ならこっち)、Dockerコンテナを使わないで実行する場合には、その環境にインストールされているChromeを使用するように分岐させています。今回、Github ActionsではDockerコンテナを立ち上げずに実行しているのでSeleniumの方を使用することになります。
https://qiita.com/ryouzi/items/fe0f583dcc93e06b6e64

.rspec
--format documentation # この行を追加

この設定により、RSpecのテスト結果の出力形式を「ドキュメンテーション形式」に設定し、テストの実行結果がより読みやすくなります。

capybara.rb
require 'capybara/rspec'
require 'selenium-webdriver'

Capybara.register_driver :remote_chrome do |app|
  options = Selenium::WebDriver::Chrome::Options.new
  options.add_argument('no-sandbox')
  options.add_argument('headless')
  options.add_argument('disable-gpu')
  options.add_argument('window-size=1680,1050')
  Capybara::Selenium::Driver.new(app, browser: :remote, url: ENV['SELENIUM_DRIVER_URL'], capabilities: options)
end

Capybara.javascript_driver = :selenium_chrome_headless

CapybaraがリモートのChromeドライバーを使うために必要なオプションを指定しています。
url: ENV['SELENIUM_DRIVER_URL']により、docker-compose.ymlで指定した環境変数SELENIUM_DRIVER_URLをサーバーのurlとして指定しています。

config/environments/test.rb
config.hosts << "許可したいホストのIP"

Railsサーバーに特定のホストからのリクエストを許可するための記述になります。RSpec Systemの実行時にホストが拒否される場合に追加してください。

以上で、ローカルでRSpec Model, Systemを実行するための環境は整いました。実際のテストコードについては、ここでは割愛します。
では続いて、Github ActionsにRSpecを導入していきましょう。

Gihub ActionsにRSpecを導入するためのCI設定

私はここで一番時間を取られました。
まずはci.ymlの設定を追加・変更していきます。

ci.yml

test:
    runs-on: ubuntu-latest

    services:
      postgres:
        image: postgres
        env:
          POSTGRES_USER: # ユーザー名を指定
          POSTGRES_PASSWORD: # パスワードを指定
        ports:
          - 5432:5432
        options: --health-cmd="pg_isready" --health-interval=10s --health-timeout=5s --health-retries=3

      timeout 5s --health-retries 5
    env:
      RAILS_ENV: test # この行を追加
      DATABASE_URL: postgres://postgres:postgres@localhost:5432/myapp_test

    steps:
      - name: Install packages
        run: sudo apt-get update && sudo apt-get install --no-install-recommends -y google-chrome-stable curl libjemalloc2 libvips postgresql-client

      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: .ruby-version
          bundler-cache: true

      - name: Database create and migrate # このセクションを追加
        run: |
          cp config/database.ci.yml config/database.yml
          bundle exec rails assets:precompile #ここで詰まった
          bundle exec rails db:create
          bundle exec rails db:migrate

      - name: Run rspec # このセクションを追加
        run: bundle exec rspec

env:の部分でこれ以下の処理をテスト環境で実行するように指定しています。
name: Database create and migrateのセクションではRSpec Systemを実行するために一時的にデータベースを作成しています。

database.ci.yml
test:  
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  host: db
  username: # ユーザー名
  password: # パスワード
  database: myapp_test

ここでテスト用のデータベースを設定しています。

私が時間を取られたポイント

アセットのプリコンパイルができていなかった

私は初め、bundle exec rails assets:precompileが抜けていたために、ActionView::Template::Error:The asset 'application.js' was not found in the load path.
というエラーが出てしまい、プリコンパイルができていないということに気づくまでに時間を取られました。

entorypoint.shにも同様のコードを書いていますが、Github ActionsではDockerコンテナを起動していないため、entorypoint.shも実行されていなかった、ということだと解釈しました。

ChromeとChromeDriverのバージョンの不一致

gem "webdrivers"はインストールされているChromeのバージョンに適するChromeDriverを見つけてくれるらしいのですが、それがうまく見つからないのか、
Webdrivers::NetworkError: # Net::HTTPClientException: 404 "Not Found" with https://chromedriver.storage.googleapis.com/LATEST_RELEASE_131.0.6778
というエラーが出てしまい、テストが実行できませんでした。
Gemfile.lockを確認すると、webdrivers (5.2.0)がインストールされていたので、最新版のwebdrivers (5.3.1)をバージョンを指定してインストールしてみたところ、エラーが解消されました。

終わりに

本記事はほとんど自分用として今回取り組んだことをまとめたものになりますので、色々と至らない点があるかと思いますがご了承ください。
間違っている点などありましたらご指摘いただけると幸いです。

参考にさせていただいた記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?