rfix 2.0.4 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/exe/rfix +11 -90
  3. data/lib/rfix.rb +10 -9
  4. data/lib/rfix/branch/reference.rb +2 -2
  5. data/lib/rfix/branch/upstream.rb +2 -4
  6. data/lib/rfix/cli/command.rb +14 -1
  7. data/lib/rfix/cli/command/all.rb +21 -0
  8. data/lib/rfix/cli/command/base.rb +30 -19
  9. data/lib/rfix/cli/command/branch.rb +2 -0
  10. data/lib/rfix/cli/command/help.rb +2 -0
  11. data/lib/rfix/cli/command/info.rb +6 -1
  12. data/lib/rfix/cli/command/local.rb +2 -0
  13. data/lib/rfix/cli/command/origin.rb +2 -0
  14. data/lib/rfix/cli/command/setup.rb +2 -0
  15. data/lib/rfix/cli/command/status.rb +39 -0
  16. data/lib/rfix/collector.rb +69 -0
  17. data/lib/rfix/diff.rb +69 -0
  18. data/lib/rfix/extension/comment_config.rb +15 -0
  19. data/lib/rfix/extension/offense.rb +17 -14
  20. data/lib/rfix/extension/pastel.rb +7 -4
  21. data/lib/rfix/extension/progresbar.rb +15 -0
  22. data/lib/rfix/extension/strings.rb +10 -2
  23. data/lib/rfix/file.rb +5 -3
  24. data/lib/rfix/file/base.rb +21 -14
  25. data/lib/rfix/file/deleted.rb +2 -0
  26. data/lib/rfix/file/ignored.rb +2 -0
  27. data/lib/rfix/file/null.rb +17 -0
  28. data/lib/rfix/file/tracked.rb +39 -23
  29. data/lib/rfix/file/undefined.rb +17 -0
  30. data/lib/rfix/file/untracked.rb +3 -1
  31. data/lib/rfix/formatter.rb +67 -71
  32. data/lib/rfix/highlighter.rb +1 -3
  33. data/lib/rfix/rake/gemfile.rb +26 -23
  34. data/lib/rfix/repository.rb +59 -96
  35. data/lib/rfix/types.rb +24 -14
  36. data/lib/rfix/version.rb +1 -1
  37. data/rfix.gemspec +11 -3
  38. data/vendor/cli-ui/Gemfile +17 -0
  39. data/vendor/cli-ui/Gemfile.lock +60 -0
  40. data/vendor/cli-ui/LICENSE.txt +21 -0
  41. data/vendor/cli-ui/README.md +224 -0
  42. data/vendor/cli-ui/Rakefile +20 -0
  43. data/vendor/cli-ui/bin/console +14 -0
  44. data/vendor/cli-ui/cli-ui.gemspec +25 -0
  45. data/vendor/cli-ui/dev.yml +14 -0
  46. data/vendor/cli-ui/lib/cli/ui.rb +233 -0
  47. data/vendor/cli-ui/lib/cli/ui/ansi.rb +157 -0
  48. data/vendor/cli-ui/lib/cli/ui/color.rb +84 -0
  49. data/vendor/cli-ui/lib/cli/ui/formatter.rb +192 -0
  50. data/vendor/cli-ui/lib/cli/ui/frame.rb +269 -0
  51. data/vendor/cli-ui/lib/cli/ui/frame/frame_stack.rb +98 -0
  52. data/vendor/cli-ui/lib/cli/ui/frame/frame_style.rb +120 -0
  53. data/vendor/cli-ui/lib/cli/ui/frame/frame_style/box.rb +166 -0
  54. data/vendor/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +139 -0
  55. data/vendor/cli-ui/lib/cli/ui/glyph.rb +84 -0
  56. data/vendor/cli-ui/lib/cli/ui/os.rb +67 -0
  57. data/vendor/cli-ui/lib/cli/ui/printer.rb +59 -0
  58. data/vendor/cli-ui/lib/cli/ui/progress.rb +90 -0
  59. data/vendor/cli-ui/lib/cli/ui/prompt.rb +297 -0
  60. data/vendor/cli-ui/lib/cli/ui/prompt/interactive_options.rb +484 -0
  61. data/vendor/cli-ui/lib/cli/ui/prompt/options_handler.rb +29 -0
  62. data/vendor/cli-ui/lib/cli/ui/spinner.rb +66 -0
  63. data/vendor/cli-ui/lib/cli/ui/spinner/async.rb +40 -0
  64. data/vendor/cli-ui/lib/cli/ui/spinner/spin_group.rb +263 -0
  65. data/vendor/cli-ui/lib/cli/ui/stdout_router.rb +232 -0
  66. data/vendor/cli-ui/lib/cli/ui/terminal.rb +46 -0
  67. data/vendor/cli-ui/lib/cli/ui/truncater.rb +102 -0
  68. data/vendor/cli-ui/lib/cli/ui/version.rb +5 -0
  69. data/vendor/cli-ui/lib/cli/ui/widgets.rb +77 -0
  70. data/vendor/cli-ui/lib/cli/ui/widgets/base.rb +27 -0
  71. data/vendor/cli-ui/lib/cli/ui/widgets/status.rb +61 -0
  72. data/vendor/cli-ui/lib/cli/ui/wrap.rb +56 -0
  73. data/vendor/cli-ui/test/cli/ui/ansi_test.rb +32 -0
  74. data/vendor/cli-ui/test/cli/ui/cli_ui_test.rb +23 -0
  75. data/vendor/cli-ui/test/cli/ui/color_test.rb +40 -0
  76. data/vendor/cli-ui/test/cli/ui/formatter_test.rb +79 -0
  77. data/vendor/cli-ui/test/cli/ui/glyph_test.rb +68 -0
  78. data/vendor/cli-ui/test/cli/ui/printer_test.rb +103 -0
  79. data/vendor/cli-ui/test/cli/ui/progress_test.rb +46 -0
  80. data/vendor/cli-ui/test/cli/ui/prompt/options_handler_test.rb +39 -0
  81. data/vendor/cli-ui/test/cli/ui/prompt_test.rb +348 -0
  82. data/vendor/cli-ui/test/cli/ui/spinner/spin_group_test.rb +39 -0
  83. data/vendor/cli-ui/test/cli/ui/spinner_test.rb +141 -0
  84. data/vendor/cli-ui/test/cli/ui/stdout_router_test.rb +32 -0
  85. data/vendor/cli-ui/test/cli/ui/terminal_test.rb +26 -0
  86. data/vendor/cli-ui/test/cli/ui/truncater_test.rb +31 -0
  87. data/vendor/cli-ui/test/cli/ui/widgets/status_test.rb +49 -0
  88. data/vendor/cli-ui/test/cli/ui/widgets_test.rb +15 -0
  89. data/vendor/cli-ui/test/test_helper.rb +53 -0
  90. data/vendor/cli-ui/tmp/cache/bootsnap/compile-cache/d9/c036af0f3dc494 +0 -0
  91. data/vendor/cli-ui/tmp/cache/bootsnap/load-path-cache +0 -0
  92. data/vendor/dry-cli/lib/dry/cli/command.rb +2 -1
  93. data/vendor/dry-cli/tmp/cache/bootsnap/compile-cache/ff/a22a5daafbd74c +0 -0
  94. data/vendor/dry-cli/tmp/cache/bootsnap/load-path-cache +0 -0
  95. data/vendor/strings-ansi/tmp/cache/bootsnap/compile-cache/79/49cf49407b370e +0 -0
  96. data/vendor/strings-ansi/tmp/cache/bootsnap/load-path-cache +0 -0
  97. metadata +170 -9
  98. data/lib/rfix/extension/string.rb +0 -12
  99. data/lib/rfix/indicator.rb +0 -19
data/lib/rfix/diff.rb ADDED
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/struct"
4
+ require "rugged"
5
+
6
+ module Rfix
7
+ class Diff < Dry::Struct
8
+ # https://github.com/libgit2/rugged/blob/master/ext/rugged/rugged_diff.c
9
+
10
+ attribute :options, Types::Hash.default(EMPTY_HASH)
11
+ attribute :current_path, Types::Path::Relative.default(Pathname(".").freeze)
12
+ attribute :repository, Repository
13
+
14
+ delegate :index, :origin, to: :repository
15
+ delegate :each_line, to: :diff
16
+
17
+ alias lines each_line
18
+
19
+ OPTIONS = {
20
+ context_lines: 1,
21
+ ignore_whitespace: true,
22
+ ignore_whitespace_change: true,
23
+ ignore_whitespace_eol: true,
24
+ disable_pathspec_match: false,
25
+ ignore_submodules: true,
26
+ include_ignored: false,
27
+ include_unmodified: false,
28
+ skip_binary_check: true,
29
+ ignore_filemode: true,
30
+ include_untracked_content: false,
31
+ include_typechange: false
32
+ }.freeze
33
+
34
+ def deltas
35
+ diff.deltas.reject(&:deleted?)
36
+ end
37
+
38
+ def files
39
+ deltas.map(&:new_file).map do |file|
40
+ repository.path.join(file.fetch(:path))
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def diff
47
+ origin.diff(index, **extended_options).tap do |diff|
48
+ diff.merge!(index.diff(**extended_options))
49
+ diff.find_similar!(all: true, ignore_whitespace: true)
50
+ end
51
+ end
52
+
53
+ def absolute_path
54
+ repository.path.join(current_path)
55
+ end
56
+
57
+ def extended_options
58
+ unless absolute_path.exist?
59
+ raise Error, "#{current_path} path does not exist in #{repository.path}"
60
+ end
61
+
62
+ unless absolute_path.directory?
63
+ raise Error, "#{current_path} is not a directory"
64
+ end
65
+
66
+ OPTIONS.merge(**options, paths: [current_path.join("**/*").to_s])
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+
5
+ module RuboCop
6
+ class CommentConfig
7
+ concerning :Fallback, prepend: true do
8
+ def cop_enabled_at_line?(_, line)
9
+ super && repository.include?(processed_source.file_path, line)
10
+ rescue StandardError => e
11
+ abort e.full_message(highlight: true)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,14 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/string/inflections"
4
+ require "dry/core/constants"
4
5
  require "shellwords"
5
6
  require "pathname"
6
7
  require "tty-link"
7
8
  require "rainbow"
9
+ require "rubocop"
10
+ require "rubocop/cop/offense"
8
11
 
9
- module Rfix
10
- module Extension
11
- module Offense
12
+ module RuboCop
13
+ module Cop
14
+ class Offense
15
+ # concerning :Features do
12
16
  STAR = Rainbow("⭑").yellow
13
17
  CROSS = Rainbow("✗").red
14
18
  CHECK = Rainbow("✓").green
@@ -32,32 +36,30 @@ module Rfix
32
36
  message.split(": ", 2).first
33
37
  end
34
38
 
35
- def relative_path
39
+ def relative_path(root_path)
36
40
  return EMPTY_STRING unless location.respond_to?(:source_buffer)
37
41
 
38
- location.source_buffer.name.sub(Dir.pwd, EMPTY_STRING).chars.drop_while do |char|
39
- char == "/"
40
- end.join
41
- rescue ArgumentError
42
- nil
42
+ Pathname(location.source_buffer.name).relative_path_from(root_path)
43
43
  end
44
44
 
45
- def clickable_path
46
- Rainbow("#{relative_path}:#{where}").italic
45
+ def clickable_path(root_path)
46
+ Rainbow("#{relative_path(root_path)}:#{where}").italic
47
47
  end
48
48
 
49
- def clickable_plain_severity
49
+ def href
50
50
  cop_name.split("/", 2).then do |department, cop|
51
51
  return nil if [cop, department].any?(&:nil?)
52
52
 
53
53
  { type: department.parameterize, cop: cop.parameterize }
54
54
  end.then do |options|
55
55
  "https://docs.rubocop.org/rubocop/cops_%<type>s.html#%<type>s%<cop>s" % options
56
- end.then do |url|
57
- TTY::Link.link_to(cop_name, url)
58
56
  end
59
57
  end
60
58
 
59
+ def clickable_plain_severity
60
+ TTY::Link.link_to(cop_name, href)
61
+ end
62
+
61
63
  def clickable_severity
62
64
  clickable_plain_severity && Rainbow(clickable_plain_severity).italic
63
65
  end
@@ -74,6 +76,7 @@ module Rfix
74
76
  def escape(str)
75
77
  Shellwords.escape(str)
76
78
  end
79
+ # end
77
80
  end
78
81
  end
79
82
  end
@@ -1,11 +1,14 @@
1
- require "strings-ansi"
1
+ # frozen_string_literal: true
2
+
2
3
  require "pastel"
4
+ require "strings"
3
5
 
4
6
  module Pastel
5
7
  class Color
6
- def strip(*strings)
7
- modified = strings.map(&Strings::ANSI.method(:sanitize))
8
- modified.size == 1 ? modified[0] : modified
8
+ concerning :Fallback, prepend: true do
9
+ def strip(*strings)
10
+ super(*strings.map(&Strings::ANSI.method(:sanitize)))
11
+ end
9
12
  end
10
13
  end
11
14
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "tty/progressbar"
4
+
5
+ module TTY
6
+ class ProgressBar
7
+ concerning :Log, prepend: true do
8
+ def log(input)
9
+ input.each_line do |line|
10
+ super(line.strip)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,9 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "strings"
2
4
 
3
5
  module Strings
4
6
  module Wrap
5
- def self.wrap(line, *, **)
6
- line
7
+ concerning :Fallback, prepend: true do
8
+ class_methods do
9
+ def wrap(line, *, **)
10
+ super
11
+ rescue IndexError
12
+ line
13
+ end
14
+ end
7
15
  end
8
16
  end
9
17
  end
data/lib/rfix/file.rb CHANGED
@@ -2,10 +2,12 @@
2
2
 
3
3
  module Rfix
4
4
  module File
5
- Self = Deleted | Ignored | Tracked | Untracked
5
+ def self.sum
6
+ Deleted | Ignored | Tracked | Untracked
7
+ end
6
8
 
7
- def self.call(input)
8
- Self.call(input)
9
+ class << self
10
+ delegate :call, to: :sum
9
11
  end
10
12
  end
11
13
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/string/inflections"
3
4
  require "rugged"
4
5
  require "pathname"
5
6
  require "dry/struct"
@@ -35,32 +36,38 @@ module Rfix
35
36
  abstract_class self
36
37
 
37
38
  attribute :repository, Repository
38
- attribute :basename, Types::String
39
+ attribute :basename, Types::Path::Relative
39
40
 
40
- UNTRACKED = [:worktree_new, :index_new]
41
- DELETED = [:deleted, :worktree_deleted]
42
- IGNORED = [:ignored, :unmodified].freeze
41
+ UNTRACKED = %i[worktree_new index_new].freeze
42
+ DELETED = %i[deleted worktree_deleted].freeze
43
+ IGNORED = %i[ignored unmodified].freeze
43
44
  TRACKED = [:added].freeze
44
45
 
45
- def key
46
- path.to_s
46
+ delegate :delete, to: :path
47
+ delegate :to_s, to: :basename
48
+
49
+ def to_table
50
+ [basename]
47
51
  end
48
52
 
49
- # @return [Pathnane]
50
- def path
51
- repository.path.join(basename)
53
+ def key
54
+ raise NotImplementedError
52
55
  end
53
56
 
54
- def include?(*, **)
55
- raise NotImplementedError, self.class.name
57
+ def lines
58
+ EMPTY_ARRAY
56
59
  end
57
60
 
58
- def refresh!(*)
59
- # NOP
61
+ def contains?(file)
62
+ path == file
60
63
  end
61
64
 
62
65
  def inspect
63
- "<#{self.class.name}(#{status.join(', ')}:#{basename})>"
66
+ "<#{self.class.name.demodulize}(#{status.join(', ')}:#{self})>"
67
+ end
68
+
69
+ def exists?
70
+ false
64
71
  end
65
72
 
66
73
  %i[untracked? tracked? ignored? deleted?].each do |name|
@@ -3,6 +3,8 @@
3
3
  module Rfix
4
4
  module File
5
5
  class Deleted < Base
6
+ ID = "[D]".color(:red).freeze
7
+
6
8
  attribute :status, Types::Status::Deleted
7
9
 
8
10
  def deleted?
@@ -3,6 +3,8 @@
3
3
  module Rfix
4
4
  module File
5
5
  class Ignored < Base
6
+ ID = "[I]".color(:blue).freeze
7
+
6
8
  attribute :status, Types::Status::Ignored
7
9
 
8
10
  def include?(*)
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rfix
4
+ module File
5
+ module Null
6
+ def include?(*)
7
+ false
8
+ end
9
+
10
+ def exists?
11
+ false
12
+ end
13
+
14
+ module_function :include?, :exists?
15
+ end
16
+ end
17
+ end
@@ -1,41 +1,57 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "rainbow/ext/string"
4
+
3
5
  module Rfix
4
6
  module File
5
- class Tracked < Base
6
- attribute :status, Types::Status::Tracked
7
+ class Tracked < Dry::Struct
8
+ ID = "[T]".color(:lightseagreen).freeze
9
+
10
+ attribute :status, Types::Symbol
11
+ attribute :path, Types::Path::Relative
12
+ attribute :repository, Repository
13
+
14
+ delegate :include?, to: :lines
15
+
16
+ def key
17
+ absolute_path.to_s
18
+ end
7
19
 
8
- OPTIONS = {
9
- include_untracked_content: true,
10
- recurse_untracked_dirs: true,
11
- include_untracked: true,
12
- ignore_submodules: true,
13
- include_ignored: false,
14
- context_lines: 0
15
- }.freeze
20
+ def absolute_path
21
+ repository.path.join(path)
22
+ end
16
23
 
17
- def include?(line)
18
- diff.each_line.map(&:new_lineno).select(&:positive?).to_set.include?(line)
24
+ def exists?
25
+ true
19
26
  end
20
27
 
21
28
  def tracked?
22
29
  true
23
30
  end
24
31
 
25
- private
32
+ def to_s
33
+ "%s:%s" % [path, to_str_range]
34
+ end
35
+
36
+ def to_str_range
37
+ lines
38
+ .to_a
39
+ .sort
40
+ .chunk_while { |i, j| i + 1 == j }
41
+ .map { |a| a.length < 3 ? a : "#{a.first}-#{a.last}" }
42
+ .join(",")
43
+ .then { |res| res.empty? ? "-" : res }
44
+ end
26
45
 
27
- def options
28
- OPTIONS.dup.merge(paths: [basename])
46
+ def to_table
47
+ [path, to_str_range]
29
48
  end
30
49
 
31
- def diff
32
- repository.origin.diff_workdir(**options).tap do |diff|
33
- diff.find_similar!(
34
- renames_from_rewrites: true,
35
- renames: true,
36
- copies: true
37
- )
38
- end
50
+ def lines
51
+ Diff.new(repository: repository, options: {
52
+ paths: [path.to_path],
53
+ disable_pathspec_match: true,
54
+ }).lines.lazy.map(&:new_lineno).select(&:positive?)
39
55
  end
40
56
  end
41
57
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rfix
4
+ module File
5
+ class Undefined < Base
6
+ ID = "[U]".color(:orange).freeze
7
+
8
+ def include?(*)
9
+ false
10
+ end
11
+
12
+ def ignored?
13
+ true
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,10 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "dry/types"
4
+ require "rainbow/ext/string"
4
5
 
5
6
  module Rfix
6
7
  module File
7
8
  class Untracked < Base
9
+ ID = "[U]".color(:palevioletred)
10
+
8
11
  attribute :status, Types::Status::Untracked
9
12
 
10
13
  def untracked?
@@ -14,7 +17,6 @@ module Rfix
14
17
  def include?(*)
15
18
  true
16
19
  end
17
-
18
20
  end
19
21
  end
20
22
  end