rubocop-git-kjanoudi 0.1.2

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 +31 -0
  4. data/Appraisals +30 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE.txt +26 -0
  7. data/README.md +41 -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/hound.yml +254 -0
  35. data/lib/rubocop/git.rb +22 -0
  36. data/lib/rubocop/git/cli.rb +71 -0
  37. data/lib/rubocop/git/commit.rb +22 -0
  38. data/lib/rubocop/git/commit_file.rb +51 -0
  39. data/lib/rubocop/git/diff_parser.rb +31 -0
  40. data/lib/rubocop/git/file_violation.rb +5 -0
  41. data/lib/rubocop/git/line.rb +8 -0
  42. data/lib/rubocop/git/options.rb +84 -0
  43. data/lib/rubocop/git/patch.rb +63 -0
  44. data/lib/rubocop/git/pseudo_pull_request.rb +36 -0
  45. data/lib/rubocop/git/pseudo_resource.rb +16 -0
  46. data/lib/rubocop/git/rubo_comment.rb +92 -0
  47. data/lib/rubocop/git/runner.rb +67 -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-kjanoudi.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 +173 -0
@@ -0,0 +1,22 @@
1
+ require 'rubocop/git/version'
2
+ require 'rubocop'
3
+ require 'tempfile'
4
+ require 'fileutils'
5
+
6
+ module RuboCop
7
+ module Git
8
+ autoload :Commit, 'rubocop/git/commit'
9
+ autoload :CommitFile, 'rubocop/git/commit_file'
10
+ autoload :DiffParser, 'rubocop/git/diff_parser'
11
+ autoload :FileViolation, 'rubocop/git/file_violation'
12
+ autoload :Line, 'rubocop/git/line'
13
+ autoload :Options, 'rubocop/git/options'
14
+ autoload :Patch, 'rubocop/git/patch'
15
+ autoload :PseudoPullRequest, 'rubocop/git/pseudo_pull_request'
16
+ autoload :PseudoResource, 'rubocop/git/pseudo_resource'
17
+ autoload :Runner, 'rubocop/git/runner'
18
+ autoload :StyleChecker, 'rubocop/git/style_checker'
19
+ autoload :StyleGuide, 'rubocop/git/style_guide'
20
+ autoload :RuboComment, 'rubocop/git/rubo_comment'
21
+ end
22
+ end
@@ -0,0 +1,71 @@
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('-a', '--auto-correct', 'Auto-correct offenses.') do
39
+ @options.rubocop[:auto_correct] = true
40
+ end
41
+
42
+ opt.on('-d', '--debug', 'Display debug info') do
43
+ @options.rubocop[:debug] = true
44
+ end
45
+
46
+ opt.on('-D', '--display-cop-names',
47
+ 'Display cop names in offense messages') do
48
+ @options.rubocop[:display_cop_names] = true
49
+ end
50
+
51
+ opt.on('--cached', 'git diff --cached') do
52
+ @options.cached = true
53
+ end
54
+
55
+ opt.on('--staged', 'synonym of --cached') do
56
+ @options.cached = true
57
+ end
58
+
59
+ opt.on('--hound', 'Hound compatibility mode') do
60
+ @options.hound = true
61
+ end
62
+
63
+ opt.on('--version', 'Display version') do
64
+ puts RuboCop::Git::VERSION
65
+ exit 0
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ 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,51 @@
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 filename
10
+ @file.filename
11
+ end
12
+
13
+ def content
14
+ @content ||= begin
15
+ unless removed?
16
+ @commit.file_content(filename)
17
+ end
18
+ end
19
+ end
20
+
21
+ def relevant_line?(line_number)
22
+ modified_lines.detect do |modified_line|
23
+ modified_line.line_number == line_number
24
+ end
25
+ end
26
+
27
+ def removed?
28
+ @file.status == 'removed'
29
+ end
30
+
31
+ def ruby?
32
+ filename.match(/.*\.rb$/)
33
+ end
34
+
35
+ def modified_lines
36
+ @modified_lines ||= patch.additions
37
+ end
38
+
39
+ def modified_line_at(line_number)
40
+ modified_lines.detect do |modified_line|
41
+ modified_line.line_number == line_number
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def patch
48
+ Patch.new(@file.patch)
49
+ end
50
+ end
51
+ 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,63 @@
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
+ PATCH_INFO_LINE = /\+([0-9,]+)/
8
+
9
+ def initialize(body)
10
+ @body = body || ''
11
+ @changes = []
12
+ end
13
+
14
+ def additions
15
+ line_number = 0
16
+
17
+ lines.each_with_index.inject(@changes) do |additions, (content, patch_position)|
18
+ case content
19
+ when RANGE_INFORMATION_LINE
20
+ line_number = Regexp.last_match[:line_number].to_i
21
+ when MODIFIED_LINE
22
+ additions << Line.new(content, line_number, patch_position)
23
+ line_number += 1
24
+ when NOT_REMOVED_LINE
25
+ line_number += 1
26
+ end
27
+
28
+ additions
29
+ end
30
+ end
31
+
32
+ # maps out additions line numbers to indicate start and end of code changes
33
+ # [[5,7], [11,11]] indicates changes from line 5, 6, 7 and then
34
+ # another one at 11
35
+ def additions_map
36
+ if @changes.empty?
37
+ self.additions
38
+ end
39
+
40
+ map = []
41
+ starting_line = ending_line = 0
42
+
43
+ @changes.each do |addition|
44
+ if starting_line == 0
45
+ starting_line = ending_line = addition.line_number
46
+ elsif addition.line_number == ( ending_line + 1 )
47
+ ending_line = addition.line_number
48
+ else # this row is not part of the last rows "group"
49
+ map.push([starting_line, ending_line])
50
+ starting_line = ending_line = addition.line_number
51
+ end
52
+ end
53
+ map.push([starting_line, ending_line])
54
+ map
55
+ end
56
+
57
+ private
58
+
59
+ def lines
60
+ @body.lines
61
+ end
62
+ end
63
+ 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,16 @@
1
+ module RuboCop
2
+ module Git
3
+ class PseudoResource
4
+ attr_reader :filename, :patch
5
+
6
+ def initialize(filename)
7
+ @filename = filename
8
+ @patch = ''
9
+ end
10
+
11
+ def status
12
+ 'modified'
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,92 @@
1
+ module RuboCop::Git
2
+ class RuboComment
3
+ RUBOCOP_DISABLE = "# rubocop:disable all\n"
4
+ RUBOCOP_ENABLE = "# rubocop:enable all\n"
5
+ WHITE_SPACE = /^\s*/
6
+
7
+ def initialize(files)
8
+ @edit_map = {}
9
+ @files = files
10
+ end
11
+
12
+ # adds rubocop enable and disabled comments to files
13
+ # making sure only edited lines are processed by rubocop
14
+ def add_comments
15
+ @files.each do |file|
16
+ patch_info = Patch.new(file.patch).additions_map
17
+ temp_file = Tempfile.new('temp')
18
+
19
+ line_count = edited_line_count = current_patch = 0
20
+ in_patch = false
21
+ edit_locations = []
22
+
23
+ begin
24
+ File.open(file.filename, "r").each_line do |line|
25
+ line_count += 1
26
+ edited_line_count += 1
27
+
28
+ if line_count == patch_info[current_patch].first
29
+ temp_file.puts generate_spaces(line) + RUBOCOP_ENABLE
30
+ in_patch = true
31
+ edit_locations.push edited_line_count
32
+ edited_line_count += 1
33
+
34
+ elsif in_patch && patch_info[current_patch].last + 1 == line_count
35
+ temp_file.puts generate_spaces(line) + RUBOCOP_DISABLE
36
+ in_patch = false
37
+ edit_locations.push edited_line_count
38
+ edited_line_count += 1
39
+ current_patch += 1 unless (current_patch + 1) >= patch_info.size
40
+
41
+ elsif line_count == 1 #adds disable at top of file
42
+ temp_file.puts generate_spaces(line) + RUBOCOP_DISABLE
43
+ edit_locations.push edited_line_count
44
+ edited_line_count += 1
45
+
46
+ end
47
+ temp_file.puts line
48
+ end
49
+
50
+ temp_file.close
51
+ FileUtils.mv(temp_file.path, file.filename)
52
+ @edit_map[file.filename] = edit_locations
53
+ ensure
54
+ temp_file.close
55
+ temp_file.unlink
56
+ end
57
+ end
58
+ end
59
+
60
+ # removes all added comments that where added from add_comments
61
+ def remove_comments
62
+ @files.each do |file|
63
+ temp_file = Tempfile.new('temp')
64
+ line_count = 0
65
+
66
+ begin
67
+ File.open(file.filename, "r").each_line do |line|
68
+ line_count += 1
69
+ temp_file.puts line unless @edit_map[file.filename].find_index line_count
70
+ end
71
+
72
+ temp_file.close
73
+ FileUtils.mv(temp_file.path, file.filename)
74
+ ensure
75
+ temp_file.close
76
+ temp_file.unlink
77
+ end
78
+ end
79
+ end
80
+
81
+ private
82
+
83
+ # generates whitespaces to make en/disable comments match line indent
84
+ # preventing rubocop errors
85
+ def generate_spaces(line)
86
+ whitespaces = ""
87
+ WHITE_SPACE.match(line).to_s.split('').size.times { whitespaces << " " }
88
+ whitespaces
89
+ end
90
+
91
+ end
92
+ end