Search code examples
ruby-on-railsgithub-actions

Github workflow for Ruby on Rails - Error #127. rubocop: command not found


I'm reading about workflow/actions/CI and trying to understand how github actions work.

I have this workflow on github actions (I chose one available on Github) for Ruby on Rails.

name: "Ruby on Rails CI"
on:
  push:
    branches: ["master"]
  pull_request:
    branches: ["master"]
jobs:
  test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:11-alpine
        ports:
          - "5432:5432"
        env:
          POSTGRES_DB: rails_test
          POSTGRES_USER: rails
          POSTGRES_PASSWORD: password
    env:
      RAILS_ENV: test
      DATABASE_URL: "postgres://rails:password@localhost:5432/rails_test"
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      # Add or replace dependency steps here
      - name: Install Ruby and gems
        uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0
        with:
          bundler-cache: true
      # Add or replace database setup steps here
      - name: Set up database schema
        run: bin/rails db:schema:load
      # Add or replace test runners here
      - name: Run tests
        run: bin/rails test:system

  lint:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      - name: Install Ruby and gems
        uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0
        with:
          bundler-cache: true
      # Add or replace any other lints here
      - name: Lint Ruby files
        run: rubocop --parallel

And I'm receiving this error during the lint ruby files step.

Run rubocop --parallel
  rubocop --parallel
  shell: /usr/bin/bash -e {0}
/home/runner/work/_temp/ba9b7df9-2b25-4f55-acc3-8349cc07d754.sh: line 1: rubocop: command not found
Error: Process completed with exit code 127.

My gemfile it's updated with rubocop gems. Also already run a bundle to install.

gem 'rubocop', require: false
gem 'rubocop-rails', require: false

I did try changing in the test/lint job the line rubocop --parallel to bundle exec rubocop --parallel, but received another error related to another gem rubocop-discourse.

Everything is normal locally when I use the same commands.

After some testing, removing the line bundler-cache: true from the lint steps made it work. I don't know why, and I still want to understand why. Also, I kept only the rubocop and rubocop-rails in the install.

lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: 3.1.2
      - run: gem install rubocop rubocop-rails
      - name: Rubocop Lint
        run: rubocop --parallel

Solution

  • In the GitHub runner, the workflow;

    name: "rubocop lint"
    on: workflow_dispatch
    jobs:
      lint:
        runs-on: ubuntu-latest
        steps:
          - name: Checkout code
            uses: actions/checkout@v3
          - name: Install Ruby and gems
            uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0
            with:
              ruby-version: 3.1.2
              bundler-cache: true
          - run: echo $PATH | tr ':' '\n'
          - run: bundle info rubocop
          - run: gem which rubocop
          - name: Lint Ruby files
            run: rubocop --parallel
    

    with the Gemfile

    source "https://rubygems.org"
    gem 'rubocop', require: false
    gem 'rubocop-rails', require: false
    

    will show that gem binaries are added to the path at /opt/hostedtoolcache/Ruby/3.1.2/x64/bin, but that the bundle install run inside the action installed the gems to the vendor path;

    /home/runner/work/<repo>/<repo>/vendor/bundle/ruby/3.1.0/gems/rubocop-1.52.1
    

    This path can usually be configured, but it's being hard set in the action, here, to $pwd/vendor/bundle. So using the cache means you'll have to use bundle exec.

    Bundler knows where these gems and their binaries are installed at, but because they are being installed in the vendor path, they are not in the system wide gem binaries /opt/hostedtoolcache/Ruby/3.1.2/x64/bin

    Removing bundler-cache: true and adding the step - run: gem install rubocop rubocop-rails means the gems will be installed at the system path, i.e. their binaries are available at the ruby bin path.

    In terms of understanding why one works and the other doesn't, that's why. gem install is installing to the gem home, and the action is setting the installation location to the vendor folder, which is not in the path.

    If bundle exec rubocop is giving a different error, that'd be related to some other component of your project -- bundle exec would be the canonical way of invoking the executable script installed by bundler