rfix 1.0.15 → 1.1.0.pre.147

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -0
  3. data/.rspec +0 -1
  4. data/.rubocop.yml +46 -31
  5. data/.travis.yml +5 -12
  6. data/Gemfile.base +10 -3
  7. data/Gemfile.base.lock +172 -0
  8. data/Gemfile.lock +28 -7
  9. data/Guardfile +1 -1
  10. data/Makefile +4 -13
  11. data/Rakefile +16 -95
  12. data/ci/Gemfile.rubocop-0.80.lock +16 -1
  13. data/ci/Gemfile.rubocop-0.81.lock +16 -1
  14. data/ci/Gemfile.rubocop-0.82.lock +16 -1
  15. data/ci/Gemfile.rubocop-0.83.lock +19 -4
  16. data/ci/Gemfile.rubocop-0.84.lock +19 -4
  17. data/ci/Gemfile.rubocop-0.85.1.lock +19 -4
  18. data/ci/Gemfile.rubocop-0.85.lock +16 -1
  19. data/exe/rfix +18 -144
  20. data/lib/rfix.rb +10 -3
  21. data/lib/rfix/box.rb +112 -0
  22. data/lib/rfix/branch.rb +30 -0
  23. data/lib/rfix/branches/base.rb +29 -0
  24. data/lib/rfix/branches/head.rb +11 -0
  25. data/lib/rfix/branches/main.rb +33 -0
  26. data/lib/rfix/branches/name.rb +21 -0
  27. data/lib/rfix/branches/reference.rb +19 -0
  28. data/lib/rfix/branches/upstream.rb +11 -0
  29. data/lib/rfix/cmd.rb +9 -14
  30. data/lib/rfix/commands/all.rb +26 -0
  31. data/lib/rfix/commands/branch.rb +15 -0
  32. data/lib/rfix/commands/extensions/options.rb +8 -0
  33. data/lib/rfix/commands/help.rb +7 -0
  34. data/lib/rfix/commands/helper/args.rb +137 -0
  35. data/lib/rfix/commands/helper/help.rb +6 -0
  36. data/lib/rfix/commands/helper/loader.rb +6 -0
  37. data/lib/rfix/commands/helper/option.rb +0 -0
  38. data/lib/rfix/commands/helper/params.rb +0 -0
  39. data/lib/rfix/commands/helper/rubocop.rb +17 -0
  40. data/lib/rfix/commands/info.rb +30 -0
  41. data/lib/rfix/commands/lint.rb +23 -0
  42. data/lib/rfix/commands/local.rb +12 -0
  43. data/lib/rfix/commands/origin.rb +19 -0
  44. data/lib/rfix/commands/setup.rb +29 -0
  45. data/lib/rfix/commands/welcome.rb +24 -0
  46. data/lib/rfix/deleted.rb +13 -0
  47. data/lib/rfix/error.rb +2 -0
  48. data/lib/rfix/extensions/extensions.rb +4 -26
  49. data/lib/rfix/extensions/offense.rb +2 -1
  50. data/lib/rfix/extensions/string.rb +8 -0
  51. data/lib/rfix/file.rb +46 -0
  52. data/lib/rfix/file_cache.rb +59 -0
  53. data/lib/rfix/formatter.rb +37 -10
  54. data/lib/rfix/git_helper.rb +13 -1
  55. data/lib/rfix/log.rb +104 -7
  56. data/lib/rfix/no_file.rb +13 -0
  57. data/lib/rfix/rake/paths.rb +50 -0
  58. data/lib/rfix/rake/support.rb +75 -0
  59. data/lib/rfix/repository.rb +201 -0
  60. data/lib/rfix/rfix.rb +7 -198
  61. data/lib/rfix/tracked.rb +76 -0
  62. data/lib/rfix/tracked_file.rb +1 -1
  63. data/lib/rfix/untracked.rb +13 -0
  64. data/lib/rfix/version.rb +1 -1
  65. data/path.rb +7 -0
  66. data/rfix.gemspec +6 -2
  67. data/rugged.rb +206 -0
  68. data/tasks/bump.rake +11 -0
  69. data/tasks/bundle.rake +17 -0
  70. data/tasks/complex.rake +54 -0
  71. data/tasks/simple.rake +58 -0
  72. data/tasks/travis.rake +74 -0
  73. data/tasks/vendor.rake +34 -0
  74. metadata +136 -13
  75. data/file.rb +0 -1
  76. data/lib/rfix/gem_helper.rb +0 -12
  77. data/lib/rfix/git_file.rb +0 -36
  78. data/lib/rfix/rake_helper.rb +0 -56
  79. data/lib/rfix/untracked_file.rb +0 -13
@@ -0,0 +1,13 @@
1
+ class NoFile < Struct.new(:path)
2
+ def include?(_line)
3
+ return true
4
+ end
5
+
6
+ def divide
7
+ Set.new
8
+ end
9
+
10
+ def empty?
11
+ false
12
+ end
13
+ end
@@ -0,0 +1,50 @@
1
+ module Travis
2
+ SETUP = "travis:setup".freeze
3
+ INSTALL = "travis:install".freeze
4
+ TASKS = "travis:tasks:all".freeze
5
+ GIT = "travis:git:config".freeze
6
+ end
7
+
8
+ module Bundle
9
+ INSTALL = "bundle:install".freeze
10
+ ADD = "bundle:git:add".freeze
11
+ CONFIG = File.join(__dir__, "../../../.rubocop.yml")
12
+ TAG = "rally-point".freeze
13
+ REBUILD = "bundle:rebuild".freeze
14
+ BUILD = "bundle:build".freeze
15
+ ROOT = File.expand_path(File.join(__dir__, "../../.."))
16
+ DIR = File.join(ROOT, "spec/fixtures")
17
+ TMP = File.join(ROOT, "tmp")
18
+
19
+ module Simple
20
+ FILE = File.join(DIR, "simple.bundle")
21
+ REPO = File.join(TMP, "simple")
22
+ REBUILD = "bundle:simple:rebuild".freeze
23
+ BUILD = "bundle:simple:build".freeze
24
+ FLUSH = "bundle:simple:flush".freeze
25
+ TEST = "bundle:simple:test".freeze
26
+ TAG = Bundle::TAG
27
+ end
28
+
29
+ module Complex
30
+ FILE = File.join(DIR, "complex.bundle")
31
+ REPO = File.join(TMP, "complex")
32
+ GITHUB = "https://github.com/oleander/git-fame-rb".freeze
33
+ REBUILD = "bundle:complex:rebuild".freeze
34
+ BUILD = "bundle:complex:build".freeze
35
+ FLUSH = "bundle:complex:flush".freeze
36
+ TEST = "bundle:complex:test".freeze
37
+ TAG = Bundle::TAG
38
+ end
39
+ end
40
+
41
+ module Vendor
42
+ ROOT = File.expand_path(File.join(__dir__, "../../.."))
43
+ DIR = File.join(ROOT, "vendor/shopify")
44
+ REPO = File.join(DIR, "cli-ui")
45
+ GITHUB = "https://github.com/shopify/cli-ui".freeze
46
+ START = "ef976d".freeze
47
+ BUILD = "vendor:shopify:build".freeze
48
+ REBUILD = "vendor:shopify:rebuild".freeze
49
+ TEST = "vendor:shopify:test".freeze
50
+ end
@@ -0,0 +1,75 @@
1
+ require "colorize"
2
+ require "fileutils"
3
+ require "shellwords"
4
+
5
+ module Rfix::Support
6
+ include FileUtils
7
+
8
+ alias _sh sh
9
+ alias _cd cd
10
+ alias _rm_rf rm_rf
11
+ alias _rm_f rm_f
12
+ alias _mkdir_p mkdir_p
13
+ alias _chdir chdir
14
+
15
+ def gemfiles
16
+ Dir["Gemfile*", "ci/Gemfile*"]
17
+ end
18
+
19
+ def say(msg)
20
+ $stderr.puts "#{'==>'.blue} #{to_relative(msg).italic}"
21
+ end
22
+
23
+ def sh(*args)
24
+ args = args.map(&:shellsplit).flatten
25
+ colorize args
26
+ _sh(*args)
27
+ end
28
+
29
+ def chdir(*args, &block)
30
+ colorize :cd, args
31
+ _chdir(*args, &block)
32
+ end
33
+
34
+ def rm_rf(*args)
35
+ colorize :rm, args
36
+ _rm_rf(*args)
37
+ end
38
+
39
+ def rm_f(*args)
40
+ colorize :rm, args
41
+ _rm_f(*args)
42
+ end
43
+
44
+ def cd(*args, &block)
45
+ colorize :cd, args
46
+ _cd(*args, &block)
47
+ end
48
+
49
+ def mkdir_p(*args)
50
+ colorize :mkdir, args
51
+ _mkdir_p(*args)
52
+ end
53
+
54
+ def clone_and_run(&block)
55
+ Dir.mktmpdir do |repo|
56
+ sh "git clone", Bundle::Complex::FILE, repo, "--branch", "master"
57
+ Dir.chdir(repo) { block.call(repo) }
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def current_path
64
+ File.join(Dir.getwd, "/")
65
+ end
66
+
67
+ def to_relative(path)
68
+ path.to_s.gsub(current_path, "")
69
+ end
70
+
71
+ def colorize(*args)
72
+ head, *tail = args.flatten.map(&method(:to_relative))
73
+ say [head.yellow, tail.join(" ").italic].join(" ")
74
+ end
75
+ end
@@ -0,0 +1,201 @@
1
+ require "rugged"
2
+ require "rfix/file"
3
+ require "rfix/file_cache"
4
+ require "rfix/untracked"
5
+ require "rfix/tracked"
6
+
7
+ class Rfix::Repository
8
+ include Rfix::Log
9
+ attr_reader :files, :repo
10
+
11
+ def initialize(root_path:, load_untracked: false, reference: Rfix::Branch::HEAD, paths: [])
12
+ unless File.exist?(root_path)
13
+ raise Rfix::Error, "#{root_path} does not exist"
14
+ end
15
+
16
+ unless Pathname.new(root_path).absolute?
17
+ raise Rfix::Error, "#{root_path} is not absolute"
18
+ end
19
+
20
+ unless reference.is_a?(Rfix::Branch::Base)
21
+ raise Rfix::Error.new("Need Branch::Base, got {{error:#{reference.class}}}")
22
+ end
23
+
24
+ @files = FileCache.new(root_path)
25
+ @repo = Rugged::Repository.new(root_path)
26
+ @paths = paths
27
+ @reference = reference
28
+ @load_untracked = load_untracked
29
+
30
+ load!
31
+ end
32
+
33
+ def load_untracked?
34
+ @load_untracked
35
+ end
36
+
37
+ def load_tracked?
38
+ !! @reference
39
+ end
40
+
41
+ def reference
42
+ @reference
43
+ end
44
+
45
+ def refresh!(path)
46
+ @files.get(path).refresh!
47
+ end
48
+
49
+ def include?(path, line)
50
+ if file = @files.get(path)
51
+ return file.include?(line)
52
+ end
53
+
54
+ return false
55
+ end
56
+
57
+ def set_root(_path_path)
58
+ using_path(root_path)
59
+ end
60
+
61
+ def paths
62
+ files.pluck(&:absolute_path)
63
+ end
64
+
65
+ def current_branch
66
+ repo.head.name
67
+ end
68
+
69
+ def has_reference?(reference)
70
+ repo.rev_parse(reference)
71
+ rescue Rugged::ReferenceError
72
+ return false
73
+ end
74
+
75
+ def local_branches
76
+ repo.branches.each_name(:local).to_a
77
+ end
78
+
79
+ def git_path
80
+ repo.workdir
81
+ end
82
+
83
+ def head
84
+ @head ||= repo.rev_parse("HEAD")
85
+ end
86
+
87
+ def upstream
88
+ @upstream ||= reference.resolve(with: repo)
89
+ end
90
+
91
+ private
92
+
93
+ def load_tracked!
94
+ params = {
95
+ # ignore_whitespace_change: true,
96
+ include_untracked_content: true,
97
+ recurse_untracked_dirs: true,
98
+ # ignore_whitespace_eol: true,
99
+ include_unmodified: false,
100
+ include_untracked: true,
101
+ ignore_submodules: true,
102
+ # ignore_whitespace: true,
103
+ include_ignored: false,
104
+ context_lines: 0
105
+ }
106
+
107
+ unless @paths.empty?
108
+ say_debug("Use @paths #{@paths.join(", ")}")
109
+ params[:disable_pathspec_match] = false
110
+ params[:paths] = @paths
111
+ end
112
+
113
+ say_debug("Run diff on #{reference}")
114
+ upstream.diff(head, **params).tap do |diff|
115
+ diff.find_similar!(
116
+ renames_from_rewrites: true,
117
+ renames: true,
118
+ copies: true
119
+ )
120
+ end.each_delta do |delta|
121
+ path = delta.new_file.fetch(:path)
122
+ say_debug("Found #{path} while diff")
123
+ try_store(path, [delta.status])
124
+ end
125
+ rescue Rugged::ReferenceError
126
+ abort_box($ERROR_INFO.to_s) do
127
+ prt "Reference {{error:#{reference}}} cannot be found in repository"
128
+ end
129
+ rescue Rugged::ConfigError
130
+ abort_box($ERROR_INFO.to_s) do
131
+ prt "No upstream branch set for {{error:#{current_branch}}}"
132
+ end
133
+ rescue TypeError
134
+ abort_box($ERROR_INFO.to_s) do
135
+ prt "Reference {{error:#{reference}}} is not pointing to a tree or commit"
136
+ end
137
+ end
138
+
139
+ def load!
140
+ load_tracked!
141
+ load_untracked!
142
+ end
143
+
144
+ # https://github.com/libgit2/rugged/blob/35102c0ca10ab87c4c4ffe2e25221d26993c069c/test/status_test.rb
145
+ # - +:index_new+: the file is new in the index
146
+ # - +:index_modified+: the file has been modified in the index
147
+ # - +:index_deleted+: the file has been deleted from the index
148
+ # - +:worktree_new+: the file is new in the working directory
149
+ # - +:worktree_modified+: the file has been modified in the working directory
150
+ # - +:worktree_deleted+: the file has been deleted from the working directory
151
+
152
+ MODIFIED = [:modified, :worktree_modified, :index_modified].freeze
153
+ IGNORED = [:ignored].freeze
154
+ STAGED = [:added, :index_new].freeze
155
+ UNTRACKED = [:worktree_new, :untracked].freeze
156
+ COPIED = [:copied].freeze
157
+ DELETED = [:deleted, :worktree_deleted, :index_deleted].freeze
158
+ RENAMED = [:renamed].freeze
159
+
160
+ SKIP = [*DELETED, *RENAMED, *COPIED, *IGNORED].freeze
161
+ ACCEPT = [*MODIFIED].freeze
162
+
163
+ def load_untracked!
164
+ repo.status do |path, status|
165
+ try_store(path, status)
166
+ end
167
+ end
168
+
169
+ def store(file)
170
+ say_debug("Trying to add #{file.absolute_path}")
171
+ if File.exist?(file.absolute_path)
172
+ @files.add(file)
173
+ else
174
+ say_debug "#{file} does not exist"
175
+ end
176
+ end
177
+
178
+ def try_store(path, status)
179
+ if SKIP.any?(&status.method(:include?))
180
+ return say_debug("Ignored {{warning:#{status.join(', ')}}} #{path}")
181
+ end
182
+
183
+ if STAGED.any?(&status.method(:include?))
184
+ return store(Rfix::Untracked.new(path, repo, nil))
185
+ end
186
+
187
+ if UNTRACKED.any?(&status.method(:include?))
188
+ unless load_untracked?
189
+ return say_debug("Ignore #{path} as untracked files are ignored: #{status}")
190
+ end
191
+
192
+ return store(Rfix::Untracked.new(path, repo, nil))
193
+ end
194
+
195
+ if ACCEPT.any?(&status.method(:include?))
196
+ return store(Rfix::Tracked.new(path, repo, reference))
197
+ end
198
+
199
+ say_debug "Status not found {{error:#{status.join(', ')}}} for {{italic:#{path}}}"
200
+ end
201
+ end
@@ -1,111 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # rubocop:disable Layout/LineLength
4
-
5
3
  require "rubocop"
6
- require "optparse"
7
- require "rbconfig"
8
- require "rfix/git_file"
9
- require "rfix/git_helper"
10
4
  require "rfix/log"
11
- require "rfix/tracked_file"
12
- require "rfix/untracked_file"
13
5
 
14
6
  module Rfix
15
- include GitHelper
16
7
  include Log
8
+ attr_accessor :repo
9
+ attr_accessor :test
17
10
 
18
- def indent
19
- " " * 2
20
- end
21
-
22
- def thanks
23
- tx = []
24
- tx << "\n{{v}} Thank you for installing {{green:rfix v#{Rfix::VERSION}}}!\n"
25
- tx << "{{i}} Run {{command:rfix}} for avalible commands or any of the following to get started:"
26
- tx << ""
27
- # tx << "Here are a few examples that might be useful:"
28
- tx << "#{indent}{{command:$ rfix local}} {{italic:# Auto-fixes commits not yet pushed to upstream}}"
29
- tx << "#{indent}{{command:$ rfix origin}} {{italic:# Auto-fixes commits between HEAD and origin branch}}"
30
- tx << "#{indent}{{command:$ rfix lint}} {{italic:# Lints commits and untracked files not yet pushed to upstream}}"
31
- tx << ""
32
- tx << "{{*}} {{bold:ProTip:}} Append {{command:--dry}} to run {{command:rfix}} in read-only mode"
33
- tx << ""
34
- tx << "{{i}} {{bold:Issues}} {{italic:https://github.com/oleander/rfix-rb/issues}}"
35
- tx << "{{i}} {{bold:Readme}} {{italic:https://github.com/oleander/rfix-rb/blob/master/README.md}}"
36
- tx << "{{i}} {{bold:Travis}} {{italic:https://travis-ci.org/github/oleander/rfix-rb}}"
37
- tx << ""
38
- tx << "{{italic:~ Linus}}\n\n"
39
- CLI::UI.fmt(tx.join("\n"), enable_color: true)
40
- end
41
-
42
- def help
43
- cmds = [""]
44
- cmds << "#{indent}{{command:$ rfix [cmd] [options]}} # {{italic:--dry --help --list-files --limit-files --config --untracked}}"
45
- cmds << "#{indent}{{command:$ rfix branch <branch>}} # {{italic:Fix changes made between HEAD and <branch>}}"
46
- cmds << "#{indent}{{command:$ rfix origin}} # {{italic:Fix changes made between HEAD and origin branch}}"
47
- cmds << "#{indent}{{command:$ rfix local}} # {{italic:Fix changes not yet pushed to upstream branch}}"
48
- cmds << "#{indent}{{command:$ rfix info}} # {{italic:Display runtime dependencies and their versions}}"
49
- cmds << "#{indent}{{command:$ rfix all}} # {{italic:Fix all files in this repository}} {{warning:(not recommended)}}"
50
- cmds << "#{indent}{{command:$ rfix lint}} # {{italic:Shortcut for 'local --dry --untracked'}}"
51
- CLI::UI.fmt(cmds.join("\n"), enable_color: true)
52
- end
53
-
54
- def current_branch
55
- git("rev-parse", "--abbrev-ref", "HEAD").first
56
- end
57
-
58
- def debug?
59
- @debug
60
- end
61
-
62
- def debug!
63
- @debug = true
64
- @config[:debug] = true
65
- end
66
-
67
- def number_of_commits_since
68
- cmd("git rev-list master..HEAD | wc -l").first
69
- end
70
-
71
- def config
72
- @config
73
- end
74
-
75
- def no_auto_correct!
76
- @config[:auto_correct] = false
77
- end
78
-
79
- def auto_correct!
80
- @config[:auto_correct] = true
81
- end
82
-
83
- def load_config
84
- yield @store
85
- rescue RuboCop::Error => e
86
- say_abort "[Config:RuboCop] #{e}"
87
- rescue TypeError => e
88
- say_abort "[Config:Type] #{e}"
89
- rescue Psych::SyntaxError => e
90
- say_abort "[Config:Syntax] #{e}"
91
- end
92
-
93
- def lint_mode!
94
- no_auto_correct!
95
- load_untracked!
96
- end
97
-
98
- def git_version
99
- cmd("git --version").last.split(/\s+/, 3).last
100
- end
101
-
102
- def ruby_version
103
- RbConfig::CONFIG["ruby_version"] || "<unknown>"
104
- end
105
-
106
- def current_os
107
- RbConfig::CONFIG["host_os"] || "<unknown>"
108
- end
11
+ alias test? test
109
12
 
110
13
  def global_enable!
111
14
  @global_enable = true
@@ -115,110 +18,16 @@ module Rfix
115
18
  @global_enable
116
19
  end
117
20
 
118
- def store
119
- @store
120
- end
121
-
122
- def clear_cache!
123
- RuboCop::ResultCache.cleanup(@store, true)
124
- end
125
-
126
- def init!
127
- @files ||= {}
128
- @global_enable = false
129
- @debug = false
130
- @config = {
131
- force_exclusion: true,
132
- formatters: ["Rfix::Formatter"]
133
- }
134
-
135
- @store = RuboCop::ConfigStore.new
136
- auto_correct!
137
- end
138
-
139
- def files
140
- @files.values
141
- end
142
-
143
- def spin
144
- @spin ||= CLI::UI::SpinGroup.new
145
- end
146
-
147
- def paths
148
- @files.keys
149
- end
150
-
151
- def root_dir
152
- @root_dir ||= git("rev-parse", "--show-toplevel").first
153
- end
154
-
155
21
  def refresh!(source)
156
- @files[source.file_path]&.refresh!
157
- end
158
-
159
- def enabled?(path, line)
160
22
  return true if global_enable?
161
23
 
162
- @files[path]&.include?(line)
163
- end
164
-
165
- def to_relative(path:)
166
- Pathname.new(path).relative_path_from(Pathname.new(root_dir)).to_s
167
- rescue ArgumentError
168
- path
169
- end
170
-
171
- def load_untracked!
172
- cached(list_untrack_files.map do |path|
173
- UntrackedFile.new(path, nil, root_dir)
174
- end.select(&:file?).to_set)
175
- end
176
-
177
- def load_tracked!(reference)
178
- cached(git("log", "--name-only", "--pretty=format:", *params, "#{reference}...HEAD").map do |path|
179
- TrackedFile.new(path, reference, root_dir)
180
- end.select(&:file?).to_set)
181
- end
182
-
183
- def has_branch?(name)
184
- cmd_succeeded?("git", "cat-file", "-t", name)
185
- end
186
-
187
- # Ref since last push
188
- def ref_since_push
189
- git("rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}") do
190
- [ref_since_origin]
191
- end.first
192
- end
193
-
194
- # Original branch, usually master
195
- def ref_since_origin
196
- git("show-branch", "--merge-base").first
24
+ repo.refresh!(source.file_path)
197
25
  end
198
26
 
199
- private
200
-
201
- def old?
202
- # For version 0.80.x .. 0.83.x:
203
- # Otherwise it will exit with status code = 1
204
- (0.80..0.83).include?(RuboCop::Version::STRING.to_f)
205
- end
206
-
207
- def get_file(path, &block)
208
- if file = @files[path]
209
- block.call(file)
210
- end
211
- end
212
-
213
- def list_untrack_files
214
- git("ls-files", "--exclude-standard", "--others")
215
- end
27
+ def enabled?(path, line)
28
+ return true if global_enable?
216
29
 
217
- def cached(files)
218
- @files ||= {}
219
- files.each do |file|
220
- @files[file.path] = file
221
- end
30
+ repo.include?(path, line)
222
31
  end
223
32
  end
224
33