Created
January 29, 2019 17:26
-
-
Save mattbee/8db2f0da68821314d1e11332bce1e2c5 to your computer and use it in GitHub Desktop.
pre-commit hook
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
REQUIRED_GEMS = %w(rubocop) | |
REQUIRED_GEMS.each do |gem_name| | |
begin | |
require gem_name | |
rescue LoadError => e | |
puts "=" * 50 | |
puts "Please ensure that '#{gem_name}' is installed on your system e.g. `gem install #{gem_name}`" | |
puts "=" * 50 | |
raise | |
end | |
end | |
class GitStatus | |
ADDED_OR_MODIFIED = /A|AM|^M/.freeze | |
def changed_files(file_extension_filters: []) | |
if file_extension_filters.any? | |
new_or_modified_filenames.select do |filename| | |
file_extension_filters.include?(File.extname(filename).delete('.')) | |
end | |
else | |
new_or_modified_filenames | |
end | |
end | |
private | |
def git_status | |
@git_status ||= `git status --porcelain`.split(/\n/) | |
end | |
def new_or_modified_filenames | |
git_status.select do |filename_with_status| | |
filename_with_status =~ ADDED_OR_MODIFIED | |
end.map do |filename_with_status| | |
filename_with_status.split(' ')[1] | |
end | |
end | |
end | |
class Linter | |
def initialize(filename_list) | |
@filename_list = filename_list | |
end | |
def lint! | |
puts "======== Linting with #{linter_name} ========" | |
exit_status = system("#{lint_executable} #{filenames_as_single_line}") | |
puts "\n" | |
exit_status | |
end | |
private | |
attr_reader :filename_list | |
def filenames_as_single_line | |
filename_list.join(' ') | |
end | |
end | |
class Linter::Rubocop < Linter | |
def self.file_extensions | |
%w(rb) | |
end | |
def lint_executable | |
'bundle exec rubocop --force-exclusion' | |
end | |
def linter_name | |
'rubocop' | |
end | |
end | |
class Linter::SASSLint < Linter | |
def self.file_extensions | |
%w(scss) | |
end | |
def lint_executable | |
'yarn run sass-lint' | |
end | |
def linter_name | |
'sass-lint' | |
end | |
end | |
class Linter::JSHint < Linter | |
def self.file_extensions | |
%w(js js.erb) | |
end | |
def lint_executable | |
'yarn run jshint-single' | |
end | |
def linter_name | |
'jshint' | |
end | |
private | |
def filename_list | |
@filename_list.select { |filename| filename =~ %r{app/assets/javascripts/} } | |
end | |
end | |
class Linter::JSCS < Linter | |
def self.file_extensions | |
%w(js js.erb) | |
end | |
def lint_executable | |
'yarn run jscs-single' | |
end | |
def linter_name | |
'jscs' | |
end | |
end | |
class Linter::HAMLLint < Linter | |
def self.file_extensions | |
%w(haml) | |
end | |
def lint_executable | |
'bundle exec haml-lint' | |
end | |
def linter_name | |
'haml-lint' | |
end | |
end | |
class Linter::ESLint < Linter | |
def self.file_extensions | |
%w(js jsx) | |
end | |
def lint_executable | |
'yarn run eslint-single -- --quiet' | |
end | |
def linter_name | |
'eslint' | |
end | |
private | |
def filename_list | |
files_that_use_es6 | |
end | |
def files_that_use_es6 | |
@filename_list.select { |filename| filename =~ %r{app/javascript/} } | |
end | |
end | |
class Linter::Locale < Linter | |
def self.file_extensions | |
%w(yml) | |
end | |
def lint_executable | |
'bundle exec rake lint:locale' | |
end | |
def linter_name | |
'locale' | |
end | |
private | |
def filename_list | |
@filename_list.select { |filename| filename =~ %r{config/locales/en.yml} } | |
end | |
end | |
linters = [ | |
Linter::Rubocop, | |
Linter::JSHint, | |
Linter::JSCS, | |
Linter::ESLint, | |
Linter::SASSLint, | |
Linter::HAMLLint, | |
Linter::Locale | |
] | |
git_status = GitStatus.new | |
linter_exit_statuses = [] | |
linters.each do |linter_class| | |
changed_filename_list = git_status.changed_files(file_extension_filters: linter_class.file_extensions) | |
if changed_filename_list.any? | |
linter_exit_statuses << linter_class.new(changed_filename_list).lint! | |
end | |
end | |
if linter_exit_statuses.all? { |status| status == true } | |
exit 0 | |
else | |
exit 1 | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment