cs-rubocop-git 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.travis.yml +32 -0
  4. data/Appraisals +31 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE.txt +26 -0
  7. data/README.md +46 -0
  8. data/Rakefile +15 -0
  9. data/bin/rubocop-git +5 -0
  10. data/gemfiles/0.24.gemfile +7 -0
  11. data/gemfiles/0.25.gemfile +7 -0
  12. data/gemfiles/0.26.gemfile +7 -0
  13. data/gemfiles/0.27.gemfile +7 -0
  14. data/gemfiles/0.28.gemfile +7 -0
  15. data/gemfiles/0.29.gemfile +7 -0
  16. data/gemfiles/0.30.gemfile +7 -0
  17. data/gemfiles/0.31.gemfile +7 -0
  18. data/gemfiles/0.32.gemfile +7 -0
  19. data/gemfiles/0.33.gemfile +7 -0
  20. data/gemfiles/0.34.gemfile +7 -0
  21. data/gemfiles/0.35.gemfile +7 -0
  22. data/gemfiles/0.36.gemfile +7 -0
  23. data/gemfiles/0.37.gemfile +7 -0
  24. data/gemfiles/0.38.gemfile +7 -0
  25. data/gemfiles/0.39.gemfile +7 -0
  26. data/gemfiles/0.40.gemfile +7 -0
  27. data/gemfiles/0.41.gemfile +7 -0
  28. data/gemfiles/0.42.gemfile +7 -0
  29. data/gemfiles/0.43.gemfile +7 -0
  30. data/gemfiles/0.44.gemfile +7 -0
  31. data/gemfiles/0.45.gemfile +7 -0
  32. data/gemfiles/0.46.gemfile +7 -0
  33. data/gemfiles/0.47.gemfile +7 -0
  34. data/gemfiles/0.48.gemfile +7 -0
  35. data/hound.yml +254 -0
  36. data/lib/rubocop/git.rb +19 -0
  37. data/lib/rubocop/git/cli.rb +67 -0
  38. data/lib/rubocop/git/commit.rb +22 -0
  39. data/lib/rubocop/git/commit_file.rb +55 -0
  40. data/lib/rubocop/git/diff_parser.rb +31 -0
  41. data/lib/rubocop/git/file_violation.rb +5 -0
  42. data/lib/rubocop/git/line.rb +8 -0
  43. data/lib/rubocop/git/options.rb +84 -0
  44. data/lib/rubocop/git/patch.rb +36 -0
  45. data/lib/rubocop/git/pseudo_pull_request.rb +36 -0
  46. data/lib/rubocop/git/pseudo_resource.rb +24 -0
  47. data/lib/rubocop/git/runner.rb +70 -0
  48. data/lib/rubocop/git/style_checker.rb +43 -0
  49. data/lib/rubocop/git/style_guide.rb +98 -0
  50. data/lib/rubocop/git/version.rb +5 -0
  51. data/rubocop-git.gemspec +27 -0
  52. data/test/rubocop/git/cli_test.rb +12 -0
  53. data/test/rubocop/git/options_test.rb +18 -0
  54. data/test/rubocop/git/runner_test.rb +23 -0
  55. data/test/test_helper.rb +2 -0
  56. metadata +172 -0
@@ -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,5 @@
1
+ module RuboCop::Git
2
+ # ref. https://github.com/thoughtbot/hound/blob/d2f3933/app/models/file_violation.rb
3
+ class FileViolation < Struct.new(:filename, :offenses)
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ module RuboCop::Git
2
+ # copy from https://github.com/thoughtbot/hound/blob/d2f3933/app/models/line.rb
3
+ class Line < Struct.new(:content, :line_number, :patch_position)
4
+ def ==(other_line)
5
+ content == other_line.content
6
+ end
7
+ end
8
+ 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