rfix 1.0.15 → 1.1.0.pre.147

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 (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