-
Notifications
You must be signed in to change notification settings - Fork 3
/
rubocop-pre-commit
executable file
·121 lines (98 loc) · 2.51 KB
/
rubocop-pre-commit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#! /usr/bin/env ruby
# Run rubocop against the files being committed, fixing what we can. Fixed offenses won't wind up
# in the commit, though, so abort if we find any offenses.
#
# Offenses in unstaged changes will currently abort the commit, but could be avoided by comparing
# the line number of the offense to those of the staged changes.
require 'json'
require 'open3'
require 'pathname'
class GitStatusLine
STATUSES = {
"A" => :added,
"B" => :pairing_broken,
"C" => :copied,
"D" => :deleted,
"M" => :modified,
"R" => :renamed,
"T" => :type_changed,
"U" => :unmerged,
"X" => :unknown
}
STATUS_LINE_REGEX = /^[#{STATUSES.keys.join("|")}]\s+/
def self.is_status_line?(line)
line =~ STATUS_LINE_REGEX
end
def self.from(line)
return nil unless is_status_line?(line)
new(line.chomp)
end
attr_reader :status
def initialize(line)
@line = line
@status = STATUSES[@line[0]]
end
def pathname
GitStatusPathname.new(@line.gsub(STATUS_LINE_REGEX, ''))
end
def added?
status == :added
end
def modified?
status == :modified
end
end
class GitStatusPathname
def initialize(filename)
@path = Pathname.new(filename)
end
def to_s
@path.to_s
end
def ruby?
@path.extname == ".rb" ||
@path.extname == ".rake" ||
@path.basename == "Gemfile"
end
end
class GitDiff
def self.status_lines
output = `git diff --cached --name-status`
output.lines.map{|l| GitStatusLine.from(l) }.compact
end
end
def changed_files
GitDiff.status_lines
.select{|f| f.added? || f.modified? }
.map(&:pathname)
.select(&:ruby?)
end
file_list = changed_files.join(" ")
if file_list == ""
puts "No files to check."
exit(0)
end
puts "Running rubocop against #{file_list}"
output, err, status = Open3.capture3("bundle exec rubocop --format json --force-exclusion --display-cop-names --auto-correct #{file_list}")
unless err.empty?
puts "Error executing Rubocop."
puts err
exit(1)
end
json = JSON.parse(output)
offenses = json["summary"]["offense_count"]
exit(0) if offenses == 0
puts "Rubocop found #{offenses} offense#{"s" if offenses > 1}. Aborting commit."
clean = true
json["files"].each do |file|
path = file["path"]
uncorrected = file["offenses"].reject{|offense| offense["corrected"] }
clean &&= uncorrected.empty?
uncorrected.each do |offense|
line = offense["location"]["line"]
message = offense["message"]
puts "#{path}:#{line} #{message}"
end
end
puts "All offenses corrected." if clean
exit(1)