📌

reviewdog/action-rubocop実行時に起きたGem::FilePermissionErrorの対処

2021/03/22に公開

現象

reviewdog/action-rubocopを使用してGitHub Actionsを実行したところ、Gem::FilePermissionErrorが発生しました。

GitHub Acitonsのログ

Run reviewdog/action-rubocop@v1
🐶 Installing reviewdog ... https://github.com/reviewdog/reviewdog
 Installing rubocop with extensions ... https://github.com/rubocop/rubocop
  ERROR:  While executing gem ... (Gem::FilePermissionError)
      You don't have write permissions for the /var/lib/gems/2.7.0 directory.
  Error: Process completed with exit code 1.

このときのワークフローファイルは、以下のymlとなっています。

name: reviewdog
on: [pull_request]
jobs:
  rubocop:
    name: runner / rubocop
    runs-on: ubuntu-latest
    steps:
      - name: Check out code
        uses: actions/checkout@v1
      - name: rubocop
        uses: reviewdog/action-rubocop@v1
        with:
          rubocop_version: 1.8.1
          # rubocop_extensions: rubocop-rails:gemfile rubocop-rspec:gemfile
          github_token: ${{ secrets.github_token }}
          reporter: github-pr-review # Default is github-pr-check

調査

問題の発生場所の特定

まずは問題が起きている場所の特定です。Reviewdogのコードを調べたところ、action.ymlでscript.shを実行しているようです。

・・・略・・・
runs:
  using: 'composite'
  steps:
    - run: $GITHUB_ACTION_PATH/script.sh
・・・略・・・

https://github.com/reviewdog/action-rubocop/blob/cdeaf0c191d62bcc651ae3a231c268f10b8ca1a5/action.yml#L46

このscirpt.shと現象のログを合わせて確認すると、Installing rubocop with extensions ... https://github.com/rubocop/rubocopのログのあとに失敗しているので、gem installに失敗しているようです。

・・・略・・・
echo '::group::🐶 Installing reviewdog ... https://github.com/reviewdog/reviewdog'
curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/master/install.sh | sh -s -- -b "${TEMP_PATH}" "${REVIEWDOG_VERSION}" 2>&1
echo '::endgroup::'

echo '::group:: Installing rubocop with extensions ... https://github.com/rubocop/rubocop'
# if 'gemfile' rubocop version selected
if [ "${INPUT_RUBOCOP_VERSION}" = "gemfile" ]; then
  # if Gemfile.lock is here
  if [ -f 'Gemfile.lock' ]; then
    # grep for rubocop version
    RUBOCOP_GEMFILE_VERSION=$(ruby -ne 'print $& if /^\s{4}rubocop\s\(\K.*(?=\))/' Gemfile.lock)

    # if rubocop version found, then pass it to the gem install
    # left it empty otherwise, so no version will be passed
    if [ -n "$RUBOCOP_GEMFILE_VERSION" ]; then
      RUBOCOP_VERSION=$RUBOCOP_GEMFILE_VERSION
      else
        printf "Cannot get the rubocop's version from Gemfile.lock. The latest version will be installed."
    fi
    else
      printf 'Gemfile.lock not found. The latest version will be installed.'
  fi
  else
    # set desired rubocop version
    RUBOCOP_VERSION=$INPUT_RUBOCOP_VERSION
fi

gem install -N rubocop --version "${RUBOCOP_VERSION}"

# Traverse over list of rubocop extensions
for extension in $INPUT_RUBOCOP_EXTENSIONS; do
  # grep for name and version
  INPUT_RUBOCOP_EXTENSION_NAME=$(echo "$extension" |awk 'BEGIN { FS = ":" } ; { print $1 }')
  INPUT_RUBOCOP_EXTENSION_VERSION=$(echo "$extension" |awk 'BEGIN { FS = ":" } ; { print $2 }')

  # if version is 'gemfile'
  if [ "${INPUT_RUBOCOP_EXTENSION_VERSION}" = "gemfile" ]; then
    # if Gemfile.lock is here
    if [ -f 'Gemfile.lock' ]; then
      # grep for rubocop extension version
      RUBOCOP_EXTENSION_GEMFILE_VERSION=$(ruby -ne "print $& if /^\s{4}$INPUT_RUBOCOP_EXTENSION_NAME\s\(\K.*(?=\))/" Gemfile.lock)

      # if rubocop extension version found, then pass it to the gem install
      # left it empty otherwise, so no version will be passed
      if [ -n "$RUBOCOP_EXTENSION_GEMFILE_VERSION" ]; then
        RUBOCOP_EXTENSION_VERSION=$RUBOCOP_EXTENSION_GEMFILE_VERSION
        else
          printf "Cannot get the rubocop extension version from Gemfile.lock. The latest version will be installed."
      fi
      else
        printf 'Gemfile.lock not found. The latest version will be installed.'
    fi
  else
    # set desired rubocop extension version
    RUBOCOP_EXTENSION_VERSION=$INPUT_RUBOCOP_EXTENSION_VERSION
  fi

  # Handle extensions with no version qualifier
  if [ -z "${RUBOCOP_EXTENSION_VERSION}" ]; then
    unset RUBOCOP_EXTENSION_VERSION_FLAG
  else
    RUBOCOP_EXTENSION_VERSION_FLAG="--version ${RUBOCOP_EXTENSION_VERSION}"
  fi

  # shellcheck disable=SC2086
  gem install -N "${INPUT_RUBOCOP_EXTENSION_NAME}" ${RUBOCOP_EXTENSION_VERSION_FLAG}
done
echo '::endgroup::'

export REVIEWDOG_GITHUB_API_TOKEN="${INPUT_GITHUB_TOKEN}"

echo '::group:: Running rubocop with reviewdog 🐶 ...'
・・・略・・・

https://github.com/reviewdog/action-rubocop/blob/master/script.sh

このgemのインストール失敗と、今回のエラーログについて調べたところ、以下の2つの記事を見つけました。

この2つの記事と今回の現象から、原因と対策は以下の通りであると思われます。

「GitHub Actions上でgemを使用してRubocopのインストールを行う際、GitHub Actionsのシステム側のRubyを参照していたようです。そのため、この参照がPermissionErrorとなり、この現象が発生していました。
ワークフローにruby/setup-rubyのアクションを追加することで、GitHub Actionsのローカル側のRubyを参照するようになり、PermissionErrorが発生せずにgemのインストールができると考えられます。」

対応

ワークフローファイルにruby/setup-rubyのアクションを追加し、Rubyバージョン(3.0.0)を指定することで、この問題を解決できました。

name: reviewdog
on: [pull_request]
jobs:
  rubocop:
    name: runner / rubocop
    runs-on: ubuntu-latest
    steps:
      - name: Check out code
        uses: actions/checkout@v1
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: 3.0.0
      - name: rubocop
        uses: reviewdog/action-rubocop@v1
        with:
          rubocop_version: 1.8.1
          github_token: ${{ secrets.github_token }}
          reporter: github-pr-review # Default is github-pr-check

Discussion