cs-rubocop-git 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.travis.yml +32 -0
- data/Appraisals +31 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +26 -0
- data/README.md +46 -0
- data/Rakefile +15 -0
- data/bin/rubocop-git +5 -0
- data/gemfiles/0.24.gemfile +7 -0
- data/gemfiles/0.25.gemfile +7 -0
- data/gemfiles/0.26.gemfile +7 -0
- data/gemfiles/0.27.gemfile +7 -0
- data/gemfiles/0.28.gemfile +7 -0
- data/gemfiles/0.29.gemfile +7 -0
- data/gemfiles/0.30.gemfile +7 -0
- data/gemfiles/0.31.gemfile +7 -0
- data/gemfiles/0.32.gemfile +7 -0
- data/gemfiles/0.33.gemfile +7 -0
- data/gemfiles/0.34.gemfile +7 -0
- data/gemfiles/0.35.gemfile +7 -0
- data/gemfiles/0.36.gemfile +7 -0
- data/gemfiles/0.37.gemfile +7 -0
- data/gemfiles/0.38.gemfile +7 -0
- data/gemfiles/0.39.gemfile +7 -0
- data/gemfiles/0.40.gemfile +7 -0
- data/gemfiles/0.41.gemfile +7 -0
- data/gemfiles/0.42.gemfile +7 -0
- data/gemfiles/0.43.gemfile +7 -0
- data/gemfiles/0.44.gemfile +7 -0
- data/gemfiles/0.45.gemfile +7 -0
- data/gemfiles/0.46.gemfile +7 -0
- data/gemfiles/0.47.gemfile +7 -0
- data/gemfiles/0.48.gemfile +7 -0
- data/hound.yml +254 -0
- data/lib/rubocop/git.rb +19 -0
- data/lib/rubocop/git/cli.rb +67 -0
- data/lib/rubocop/git/commit.rb +22 -0
- data/lib/rubocop/git/commit_file.rb +55 -0
- data/lib/rubocop/git/diff_parser.rb +31 -0
- data/lib/rubocop/git/file_violation.rb +5 -0
- data/lib/rubocop/git/line.rb +8 -0
- data/lib/rubocop/git/options.rb +84 -0
- data/lib/rubocop/git/patch.rb +36 -0
- data/lib/rubocop/git/pseudo_pull_request.rb +36 -0
- data/lib/rubocop/git/pseudo_resource.rb +24 -0
- data/lib/rubocop/git/runner.rb +70 -0
- data/lib/rubocop/git/style_checker.rb +43 -0
- data/lib/rubocop/git/style_guide.rb +98 -0
- data/lib/rubocop/git/version.rb +5 -0
- data/rubocop-git.gemspec +27 -0
- data/test/rubocop/git/cli_test.rb +12 -0
- data/test/rubocop/git/options_test.rb +18 -0
- data/test/rubocop/git/runner_test.rb +23 -0
- data/test/test_helper.rb +2 -0
- metadata +172 -0
data/lib/rubocop/git.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubocop/git/version'
|
2
|
+
require 'rubocop'
|
3
|
+
|
4
|
+
module RuboCop
|
5
|
+
module Git
|
6
|
+
autoload :Commit, 'rubocop/git/commit'
|
7
|
+
autoload :CommitFile, 'rubocop/git/commit_file'
|
8
|
+
autoload :DiffParser, 'rubocop/git/diff_parser'
|
9
|
+
autoload :FileViolation, 'rubocop/git/file_violation'
|
10
|
+
autoload :Line, 'rubocop/git/line'
|
11
|
+
autoload :Options, 'rubocop/git/options'
|
12
|
+
autoload :Patch, 'rubocop/git/patch'
|
13
|
+
autoload :PseudoPullRequest, 'rubocop/git/pseudo_pull_request'
|
14
|
+
autoload :PseudoResource, 'rubocop/git/pseudo_resource'
|
15
|
+
autoload :Runner, 'rubocop/git/runner'
|
16
|
+
autoload :StyleChecker, 'rubocop/git/style_checker'
|
17
|
+
autoload :StyleGuide, 'rubocop/git/style_guide'
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'rubocop/git'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
module RuboCop
|
5
|
+
module Git
|
6
|
+
class CLI
|
7
|
+
def run(args = ARGV)
|
8
|
+
@options = Options.new
|
9
|
+
parse_arguments(args)
|
10
|
+
Runner.new.run(@options)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def parse_arguments(args)
|
16
|
+
@options.commits = option_parser.parse(args)
|
17
|
+
rescue OptionParser::InvalidOption, Options::Invalid => ex
|
18
|
+
warn "ERROR: #{ex.message}"
|
19
|
+
$stderr.puts
|
20
|
+
warn option_parser
|
21
|
+
exit 1
|
22
|
+
end
|
23
|
+
|
24
|
+
def option_parser
|
25
|
+
@option_parser ||= OptionParser.new do |opt|
|
26
|
+
opt.banner << ' [[commit] commit]'
|
27
|
+
|
28
|
+
opt.on('-c', '--config FILE',
|
29
|
+
'Specify configuration file') do |config|
|
30
|
+
@options.config = config
|
31
|
+
end
|
32
|
+
|
33
|
+
opt.on('-r', '--require FILE',
|
34
|
+
'Require Ruby file') do |file|
|
35
|
+
require file
|
36
|
+
end
|
37
|
+
|
38
|
+
opt.on('-d', '--debug', 'Display debug info') do
|
39
|
+
@options.rubocop[:debug] = true
|
40
|
+
end
|
41
|
+
|
42
|
+
opt.on('-D', '--display-cop-names',
|
43
|
+
'Display cop names in offense messages') do
|
44
|
+
@options.rubocop[:display_cop_names] = true
|
45
|
+
end
|
46
|
+
|
47
|
+
opt.on('--cached', 'git diff --cached') do
|
48
|
+
@options.cached = true
|
49
|
+
end
|
50
|
+
|
51
|
+
opt.on('--staged', 'synonym of --cached') do
|
52
|
+
@options.cached = true
|
53
|
+
end
|
54
|
+
|
55
|
+
opt.on('--hound', 'Hound compatibility mode') do
|
56
|
+
@options.hound = true
|
57
|
+
end
|
58
|
+
|
59
|
+
opt.on('--version', 'Display version') do
|
60
|
+
puts RuboCop::Git::VERSION
|
61
|
+
exit 0
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Git
|
5
|
+
# ref. https://github.com/thoughtbot/hound/blob/d2f3933/app/models/commit.rb
|
6
|
+
class Commit
|
7
|
+
def initialize(options)
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def file_content(filename)
|
12
|
+
if @options.cached
|
13
|
+
`git show :#{filename.shellescape}`
|
14
|
+
elsif @options.commit_last
|
15
|
+
`git show #{@options.commit_last.shellescape}:#{filename.shellescape}`
|
16
|
+
else
|
17
|
+
File.read(filename)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module RuboCop::Git
|
2
|
+
# copy from https://github.com/thoughtbot/hound/blob/d2f3933/app/models/commit_file.rb
|
3
|
+
class CommitFile
|
4
|
+
def initialize(file, commit)
|
5
|
+
@file = file
|
6
|
+
@commit = commit
|
7
|
+
end
|
8
|
+
|
9
|
+
def absolute_path
|
10
|
+
@file.absolute_path
|
11
|
+
end
|
12
|
+
|
13
|
+
def filename
|
14
|
+
@file.filename
|
15
|
+
end
|
16
|
+
|
17
|
+
def content
|
18
|
+
@content ||= begin
|
19
|
+
unless removed?
|
20
|
+
@commit.file_content(filename)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def relevant_line?(line_number)
|
26
|
+
modified_lines.detect do |modified_line|
|
27
|
+
modified_line.line_number == line_number
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def removed?
|
32
|
+
@file.status == 'removed'
|
33
|
+
end
|
34
|
+
|
35
|
+
def ruby?
|
36
|
+
filename.match(/.*\.rb$/)
|
37
|
+
end
|
38
|
+
|
39
|
+
def modified_lines
|
40
|
+
@modified_lines ||= patch.additions
|
41
|
+
end
|
42
|
+
|
43
|
+
def modified_line_at(line_number)
|
44
|
+
modified_lines.detect do |modified_line|
|
45
|
+
modified_line.line_number == line_number
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def patch
|
52
|
+
Patch.new(@file.patch)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Git
|
3
|
+
class DiffParser
|
4
|
+
class << self
|
5
|
+
def parse(diff)
|
6
|
+
new.parse(diff)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse(diff)
|
11
|
+
files = []
|
12
|
+
in_patch = false
|
13
|
+
|
14
|
+
diff.each_line do |line|
|
15
|
+
case line
|
16
|
+
when /^diff --git/
|
17
|
+
in_patch = false
|
18
|
+
when %r{^\+{3} b/(?<path>[^\t\n\r]+)}
|
19
|
+
files << PseudoResource.new(Regexp.last_match[:path])
|
20
|
+
when /^@@/
|
21
|
+
in_patch = true
|
22
|
+
end
|
23
|
+
|
24
|
+
files.last.patch << line if in_patch
|
25
|
+
end
|
26
|
+
|
27
|
+
files
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Git
|
3
|
+
class Options
|
4
|
+
class Invalid < StandardError; end
|
5
|
+
|
6
|
+
HOUND_DEFAULT_CONFIG_FILE =
|
7
|
+
File.expand_path('../../../../hound.yml', __FILE__)
|
8
|
+
|
9
|
+
attr_accessor :config
|
10
|
+
attr_reader :cached, :hound, :rubocop
|
11
|
+
|
12
|
+
def initialize(hash_options = nil)
|
13
|
+
@config = nil
|
14
|
+
@cached = false
|
15
|
+
@hound = false
|
16
|
+
@rubocop = {}
|
17
|
+
@commits = []
|
18
|
+
|
19
|
+
from_hash(hash_options) if hash_options
|
20
|
+
end
|
21
|
+
|
22
|
+
def cached=(cached_)
|
23
|
+
if cached_ && !@commits.empty?
|
24
|
+
fail Invalid, 'cached and commit cannot be specified together'
|
25
|
+
end
|
26
|
+
@cached = !!cached_
|
27
|
+
end
|
28
|
+
|
29
|
+
def hound=(hound_)
|
30
|
+
@hound = !!hound_
|
31
|
+
end
|
32
|
+
|
33
|
+
def rubocop=(rubocop_)
|
34
|
+
unless rubocop_.is_a?(Hash)
|
35
|
+
fail Invalid, "invalid rubocop: #{rubocop_.inspect}"
|
36
|
+
end
|
37
|
+
@rubocop = rubocop_
|
38
|
+
end
|
39
|
+
|
40
|
+
def commits=(commits)
|
41
|
+
unless commits.is_a?(Array) && commits.length <= 2
|
42
|
+
fail Invalid, "invalid commits: #{commits.inspect}"
|
43
|
+
end
|
44
|
+
if !commits.empty? && cached
|
45
|
+
fail Invalid, 'cached and commit cannot be specified together'
|
46
|
+
end
|
47
|
+
@commits = commits
|
48
|
+
end
|
49
|
+
|
50
|
+
def config_file
|
51
|
+
if hound
|
52
|
+
HOUND_DEFAULT_CONFIG_FILE
|
53
|
+
elsif config
|
54
|
+
config
|
55
|
+
elsif File.exist?(RuboCop::ConfigLoader::DOTFILE)
|
56
|
+
RuboCop::ConfigLoader::DOTFILE
|
57
|
+
else
|
58
|
+
RuboCop::ConfigLoader::DEFAULT_FILE
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def commit_first
|
63
|
+
@commits.first
|
64
|
+
end
|
65
|
+
|
66
|
+
def commit_last
|
67
|
+
@commits.length == 1 ? false : @commits.last
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def from_hash(hash_options)
|
73
|
+
hash_options = hash_options.dup
|
74
|
+
%w(config cached hound rubocop commits).each do |key|
|
75
|
+
value = hash_options.delete(key) || hash_options.delete(key.to_sym)
|
76
|
+
public_send("#{key}=", value)
|
77
|
+
end
|
78
|
+
unless hash_options.empty?
|
79
|
+
fail Invalid, "invalid keys: #{hash_options.keys.join(' ')}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module RuboCop::Git
|
2
|
+
# copy from https://github.com/thoughtbot/hound/blob/d2f3933/app/models/patch.rb
|
3
|
+
class Patch
|
4
|
+
RANGE_INFORMATION_LINE = /^@@ .+\+(?<line_number>\d+),/
|
5
|
+
MODIFIED_LINE = /^\+(?!\+|\+)/
|
6
|
+
NOT_REMOVED_LINE = /^[^-]/
|
7
|
+
|
8
|
+
def initialize(body)
|
9
|
+
@body = body || ''
|
10
|
+
end
|
11
|
+
|
12
|
+
def additions
|
13
|
+
line_number = 0
|
14
|
+
|
15
|
+
lines.each_with_index.inject([]) do |additions, (content, patch_position)|
|
16
|
+
case content
|
17
|
+
when RANGE_INFORMATION_LINE
|
18
|
+
line_number = Regexp.last_match[:line_number].to_i
|
19
|
+
when MODIFIED_LINE
|
20
|
+
additions << Line.new(content, line_number, patch_position)
|
21
|
+
line_number += 1
|
22
|
+
when NOT_REMOVED_LINE
|
23
|
+
line_number += 1
|
24
|
+
end
|
25
|
+
|
26
|
+
additions
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def lines
|
33
|
+
@body.lines
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Git
|
3
|
+
# ref. https://github.com/thoughtbot/hound/blob/d2f3933/app/models/pull_request.rb
|
4
|
+
class PseudoPullRequest
|
5
|
+
HOUND_CONFIG_FILE = '.hound.yml'
|
6
|
+
|
7
|
+
def initialize(files, options)
|
8
|
+
@files = files
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def pull_request_files
|
13
|
+
@files.map do |file|
|
14
|
+
build_commit_file(file)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def config
|
19
|
+
return unless @options.hound
|
20
|
+
File.read(HOUND_CONFIG_FILE)
|
21
|
+
rescue Errno::ENOENT
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def build_commit_file(file)
|
28
|
+
CommitFile.new(file, head_commit)
|
29
|
+
end
|
30
|
+
|
31
|
+
def head_commit
|
32
|
+
@head_commit ||= Commit.new(@options)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Git
|
3
|
+
class PseudoResource
|
4
|
+
attr_reader :patch, :pwd, :file_relative_path
|
5
|
+
|
6
|
+
alias_method :filename, :file_relative_path
|
7
|
+
|
8
|
+
def initialize(file_relative_path, pwd = Dir.pwd)
|
9
|
+
@file_relative_path = file_relative_path
|
10
|
+
@pwd = pwd
|
11
|
+
@patch = ''
|
12
|
+
end
|
13
|
+
|
14
|
+
def absolute_path
|
15
|
+
filename
|
16
|
+
File.join(pwd, filename)
|
17
|
+
end
|
18
|
+
|
19
|
+
def status
|
20
|
+
'modified'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Git
|
5
|
+
# ref. https://github.com/thoughtbot/hound/blob/d2f3933/app/services/build_runner.rb
|
6
|
+
class Runner
|
7
|
+
def run(options)
|
8
|
+
options = Options.new(options) unless options.is_a?(Options)
|
9
|
+
|
10
|
+
@options = options
|
11
|
+
@files = DiffParser.parse(git_diff(options))
|
12
|
+
|
13
|
+
display_violations($stdout)
|
14
|
+
|
15
|
+
exit(1) if violated?
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def violations
|
21
|
+
@violations ||= style_checker.violations
|
22
|
+
end
|
23
|
+
|
24
|
+
def style_checker
|
25
|
+
StyleChecker.new(pull_request.pull_request_files,
|
26
|
+
@options.rubocop,
|
27
|
+
@options.config_file,
|
28
|
+
pull_request.config)
|
29
|
+
end
|
30
|
+
|
31
|
+
def pull_request
|
32
|
+
@pull_request ||= PseudoPullRequest.new(@files, @options)
|
33
|
+
end
|
34
|
+
|
35
|
+
def git_diff(options)
|
36
|
+
args = %w(diff --diff-filter=AMCR --find-renames --find-copies)
|
37
|
+
|
38
|
+
args << '--cached' if options.cached
|
39
|
+
args << options.commit_first.shellescape if options.commit_first
|
40
|
+
args << options.commit_last.shellescape if options.commit_last
|
41
|
+
|
42
|
+
`git #{args.join(' ')}`
|
43
|
+
end
|
44
|
+
|
45
|
+
def display_violations(io)
|
46
|
+
formatter = RuboCop::Formatter::ClangStyleFormatter.new(io)
|
47
|
+
formatter.started(nil)
|
48
|
+
|
49
|
+
violations.map do |violation|
|
50
|
+
offenses = violation.offenses
|
51
|
+
offenses = offenses.reject(&:disabled?) if offenses.first.respond_to?(:disabled?)
|
52
|
+
formatter.file_finished(
|
53
|
+
violation.filename,
|
54
|
+
offenses.compact.sort.freeze
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
formatter.finished(@files.map(&:filename).freeze)
|
59
|
+
end
|
60
|
+
|
61
|
+
def violated?
|
62
|
+
violations.any? do |violation|
|
63
|
+
offenses = violation.offenses
|
64
|
+
offenses = offenses.reject(&:disabled?) if offenses.first.respond_to?(:disabled?)
|
65
|
+
offenses && offenses.length > 0
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|