Эпизод #5 - Overcommit

Overcommit - инструмент для удобного управления хуками гита, рассмотрим его как инструмент для самоконтроля по написанию чистого кода. Overcommit будет полезен как фронтендерам, так и бекендерам за счет того, что имеет большую базу предустановленных хуков. В данной статье будет рассмотрена настройка проверки кода утилитами RuboCop и Fasterer при каждой попытке сделать коммит.

Установка

Overcommit устанавливается как gem, командой:

gem install overcommit

Теперь можно устанановить хуки в репозиторий.

Важно: установка производится в корневом каталоге проекта, где инициализирован Git репозиторий. Если репозиторий не инициализирован, то запустите команду git init.

overcommit --install

Данная команда заменит все существующие хуки. Ваши хуки будут сохранены в резервной копии и их можно восстановить командой:

overcommit --uninstall

Конфигурация

Все специфичные для репозитория настройки хранятся в файле .overcommit.yml, который распологается в корневой директории вашего проекта. Ваш конфигурационный файл будет автоматически расширять настройки по умолчанию.

Предположим, что мы хотим настроть хуки, которые будут срабатывать каждый раз, когда мы создаем новый коммит (PreCommit). Хуки должны проверить код на соответствие так называемым style-guide и убедиться, что при написании кода мы использовали самые оптимальные методы. В этом нам помогут уже знакомые по предыдущим эпизодам инструменты Rubocop и Fasterer. Все возможные PreCommit-хуки можно найти тут.

Начнем с подключения Rubocop.

.overcommit.yml

Precommit:
  RuboCop:
    enabled: true
  1. Указываем момент срабатывания хука - PreCommit.
  2. Прописываем название самого хука - Rubocop.
  3. Активируем его enabled: true

Далее нужно определиться с поведением хука для строк, которые не были модифицированны. Ранее мы определились, что мы хотим, чтобы хук анализировал только тот код, который был изменен. Поэтому нужно добавить опцию problem_on_unmodified_line с флагом ignore. А также определить поведение, когда будут найдены несоответствия. Настроим так, чтобы коммит нельзя было создать, пока не будут исправлены все несоответствия. В этой задаче нам поможет флаг on_warn с флагом fail.

Precommit:
  RuboCop:
    enabled: true
    on_warn: fail
    problem_on_unmodified_line: ignore

Часто требуется исключить некоторые файлы из проекта. Допустим, мы работаем над Rails проектом и хотим исключить из хука Rubocop все файлы, которые лежат в директории **/db/. Тогда наш конфигурационный файл примет следующий вид:

Precommit:
  RuboCop:
    enabled: true
    on_warn: fail
    problem_on_unmodified_line: ignore
    exclude:
      - '**/db/'

Теперь можно проделать тоже самое для хука Fasterer. Все шаги практически идентичны предыдущим, за несколькими исключениями. Вот так будет выглядеть обновленный конфигурационный файл:

Precommit:
  RuboCop:
    enabled: true
    on_warn: fail
    problem_on_unmodified_line: ignore
    exclude:
      - '**/db/'

  Fasterer:
    enabled: true
    on_warn: fail
    problem_on_unmodified_line: ignore

Важно: убедитесь, что у вас установлены Rubocop и Fasterer, перед использованием этого конфигурационного файла.

gem install fasterer rubocop

После того как конфигурационный файл подготовлен необходимо прописать новые хуки в настройки вашего репозитория:

overcommit --sign

Данную команду нужно запускать каждый раз, после того как вы внесли какие-либо изменения в конфигурационный файл.

Использование

После того как Overcommit настроен и хуки прописаны в вашем репозитории, при попытке сделать коммит, будет производиться анализ измененного кода. Если будут найдены какие-либо несоответствия прописанным правилам, созадние коммита будет прервано и указаны инструкции для испавления ошибок.

Для примера напишем класс User. Добавим пару простых методов, первый будет находить первого администратора среди всех пользователей, второй будет возвращать название роли пользователя.

class User
  attr_reader :first_name, :last_name, :email, :admin?

  def self.first_admin
    all.select { |user| user.admin? }.first
  end

  def role_name
    if admin?
      "Администратор"
    else
      "Пользователь"
    end
  end
end

Добавим новый код репозиторий:

git add user.rb
git commit

Добавленный код был проанализирован, коммит отменен и мы видим допущенные ошибки.

overcommit-failed

Внесем изменения согласно данному отчету:

class User
  attr_reader :first_name, :last_name, :email, :admin?

  def self.first_admin
    all.detect(:admin?)
  end

  def role_name
    if admin?
      'Администратор'
    else
      'Пользователь'
    end
  end
end

Повторим создание коммита:

git add user.rb
git commit

Теперь код валиден и мы можем завершить создание коммита

overcommit-success

Бывают случаи, когда исправить код не получается, а коммит нужно сделать и причем срочно. Для таких случаем нам придут на помощь переменные окружения. С помощью них можно отключить определенный хук или наоборот запустить только конкретный, а можем поностью провести коммит отключив все хуки. Вот примеры таких команд:

SKIP=RuboCop git commit # пропустить хук RuboCop
ONLY=RuboCop git commit # запустить только RuboCop
OVERCOMMIT_DISABLE=1 git commit # отключить все хуки

Для удобства можно создать алиасы для часто используемых команд.

Обязательно загляните в оф. репозиторий и изучите все возможности Overcommit.

В этой статье рассмотрена лишь малая часть возможностей этой замечательной утилиты, но даже эта малая часть поможет сделать вашу работу чуточку проще.