From 9a5d395d045753dd6a86932d91171e9f51cedc14 Mon Sep 17 00:00:00 2001 From: James Couball Date: Wed, 2 Jul 2025 18:11:07 -0700 Subject: [PATCH 01/19] fix: remove duplicate methods found by rubocop --- .rubocop_todo.yml | 6 ------ lib/git/base.rb | 23 ----------------------- lib/git/worktree.rb | 2 +- 3 files changed, 1 insertion(+), 30 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 46c7f6c2..12e77b58 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,12 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 2 -Lint/DuplicateMethods: - Exclude: - - 'lib/git/base.rb' - - 'lib/git/worktree.rb' - # Offense count: 1 # Configuration parameters: AllowComments, AllowEmptyLambdas. Lint/EmptyBlock: diff --git a/lib/git/base.rb b/lib/git/base.rb index 1193eae9..a6ccf782 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -182,29 +182,6 @@ def add_remote(name, url, opts = {}) Git::Remote.new(self, name) end - # Create a new git tag - # - # @example - # repo.add_tag('tag_name', object_reference) - # repo.add_tag('tag_name', object_reference, {:options => 'here'}) - # repo.add_tag('tag_name', {:options => 'here'}) - # - # @param [String] name The name of the tag to add - # @param [Hash] options Opstions to pass to `git tag`. - # See [git-tag](https://git-scm.com/docs/git-tag) for more details. - # @option options [boolean] :annotate Make an unsigned, annotated tag object - # @option options [boolean] :a An alias for the `:annotate` option - # @option options [boolean] :d Delete existing tag with the given names. - # @option options [boolean] :f Replace an existing tag with the given name (instead of failing) - # @option options [String] :message Use the given tag message - # @option options [String] :m An alias for the `:message` option - # @option options [boolean] :s Make a GPG-signed tag. - # - def add_tag(name, *options) - lib.tag(name, *options) - tag(name) - end - # changes current working directory for a block # to the git working directory # diff --git a/lib/git/worktree.rb b/lib/git/worktree.rb index c9dbea4d..a6bf95c1 100644 --- a/lib/git/worktree.rb +++ b/lib/git/worktree.rb @@ -4,7 +4,7 @@ module Git class Worktree < Path - attr_accessor :full, :dir, :gcommit + attr_accessor :full, :dir def initialize(base, dir, gcommit = nil) @full = dir From b5edab204d7c2baf073b16bdefc4d7707b80141e Mon Sep 17 00:00:00 2001 From: James Couball Date: Wed, 2 Jul 2025 18:21:35 -0700 Subject: [PATCH 02/19] fix: fix Rubocop Lint/EmptyBlock offense --- .rubocop_todo.yml | 6 ------ tests/units/test_archive.rb | 10 +++++++++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 12e77b58..15c6b639 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,12 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 1 -# Configuration parameters: AllowComments, AllowEmptyLambdas. -Lint/EmptyBlock: - Exclude: - - 'tests/units/test_archive.rb' - # Offense count: 3 # Configuration parameters: AllowedParentClasses. Lint/MissingSuper: diff --git a/tests/units/test_archive.rb b/tests/units/test_archive.rb index 53a7bf9e..0035017c 100644 --- a/tests/units/test_archive.rb +++ b/tests/units/test_archive.rb @@ -8,8 +8,16 @@ def setup @git = Git.open(@wdir) end + require 'securerandom' + require 'tmpdir' + + # Create a temporary file path without actually creating the file + # + # @return [String] the path to the temporary file + # def tempfile - Dir::Tmpname.create('test-archive') {} + random_string = SecureRandom.hex(8) + File.join(Dir.tmpdir, "test-archive-#{random_string}") end def test_archive From d00fc94bfd3787c86771e7579e9158883c102c07 Mon Sep 17 00:00:00 2001 From: James Couball Date: Wed, 2 Jul 2025 21:06:48 -0700 Subject: [PATCH 03/19] fix: fix Rubocop Lint/MissingSuper offense The Branch, Remote, and Worktree classes all inherit from Path but do not initialize it. Rather than call super, I am removing the inheritance. While this could be considered a breaking change, since the base class was never initialized, objects of these classes can not make use of the Path methods. --- .rubocop_todo.yml | 8 -------- lib/git/branch.rb | 2 +- lib/git/remote.rb | 2 +- lib/git/worktree.rb | 2 +- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 15c6b639..e490a0c7 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,14 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 3 -# Configuration parameters: AllowedParentClasses. -Lint/MissingSuper: - Exclude: - - 'lib/git/branch.rb' - - 'lib/git/remote.rb' - - 'lib/git/worktree.rb' - # Offense count: 8 Lint/StructNewOverride: Exclude: diff --git a/lib/git/branch.rb b/lib/git/branch.rb index d1e60068..b3ea860e 100644 --- a/lib/git/branch.rb +++ b/lib/git/branch.rb @@ -3,7 +3,7 @@ require 'git/path' module Git - class Branch < Path + class Branch attr_accessor :full, :remote, :name def initialize(base, name) diff --git a/lib/git/remote.rb b/lib/git/remote.rb index 178436cd..7fbff39e 100644 --- a/lib/git/remote.rb +++ b/lib/git/remote.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Git - class Remote < Path + class Remote attr_accessor :name, :url, :fetch_opts def initialize(base, name) diff --git a/lib/git/worktree.rb b/lib/git/worktree.rb index a6bf95c1..25a66975 100644 --- a/lib/git/worktree.rb +++ b/lib/git/worktree.rb @@ -3,7 +3,7 @@ require 'git/path' module Git - class Worktree < Path + class Worktree attr_accessor :full, :dir def initialize(base, dir, gcommit = nil) From 1f94cf42f81e9396ac6075bba7d9d3d400323854 Mon Sep 17 00:00:00 2001 From: James Couball Date: Thu, 3 Jul 2025 09:11:20 -0700 Subject: [PATCH 04/19] fix: fix Rubocop Lint/StructNewOverride offense --- .rubocop_todo.yml | 7 ------- tests/units/test_command_line_error.rb | 5 ++--- tests/units/test_failed_error.rb | 4 ++-- tests/units/test_signaled_error.rb | 6 ++++-- tests/units/test_timeout_error.rb | 6 ++++-- 5 files changed, 12 insertions(+), 16 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index e490a0c7..f6703b79 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,13 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 8 -Lint/StructNewOverride: - Exclude: - - 'tests/units/test_command_line_error.rb' - - 'tests/units/test_failed_error.rb' - - 'tests/units/test_signaled_error.rb' - - 'tests/units/test_timeout_error.rb' # Offense count: 2 # Configuration parameters: AllowComments, AllowNil. diff --git a/tests/units/test_command_line_error.rb b/tests/units/test_command_line_error.rb index 25c03765..22c2c21c 100644 --- a/tests/units/test_command_line_error.rb +++ b/tests/units/test_command_line_error.rb @@ -4,9 +4,8 @@ class TestCommandLineError < Test::Unit::TestCase def test_initializer - status = Struct.new(:to_s).new('pid 89784 exit 1') + status = Class.new { def to_s = 'pid 89784 exit 1' }.new result = Git::CommandLineResult.new(%w[git status], status, 'stdout', 'stderr') - error = Git::CommandLineError.new(result) assert(error.is_a?(Git::Error)) @@ -14,7 +13,7 @@ def test_initializer end def test_to_s - status = Struct.new(:to_s).new('pid 89784 exit 1') + status = Class.new { def to_s = 'pid 89784 exit 1' }.new result = Git::CommandLineResult.new(%w[git status], status, 'stdout', 'stderr') error = Git::CommandLineError.new(result) diff --git a/tests/units/test_failed_error.rb b/tests/units/test_failed_error.rb index 16a7c855..2a2cd6e9 100644 --- a/tests/units/test_failed_error.rb +++ b/tests/units/test_failed_error.rb @@ -4,7 +4,7 @@ class TestFailedError < Test::Unit::TestCase def test_initializer - status = Struct.new(:to_s).new('pid 89784 exit 1') + status = Class.new { def to_s = 'pid 89784 exit 1' }.new result = Git::CommandLineResult.new(%w[git status], status, 'stdout', 'stderr') error = Git::FailedError.new(result) @@ -13,7 +13,7 @@ def test_initializer end def test_to_s - status = Struct.new(:to_s).new('pid 89784 exit 1') + status = Class.new { def to_s = 'pid 89784 exit 1' }.new result = Git::CommandLineResult.new(%w[git status], status, 'stdout', 'stderr') error = Git::FailedError.new(result) diff --git a/tests/units/test_signaled_error.rb b/tests/units/test_signaled_error.rb index 9fb75c15..7400985a 100644 --- a/tests/units/test_signaled_error.rb +++ b/tests/units/test_signaled_error.rb @@ -4,7 +4,8 @@ class TestSignaledError < Test::Unit::TestCase def test_initializer - status = Struct.new(:to_s).new('pid 65628 SIGKILL (signal 9)') # `kill -9 $$` + # `kill -9 $$` + status = Class.new { def to_s = 'pid 65628 SIGKILL (signal 9)' }.new result = Git::CommandLineResult.new(%w[git status], status, '', 'uncaught signal') error = Git::SignaledError.new(result) @@ -13,7 +14,8 @@ def test_initializer end def test_to_s - status = Struct.new(:to_s).new('pid 65628 SIGKILL (signal 9)') # `kill -9 $$` + # `kill -9 $$` + status = Class.new { def to_s = 'pid 65628 SIGKILL (signal 9)' }.new result = Git::CommandLineResult.new(%w[git status], status, '', 'uncaught signal') error = Git::SignaledError.new(result) diff --git a/tests/units/test_timeout_error.rb b/tests/units/test_timeout_error.rb index e3e4999a..911eece8 100644 --- a/tests/units/test_timeout_error.rb +++ b/tests/units/test_timeout_error.rb @@ -4,7 +4,8 @@ class TestTimeoutError < Test::Unit::TestCase def test_initializer - status = Struct.new(:to_s).new('pid 65628 SIGKILL (signal 9)') # `kill -9 $$` + # `kill -9 $$` + status = Class.new { def to_s = 'pid 65628 SIGKILL (signal 9)' }.new result = Git::CommandLineResult.new(%w[git status], status, 'stdout', 'stderr') timeout_diration = 10 @@ -14,7 +15,8 @@ def test_initializer end def test_to_s - status = Struct.new(:to_s).new('pid 65628 SIGKILL (signal 9)') # `kill -9 $$` + # `kill -9 $$` + status = Class.new { def to_s = 'pid 65628 SIGKILL (signal 9)' }.new result = Git::CommandLineResult.new(%w[git status], status, 'stdout', 'Waiting...') timeout_duration = 10 From b3cd76c7802172bff1c95e8debad4058ae29f730 Mon Sep 17 00:00:00 2001 From: James Couball Date: Thu, 3 Jul 2025 09:16:57 -0700 Subject: [PATCH 05/19] fix: fix Rubocop Lint/SuppressedException offense --- .rubocop_todo.yml | 8 -------- lib/git/lib.rb | 7 +------ tests/units/test_each_conflict.rb | 11 +++++++++-- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index f6703b79..d3eeeed9 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,14 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. - -# Offense count: 2 -# Configuration parameters: AllowComments, AllowNil. -Lint/SuppressedException: - Exclude: - - 'lib/git/lib.rb' - - 'tests/units/test_each_conflict.rb' - # Offense count: 1 Lint/UselessConstantScoping: Exclude: diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 44919fa4..1a112994 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -707,12 +707,7 @@ def worktree_prune def list_files(ref_dir) dir = File.join(@git_dir, 'refs', ref_dir) - files = [] - begin - files = Dir.glob('**/*', base: dir).select { |f| File.file?(File.join(dir, f)) } - rescue StandardError - end - files + Dir.glob('**/*', base: dir).select { |f| File.file?(File.join(dir, f)) } end # The state and name of branch pointed to by `HEAD` diff --git a/tests/units/test_each_conflict.rb b/tests/units/test_each_conflict.rb index 6bfb37df..f6983d8a 100644 --- a/tests/units/test_each_conflict.rb +++ b/tests/units/test_each_conflict.rb @@ -5,9 +5,10 @@ class TestEachConflict < Test::Unit::TestCase def test_conflicts in_temp_repo('working') do + # Setup a repository with a conflict g = Git.open('.') - g.branch('new_branch').in_branch('test') do + g.branch('new_branch').in_branch('commit message') do new_file('example.txt', "1\n2\n3") g.add true @@ -20,11 +21,17 @@ def test_conflicts end g.merge('new_branch') + begin g.merge('new_branch2') - rescue StandardError + rescue Git::FailedError => e + assert_equal(1, e.result.status.exitstatus) + assert_match(/CONFLICT/, e.result.stdout) end + assert_equal(1, g.lib.unmerged.size) + + # Check the conflict g.each_conflict do |file, your, their| assert_equal('example.txt', file) assert_equal("1\n2\n3\n", File.read(your)) From ad27108a47df09f789efdc269995602eca63ebc2 Mon Sep 17 00:00:00 2001 From: James Couball Date: Thu, 3 Jul 2025 09:20:56 -0700 Subject: [PATCH 06/19] fix: fix Rubocop Lint/UselessConstantScoping offense --- .rubocop_todo.yml | 5 ----- lib/git/branch.rb | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index d3eeeed9..ffa0d8ac 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,11 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 1 -Lint/UselessConstantScoping: - Exclude: - - 'lib/git/branch.rb' - # Offense count: 68 # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. Metrics/AbcSize: diff --git a/lib/git/branch.rb b/lib/git/branch.rb index b3ea860e..27d5b91a 100644 --- a/lib/git/branch.rb +++ b/lib/git/branch.rb @@ -93,18 +93,6 @@ def to_s @full end - private - - def check_if_create - @base.lib.branch_new(@name) - rescue StandardError - nil - end - - def determine_current - @base.lib.branch_current == @name - end - BRANCH_NAME_REGEXP = %r{ ^ # Optional 'refs/remotes/' at the beggining to specify a remote tracking branch @@ -116,6 +104,8 @@ def determine_current $ }x + private + # Given a full branch name return an Array containing the remote and branch names. # # Removes 'remotes' from the beggining of the name (if present). @@ -143,5 +133,15 @@ def parse_name(name) branch_name = match[:branch_name] [remote, branch_name] end + + def check_if_create + @base.lib.branch_new(@name) + rescue StandardError + nil + end + + def determine_current + @base.lib.branch_current == @name + end end end From 136e7e8c5263d1b50578b6c3adfe582d0cff9251 Mon Sep 17 00:00:00 2001 From: James Couball Date: Thu, 3 Jul 2025 09:29:17 -0700 Subject: [PATCH 07/19] fix: fix Rubocop Metrics/BlockLength offense Ignore this offense for the gemspec and for tests since the DSL for both make it hard to limit the block length. --- .rubocop.yml | 6 ++++++ .rubocop_todo.yml | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 15b15e0a..76caea51 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -3,6 +3,12 @@ inherit_from: .rubocop_todo.yml inherit_gem: main_branch_shared_rubocop_config: config/rubocop.yml +Metrics/BlockLength: + Exclude: + - "tests/test_helper.rb" + - "tests/units/**/*" + - "*.gemspec" + AllCops: # Pin this project to Ruby 3.1 in case the shared config above is upgraded to 3.2 # or later. diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index ffa0d8ac..cd9f4a79 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -11,12 +11,6 @@ Metrics/AbcSize: Max: 109 -# Offense count: 8 -# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. -# AllowedMethods: refine -Metrics/BlockLength: - Max: 49 - # Offense count: 21 # Configuration parameters: CountComments, CountAsOne. Metrics/ClassLength: From 86781bc6736398e229e30dfd5aad0b7cfead50b1 Mon Sep 17 00:00:00 2001 From: James Couball Date: Thu, 3 Jul 2025 10:28:03 -0700 Subject: [PATCH 08/19] fix: fix Rubocop Metrics/ParameterLists offense --- .rubocop_todo.yml | 45 ++++++++++++--------------- lib/git/command_line.rb | 69 +++++++++++++++++++++++++++++------------ lib/git/lib.rb | 57 +++++++++++++++++++++------------- 3 files changed, 105 insertions(+), 66 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index cd9f4a79..96520d72 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,31 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 68 -# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. -Metrics/AbcSize: - Max: 109 - -# Offense count: 21 -# Configuration parameters: CountComments, CountAsOne. -Metrics/ClassLength: - Max: 898 - -# Offense count: 14 -# Configuration parameters: AllowedMethods, AllowedPatterns. -Metrics/CyclomaticComplexity: - Max: 21 - -# Offense count: 111 -# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. -Metrics/MethodLength: - Max: 51 - -# Offense count: 2 -# Configuration parameters: CountKeywordArgs, MaxOptionalParameters. -Metrics/ParameterLists: - Max: 8 - # Offense count: 12 # Configuration parameters: AllowedMethods, AllowedPatterns. Metrics/PerceivedComplexity: @@ -115,3 +90,23 @@ Style/OptionalBooleanParameter: # URISchemes: http, https Layout/LineLength: Max: 346 + +# Offense count: 68 +# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. +Metrics/AbcSize: + Max: 109 + +# Offense count: 21 +# Configuration parameters: CountComments, CountAsOne. +Metrics/ClassLength: + Max: 925 + +# Offense count: 14 +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/CyclomaticComplexity: + Max: 21 + +# Offense count: 111 +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. +Metrics/MethodLength: + Max: 51 diff --git a/lib/git/command_line.rb b/lib/git/command_line.rb index 372084cf..638db636 100644 --- a/lib/git/command_line.rb +++ b/lib/git/command_line.rb @@ -97,6 +97,10 @@ def initialize(env, binary_path, global_opts, logger) # Execute a git command, wait for it to finish, and return the result # + # Non-option the command line arguements to pass to git. If you collect + # the command line arguments in an array, make sure you splat the array + # into the parameter list. + # # NORMALIZATION # # The command output is returned as a Unicde string containing the binary output @@ -142,11 +146,9 @@ def initialize(env, binary_path, global_opts, logger) # stderr.string #=> "unknown revision or path not in the working tree.\n" # end # - # @param args [Array] the command line arguements to pass to git - # - # This array should be splatted into the parameter list. + # @param options_hash [Hash] the options to pass to the command # - # @param out [#write, nil] the object to write stdout to or nil to ignore stdout + # @option options_hash [#write, nil] :out the object to write stdout to or nil to ignore stdout # # If this is a 'StringIO' object, then `stdout_writer.string` will be returned. # @@ -154,20 +156,20 @@ def initialize(env, binary_path, global_opts, logger) # stdout to a file or some other object that responds to `#write`. The default # behavior will return the output of the command. # - # @param err [#write] the object to write stderr to or nil to ignore stderr + # @option options_hash [#write, nil] :err the object to write stderr to or nil to ignore stderr # # If this is a 'StringIO' object and `merged_output` is `true`, then # `stderr_writer.string` will be merged into the output returned by this method. # - # @param normalize [Boolean] whether to normalize the output to a valid encoding + # @option options_hash [Boolean] :normalize whether to normalize the output of stdout and stderr # - # @param chomp [Boolean] whether to chomp the output + # @option options_hash [Boolean] :chomp whether to chomp both stdout and stderr output # - # @param merge [Boolean] whether to merge stdout and stderr in the string returned + # @option options_hash [Boolean] :merge whether to merge stdout and stderr in the string returned # - # @param chdir [String] the directory to run the command in + # @option options_hash [String, nil] :chdir the directory to run the command in # - # @param timeout [Numeric, nil] the maximum seconds to wait for the command to complete + # @option options_hash [Numeric, nil] :timeout the maximum seconds to wait for the command to complete # # If timeout is zero, the timeout will not be enforced. # @@ -189,21 +191,50 @@ def initialize(env, binary_path, global_opts, logger) # # @raise [Git::TimeoutError] if the command times out # - def run(*args, normalize:, chomp:, merge:, out: nil, err: nil, chdir: nil, timeout: nil) + def run(*, **options_hash) + options_hash = RUN_ARGS.merge(options_hash) + extra_options = options_hash.keys - RUN_ARGS.keys + raise ArgumentError, "Unknown options: #{extra_options.join(', ')}" if extra_options.any? + + result = run_with_capture(*, **options_hash) + process_result(result, options_hash[:normalize], options_hash[:chomp], options_hash[:timeout]) + end + + # @return [Git::CommandLineResult] the result of running the command + # + # @api private + # + def run_with_capture(*args, **options_hash) git_cmd = build_git_cmd(args) - begin - options = { chdir: chdir || :not_set, timeout_after: timeout, raise_errors: false } + options = run_with_capture_options(**options_hash) + ProcessExecuter.run_with_capture(env, *git_cmd, **options) + rescue ProcessExecuter::ProcessIOError => e + raise Git::ProcessIOError.new(e.message), cause: e.exception.cause + end + + def run_with_capture_options(**options_hash) + chdir = options_hash[:chdir] || :not_set + timeout_after = options_hash[:timeout] + out = options_hash[:out] + err = options_hash[:err] + merge_output = options_hash[:merge] || false + + { chdir:, timeout_after:, merge_output:, raise_errors: false }.tap do |options| options[:out] = out unless out.nil? options[:err] = err unless err.nil? - options[:merge_output] = merge unless merge.nil? - - result = ProcessExecuter.run_with_capture(env, *git_cmd, **options) - rescue ProcessExecuter::ProcessIOError => e - raise Git::ProcessIOError.new(e.message), cause: e.exception.cause end - process_result(result, normalize, chomp, timeout) end + RUN_ARGS = { + normalize: false, + chomp: false, + merge: false, + out: nil, + err: nil, + chdir: nil, + timeout: nil + }.freeze + private # Build the git command line from the available sources to send to `Process.spawn` diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 1a112994..fc31d5f3 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -1522,6 +1522,16 @@ def self.warn_if_old_command(lib) true end + COMMAND_ARG_DEFAULTS = { + out: nil, + err: nil, + normalize: true, + chomp: true, + merge: false, + chdir: nil, + timeout: nil # Don't set to Git.config.timeout here since it is mutable + }.freeze + private def command_lines(cmd, *opts, chdir: nil) @@ -1569,26 +1579,20 @@ def command_line # Runs a git command and returns the output # # Additional args are passed to the command line. They should exclude the 'git' - # command itself and global options. - # - # For example, to run `git log --pretty=oneline`, you would pass `['log', - # '--pretty=oneline']` - # - # @param out [String, nil] the path to a file or an IO to write the command's - # stdout to - # - # @param err [String, nil] the path to a file or an IO to write the command's - # stdout to - # - # @param normalize [Boolean] true to normalize the output encoding - # - # @param chomp [Boolean] true to remove trailing newlines from the output - # - # @param merge [Boolean] true to merge stdout and stderr + # command itself and global options. Remember to splat the the arguments if given + # as an array. # - # @param chdir [String, nil] the directory to run the command in + # For example, to run `git log --pretty=oneline`, you would create the array + # `args = ['log', '--pretty=oneline']` and call `command(*args)`. # - # @param timeout [Numeric, nil] the maximum seconds to wait for the command to complete + # @param options_hash [Hash] the options to pass to the command + # @option options_hash [IO, String, #write, nil] :out the destination for captured stdout + # @option options_hash [IO, String, #write, nil] :err the destination for captured stderr + # @option options_hash [Boolean] :normalize true to normalize the output encoding to UTF-8 + # @option options_hash [Boolean] :chomp true to remove trailing newlines from the output + # @option options_hash [Boolean] :merge true to merge stdout and stderr into a single output + # @option options_hash [String, nil] :chdir the directory to run the command in + # @option options_hash [Numeric, nil] :timeout the maximum seconds to wait for the command to complete # # If timeout is nil, the global timeout from {Git::Config} is used. # @@ -1603,9 +1607,14 @@ def command_line # @return [String] the command's stdout (or merged stdout and stderr if `merge` # is true) # + # @raise [ArgumentError] if an unknown option is passed + # # @raise [Git::FailedError] if the command failed + # # @raise [Git::SignaledError] if the command was signaled + # # @raise [Git::TimeoutError] if the command times out + # # @raise [Git::ProcessIOError] if an exception was raised while collecting subprocess output # # The exception's `result` attribute is a {Git::CommandLineResult} which will @@ -1614,10 +1623,14 @@ def command_line # # @api private # - def command(*, out: nil, err: nil, normalize: true, chomp: true, merge: false, chdir: nil, timeout: nil) - timeout ||= Git.config.timeout - result = command_line.run(*, out: out, err: err, normalize: normalize, chomp: chomp, merge: merge, - chdir: chdir, timeout: timeout) + def command(*, **options_hash) + options_hash = COMMAND_ARG_DEFAULTS.merge(options_hash) + options_hash[:timeout] ||= Git.config.timeout + + extra_options = options_hash.keys - COMMAND_ARG_DEFAULTS.keys + raise ArgumentError, "Unknown options: #{extra_options.join(', ')}" if extra_options.any? + + result = command_line.run(*, **options_hash) result.stdout end From 17390650e4218559d125f9aa17a5b7bdc732d860 Mon Sep 17 00:00:00 2001 From: James Couball Date: Thu, 3 Jul 2025 10:59:42 -0700 Subject: [PATCH 09/19] fix: fix Rubocop Naming/AccessorMethodName offense --- .rubocop_todo.yml | 15 +++++---------- lib/git/object.rb | 11 ++++++++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 96520d72..22c67170 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,16 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 12 -# Configuration parameters: AllowedMethods, AllowedPatterns. -Metrics/PerceivedComplexity: - Max: 22 - -# Offense count: 1 -Naming/AccessorMethodName: - Exclude: - - 'lib/git/object.rb' - # Offense count: 1 # Configuration parameters: ForbiddenDelimiters. # ForbiddenDelimiters: (?i-mx:(^|\s)(EO[A-Z]{1}|END)(\s|$)) @@ -110,3 +100,8 @@ Metrics/CyclomaticComplexity: # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. Metrics/MethodLength: Max: 51 + +# Offense count: 12 +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/PerceivedComplexity: + Max: 22 diff --git a/lib/git/object.rb b/lib/git/object.rb index 0e4b1a99..d1fac5d7 100644 --- a/lib/git/object.rb +++ b/lib/git/object.rb @@ -159,7 +159,7 @@ def initialize(base, sha, init = nil) @message = nil return unless init - set_commit(init) + from_data(init) end def message @@ -211,7 +211,12 @@ def diff_parent diff(parent) end - def set_commit(data) + def set_commit(data) # rubocop:disable Naming/AccessorMethodName + Git.deprecation('Git::Object::Commit#set_commit is deprecated. Use #from_data instead.') + from_data(data) + end + + def from_data(data) @sha ||= data['sha'] @committer = Git::Author.new(data['committer']) @author = Git::Author.new(data['author']) @@ -231,7 +236,7 @@ def check_commit return if @tree data = @base.lib.cat_file_commit(@objectish) - set_commit(data) + from_data(data) end end From 9e4fc56d293ec7e7d515844cb028e2192097a864 Mon Sep 17 00:00:00 2001 From: James Couball Date: Thu, 3 Jul 2025 11:00:07 -0700 Subject: [PATCH 10/19] fix: fix Rubocop Naming/HeredocDelimiterNaming offense --- .rubocop_todo.yml | 7 ------- tests/units/test_signed_commits.rb | 4 ++-- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 22c67170..d065e0a3 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,13 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 1 -# Configuration parameters: ForbiddenDelimiters. -# ForbiddenDelimiters: (?i-mx:(^|\s)(EO[A-Z]{1}|END)(\s|$)) -Naming/HeredocDelimiterNaming: - Exclude: - - 'tests/units/test_signed_commits.rb' - # Offense count: 5 # Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods. # AllowedMethods: call diff --git a/tests/units/test_signed_commits.rb b/tests/units/test_signed_commits.rb index 99be0852..5cc28ccf 100644 --- a/tests/units/test_signed_commits.rb +++ b/tests/units/test_signed_commits.rb @@ -4,11 +4,11 @@ require 'fileutils' class TestSignedCommits < Test::Unit::TestCase - SSH_SIGNATURE_REGEXP = Regexp.new(<<~EOS.chomp, Regexp::MULTILINE) + SSH_SIGNATURE_REGEXP = Regexp.new(<<~REGEXP.chomp, Regexp::MULTILINE) -----BEGIN SSH SIGNATURE----- .* -----END SSH SIGNATURE----- - EOS + REGEXP def in_repo_with_signing_config in_temp_dir do |_path| From fd437a64d6b251d7966057bf3ff167a9f113e530 Mon Sep 17 00:00:00 2001 From: James Couball Date: Thu, 3 Jul 2025 11:02:29 -0700 Subject: [PATCH 11/19] fix: fix Rubocop Naming/PredicateMethod offense --- .rubocop_todo.yml | 9 --------- lib/git/branch.rb | 8 ++------ lib/git/lib.rb | 4 +++- tests/units/test_command_line.rb | 6 +++--- 4 files changed, 8 insertions(+), 19 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index d065e0a3..b23ea4d3 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,15 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 5 -# Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods. -# AllowedMethods: call -Naming/PredicateMethod: - Exclude: - - 'lib/git/branch.rb' - - 'lib/git/lib.rb' - - 'tests/units/test_command_line.rb' - # Offense count: 3 # Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros, UseSorbetSigs. # NamePrefix: is_, has_, have_, does_ diff --git a/lib/git/branch.rb b/lib/git/branch.rb index 27d5b91a..67cb632c 100644 --- a/lib/git/branch.rb +++ b/lib/git/branch.rb @@ -56,8 +56,8 @@ def delete @base.lib.branch_delete(@name) end - def current - determine_current + def current # rubocop:disable Naming/PredicateMethod + @base.lib.branch_current == @name end def contains?(commit) @@ -139,9 +139,5 @@ def check_if_create rescue StandardError nil end - - def determine_current - @base.lib.branch_current == @name - end end end diff --git a/lib/git/lib.rb b/lib/git/lib.rb index fc31d5f3..ae7bd1c8 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -1512,7 +1512,9 @@ def meets_required_version? (current_command_version <=> required_command_version) >= 0 end - def self.warn_if_old_command(lib) + def self.warn_if_old_command(lib) # rubocop:disable Naming/PredicateMethod + Git::Deprecation.warn('Git::Lib#warn_if_old_command is deprecated. Use meets_required_version?.') + return true if @version_checked @version_checked = true diff --git a/tests/units/test_command_line.rb b/tests/units/test_command_line.rb index 7488b57b..61c148e4 100644 --- a/tests/units/test_command_line.rb +++ b/tests/units/test_command_line.rb @@ -42,15 +42,15 @@ def err_writer nil end - def normalize + def normalize # rubocop:disable Naming/PredicateMethod false end - def chomp + def chomp # rubocop:disable Naming/PredicateMethod false end - def merge + def merge # rubocop:disable Naming/PredicateMethod false end From 8694a9ee93402d4f98b15032f156f1e6e2de26c5 Mon Sep 17 00:00:00 2001 From: James Couball Date: Thu, 3 Jul 2025 11:09:28 -0700 Subject: [PATCH 12/19] fix: fix Rubocop Naming/PredicatePrefix offense --- .rubocop_todo.yml | 11 ----------- lib/git/base.rb | 21 ++++++++++++++++++--- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index b23ea4d3..8c5ee345 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,17 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 3 -# Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros, UseSorbetSigs. -# NamePrefix: is_, has_, have_, does_ -# ForbiddenPrefixes: is_, has_, have_, does_ -# AllowedMethods: is_a? -# MethodDefinitionMacros: define_method, define_singleton_method -Naming/PredicatePrefix: - Exclude: - - 'spec/**/*' - - 'lib/git/base.rb' - # Offense count: 2 # Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns. # SupportedStyles: snake_case, normalcase, non_integer diff --git a/lib/git/base.rb b/lib/git/base.rb index a6ccf782..058cd0f3 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -253,23 +253,38 @@ def set_working(work_dir, check = true) end # returns +true+ if the branch exists locally - def is_local_branch?(branch) + def local_branch?(branch) branch_names = branches.local.map(&:name) branch_names.include?(branch) end + def is_local_branch?(branch) # rubocop:disable Naming/PredicatePrefix + Git.deprecated('Git::Base#is_local_branch? is deprecated. Use Git::Base#local_branch? instead.') + local_branch?(branch) + end + # returns +true+ if the branch exists remotely - def is_remote_branch?(branch) + def remote_branch?(branch) branch_names = branches.remote.map(&:name) branch_names.include?(branch) end + def is_remote_branch?(branch) # rubocop:disable Naming/PredicatePrefix + Git.deprecated('Git::Base#is_remote_branch? is deprecated. Use Git::Base#remote_branch? instead.') + remote_branch?(branch) + end + # returns +true+ if the branch exists - def is_branch?(branch) + def branch?(branch) branch_names = branches.map(&:name) branch_names.include?(branch) end + def is_branch?(branch) # rubocop:disable Naming/PredicatePrefix + Git.deprecated('Git::Base#is_branch? is deprecated. Use Git::Base#branch? instead.') + branch?(branch) + end + # this is a convenience method for accessing the class that wraps all the # actual 'git' forked system calls. At some point I hope to replace the Git::Lib # class with one that uses native methods or libgit C bindings From 2303af6393dc2b8be6da3c14662655f8710dfecf Mon Sep 17 00:00:00 2001 From: James Couball Date: Thu, 3 Jul 2025 11:14:07 -0700 Subject: [PATCH 13/19] fix: fix Rubocop Naming/VariableNumber offense --- .rubocop_todo.yml | 9 --------- tests/units/test_log.rb | 2 +- tests/units/test_log_execute.rb | 2 +- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 8c5ee345..1b8669b4 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,15 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 2 -# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns. -# SupportedStyles: snake_case, normalcase, non_integer -# AllowedIdentifiers: TLS1_1, TLS1_2, capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64 -Naming/VariableNumber: - Exclude: - - 'tests/units/test_log.rb' - - 'tests/units/test_log_execute.rb' - # Offense count: 1 Style/ClassVars: Exclude: diff --git a/tests/units/test_log.rb b/tests/units/test_log.rb index 781d90ff..6f71fe29 100644 --- a/tests/units/test_log.rb +++ b/tests/units/test_log.rb @@ -15,7 +15,7 @@ def test_log_max_count_default end # In these tests, note that @git.log(n) is equivalent to @git.log.max_count(n) - def test_log_max_count_20 + def test_log_max_count_twenty assert_equal(20, @git.log(20).size) assert_equal(20, @git.log.max_count(20).size) end diff --git a/tests/units/test_log_execute.rb b/tests/units/test_log_execute.rb index d6a1ef40..b55e78e4 100644 --- a/tests/units/test_log_execute.rb +++ b/tests/units/test_log_execute.rb @@ -16,7 +16,7 @@ def test_log_max_count_default end # In these tests, note that @git.log(n) is equivalent to @git.log.max_count(n) - def test_log_max_count_20 + def test_log_max_count_twenty assert_equal(20, @git.log(20).execute.size) assert_equal(20, @git.log.max_count(20).execute.size) end From 9248232b5c5b5c29700c5ade644bb048bf08cf46 Mon Sep 17 00:00:00 2001 From: James Couball Date: Thu, 3 Jul 2025 11:18:18 -0700 Subject: [PATCH 14/19] fix: fix Rubocop Style/ClassVars offense --- .rubocop_todo.yml | 5 ----- lib/git/base.rb | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 1b8669b4..1880695c 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,11 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 1 -Style/ClassVars: - Exclude: - - 'lib/git/base.rb' - # Offense count: 66 # Configuration parameters: AllowedConstants. Style/Documentation: diff --git a/lib/git/base.rb b/lib/git/base.rb index 058cd0f3..31f3b653 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -35,7 +35,7 @@ def self.repository_default_branch(repository, options = {}) # # @return [Git::Config] the current config instance. def self.config - @@config ||= Config.new + @config ||= Config.new end def self.binary_version(binary_path) From ee355a485a993d257f98e4c423bdca7e3a4040a0 Mon Sep 17 00:00:00 2001 From: James Couball Date: Thu, 3 Jul 2025 11:43:35 -0700 Subject: [PATCH 15/19] fix: fix Rubocop Style/Documentation offense --- .rubocop.yml | 6 ++++++ .rubocop_todo.yml | 5 ----- lib/git/author.rb | 1 + lib/git/branch.rb | 1 + lib/git/config.rb | 1 + lib/git/diff.rb | 1 + lib/git/diff_path_status.rb | 1 + lib/git/lib.rb | 2 ++ lib/git/object.rb | 11 +++++++++++ lib/git/path.rb | 5 +++++ lib/git/remote.rb | 1 + lib/git/stash.rb | 1 + lib/git/worktree.rb | 1 + tests/test_helper.rb | 5 +++++ 14 files changed, 37 insertions(+), 5 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 76caea51..a42b8f79 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -3,12 +3,18 @@ inherit_from: .rubocop_todo.yml inherit_gem: main_branch_shared_rubocop_config: config/rubocop.yml +# Testing and gemspec DSL results in large blocks Metrics/BlockLength: Exclude: - "tests/test_helper.rb" - "tests/units/**/*" - "*.gemspec" +# Don't force every test class to be described +Style/Documentation: + Exclude: + - "tests/units/**/*" + AllCops: # Pin this project to Ruby 3.1 in case the shared config above is upgraded to 3.2 # or later. diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 1880695c..7bafca42 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,11 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 66 -# Configuration parameters: AllowedConstants. -Style/Documentation: - Enabled: false - # Offense count: 4 # This cop supports safe autocorrection (--autocorrect). Style/IfUnlessModifier: diff --git a/lib/git/author.rb b/lib/git/author.rb index 1cc60832..ede74b34 100644 --- a/lib/git/author.rb +++ b/lib/git/author.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true module Git + # An author in a Git commit class Author attr_accessor :name, :email, :date diff --git a/lib/git/branch.rb b/lib/git/branch.rb index 67cb632c..94e81b08 100644 --- a/lib/git/branch.rb +++ b/lib/git/branch.rb @@ -3,6 +3,7 @@ require 'git/path' module Git + # Represents a Git branch class Branch attr_accessor :full, :remote, :name diff --git a/lib/git/config.rb b/lib/git/config.rb index fbd49b6c..115f0be3 100644 --- a/lib/git/config.rb +++ b/lib/git/config.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true module Git + # The global configuration for this gem class Config attr_writer :binary_path, :git_ssh, :timeout diff --git a/lib/git/diff.rb b/lib/git/diff.rb index 899802c6..036fbc29 100644 --- a/lib/git/diff.rb +++ b/lib/git/diff.rb @@ -76,6 +76,7 @@ def stats } end + # The changes for a single file within a diff class DiffFile attr_accessor :patch, :path, :mode, :src, :dst, :type diff --git a/lib/git/diff_path_status.rb b/lib/git/diff_path_status.rb index 57400c8e..726e512d 100644 --- a/lib/git/diff_path_status.rb +++ b/lib/git/diff_path_status.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true module Git + # The files and their status (e.g., added, modified, deleted) between two commits class DiffPathStatus include Enumerable diff --git a/lib/git/lib.rb b/lib/git/lib.rb index ae7bd1c8..1ca96106 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -11,6 +11,8 @@ require 'open3' module Git + # Internal git operations + # @api private class Lib # The path to the Git working copy. The default is '"./.git"'. # diff --git a/lib/git/object.rb b/lib/git/object.rb index d1fac5d7..f392cb6f 100644 --- a/lib/git/object.rb +++ b/lib/git/object.rb @@ -8,6 +8,7 @@ module Git # represents a git object class Object + # A base class for all Git objects class AbstractObject attr_accessor :objectish, :type, :mode @@ -79,6 +80,7 @@ def commit? = false def tag? = false end + # A Git blob object class Blob < AbstractObject def initialize(base, sha, mode = nil) super(base, sha) @@ -90,6 +92,7 @@ def blob? end end + # A Git tree object class Tree < AbstractObject def initialize(base, sha, mode = nil) super(base, sha) @@ -149,6 +152,7 @@ def check_tree end end + # A Git commit object class Commit < AbstractObject def initialize(base, sha, init = nil) super(base, sha) @@ -240,6 +244,13 @@ def check_commit end end + # A Git tag object + # + # This class represents a tag in Git, which can be either annotated or lightweight. + # + # Annotated tags contain additional metadata such as the tagger's name, email, and + # the date when the tag was created, along with a message. + # class Tag < AbstractObject attr_accessor :name diff --git a/lib/git/path.rb b/lib/git/path.rb index 59d77e39..08f15e90 100644 --- a/lib/git/path.rb +++ b/lib/git/path.rb @@ -1,6 +1,11 @@ # frozen_string_literal: true module Git + # A base class that represents and validates a filesystem path + # + # Use for tracking things relevant to a Git repository, such as the working + # directory or index file. + # class Path attr_accessor :path diff --git a/lib/git/remote.rb b/lib/git/remote.rb index 7fbff39e..8eed519b 100644 --- a/lib/git/remote.rb +++ b/lib/git/remote.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true module Git + # A remote in a Git repository class Remote attr_accessor :name, :url, :fetch_opts diff --git a/lib/git/stash.rb b/lib/git/stash.rb index bace354c..6a496052 100644 --- a/lib/git/stash.rb +++ b/lib/git/stash.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true module Git + # A stash in a Git repository class Stash def initialize(base, message, existing = false) @base = base diff --git a/lib/git/worktree.rb b/lib/git/worktree.rb index 25a66975..b99db5c3 100644 --- a/lib/git/worktree.rb +++ b/lib/git/worktree.rb @@ -3,6 +3,7 @@ require 'git/path' module Git + # A worktree in a Git repository class Worktree attr_accessor :full, :dir diff --git a/tests/test_helper.rb b/tests/test_helper.rb index e14d2f19..fb4ac4b3 100644 --- a/tests/test_helper.rb +++ b/tests/test_helper.rb @@ -17,6 +17,11 @@ module Test module Unit + # A base class for all test cases in this project + # + # This class provides utility methods for setting up and tearing down test + # environments, creating temporary repositories, and mocking the Git binary. + # class TestCase TEST_ROOT = File.expand_path(__dir__) TEST_FIXTURES = File.join(TEST_ROOT, 'files') From 528e3125bbf2447345187e3e75fcf46b24b400f9 Mon Sep 17 00:00:00 2001 From: James Couball Date: Thu, 3 Jul 2025 12:40:03 -0700 Subject: [PATCH 16/19] fix: fix Rubocop Style/IfUnlessModifier offense --- .rubocop_todo.yml | 7 ------- lib/git/base.rb | 4 +--- lib/git/lib.rb | 12 +++--------- 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 7bafca42..1c2c3b33 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,13 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 4 -# This cop supports safe autocorrection (--autocorrect). -Style/IfUnlessModifier: - Exclude: - - 'lib/git/base.rb' - - 'lib/git/lib.rb' - # Offense count: 2 Style/MultilineBlockChain: Exclude: diff --git a/lib/git/base.rb b/lib/git/base.rb index 31f3b653..fb64be96 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -865,9 +865,7 @@ def diff_path_status(objectish = 'HEAD', obj2 = nil) File.expand_path(options[:repository] || '.git', options[:working_directory]) end - if File.file?(repository) - repository = File.expand_path(File.read(repository)[8..].strip, options[:working_directory]) - end + repository = File.expand_path(File.read(repository)[8..].strip, options[:working_directory]) if File.file?(repository) options[:repository] = repository end diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 1ca96106..59ecb230 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -1300,9 +1300,7 @@ def tag(name, *opts) opts = opts.last.instance_of?(Hash) ? opts.last : {} - if (opts[:a] || opts[:annotate]) && !(opts[:m] || opts[:message]) - raise ArgumentError, 'Cannot create an annotated tag without a message.' - end + raise ArgumentError, 'Cannot create an annotated tag without a message.' if (opts[:a] || opts[:annotate]) && !(opts[:m] || opts[:message]) arr_opts = [] @@ -1520,9 +1518,7 @@ def self.warn_if_old_command(lib) # rubocop:disable Naming/PredicateMethod return true if @version_checked @version_checked = true - unless lib.meets_required_version? - warn "[WARNING] The git gem requires git #{lib.required_command_version.join('.')} or later, but only found #{lib.current_command_version.join('.')}. You should probably upgrade." - end + warn "[WARNING] The git gem requires git #{lib.required_command_version.join('.')} or later, but only found #{lib.current_command_version.join('.')}. You should probably upgrade." unless lib.meets_required_version? true end @@ -1668,9 +1664,7 @@ def diff_as_hash(diff_command, opts = []) def log_common_options(opts) arr_opts = [] - if opts[:count] && !opts[:count].is_a?(Integer) - raise ArgumentError, "The log count option must be an Integer but was #{opts[:count].inspect}" - end + raise ArgumentError, "The log count option must be an Integer but was #{opts[:count].inspect}" if opts[:count] && !opts[:count].is_a?(Integer) arr_opts << "--max-count=#{opts[:count]}" if opts[:count] arr_opts << '--all' if opts[:all] From 248657f2c70c956bed7c2d0257e6827c9edc7b93 Mon Sep 17 00:00:00 2001 From: James Couball Date: Thu, 3 Jul 2025 12:46:37 -0700 Subject: [PATCH 17/19] fix: fix Rubocop Style/MultilineBlockChain offense --- .rubocop_todo.yml | 5 ----- lib/git/base.rb | 13 ++++++------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 1c2c3b33..0c429b73 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,11 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 2 -Style/MultilineBlockChain: - Exclude: - - 'lib/git/base.rb' - # Offense count: 5 # Configuration parameters: AllowedMethods. # AllowedMethods: respond_to_missing? diff --git a/lib/git/base.rb b/lib/git/base.rb index fb64be96..926ffd4e 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -233,13 +233,12 @@ def repo # returns the repository size in bytes def repo_size - Dir.glob(File.join(repo.path, '**', '*'), File::FNM_DOTMATCH).reject do |f| - f.include?('..') - end.map do |f| - File.expand_path(f) - end.uniq.map do |f| - File.stat(f).size.to_i - end.reduce(:+) + all_files = Dir.glob(File.join(repo.path, '**', '*'), File::FNM_DOTMATCH) + + all_files.reject { |file| file.include?('..') } + .map { |file| File.expand_path(file) } + .uniq + .sum { |file| File.stat(file).size.to_i } end def set_index(index_file, check = true) From faade0716ceecfb8189f99e067d77a7dfeb14c11 Mon Sep 17 00:00:00 2001 From: James Couball Date: Thu, 3 Jul 2025 15:46:59 -0700 Subject: [PATCH 18/19] fix: fix Rubocop Style/OptionalBooleanParameter offense --- .rubocop_todo.yml | 10 ---------- lib/git/base.rb | 22 ++++++++++++++++------ lib/git/object.rb | 30 +++++++++++++++++++++++------- lib/git/path.rb | 9 +++++++-- lib/git/stash.rb | 9 +++++++-- 5 files changed, 53 insertions(+), 27 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 0c429b73..afa60ec8 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,16 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 5 -# Configuration parameters: AllowedMethods. -# AllowedMethods: respond_to_missing? -Style/OptionalBooleanParameter: - Exclude: - - 'lib/git/base.rb' - - 'lib/git/object.rb' - - 'lib/git/path.rb' - - 'lib/git/stash.rb' - # Offense count: 64 # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings. diff --git a/lib/git/base.rb b/lib/git/base.rb index 926ffd4e..09974985 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -241,14 +241,24 @@ def repo_size .sum { |file| File.stat(file).size.to_i } end - def set_index(index_file, check = true) + def set_index(index_file, check = nil, must_exist: nil) + Git::Deprecation.warn('The "check" argument is deprecated and will be removed in a future version. Use "must_exist:" instead.') unless check.nil? + + # default is true + must_exist = must_exist.nil? && check.nil? ? true : must_exist | check + @lib = nil - @index = Git::Index.new(index_file.to_s, check) + @index = Git::Index.new(index_file.to_s, must_exist:) end - def set_working(work_dir, check = true) + def set_working(work_dir, check = nil, must_exist: nil) + Git::Deprecation.warn('The "check" argument is deprecated and will be removed in a future version. Use "must_exist:" instead.') unless check.nil? + + # default is true + must_exist = must_exist.nil? && check.nil? ? true : must_exist | check + @lib = nil - @working_directory = Git::WorkingDirectory.new(work_dir.to_s, check) + @working_directory = Git::WorkingDirectory.new(work_dir.to_s, must_exist:) end # returns +true+ if the branch exists locally @@ -258,7 +268,7 @@ def local_branch?(branch) end def is_local_branch?(branch) # rubocop:disable Naming/PredicatePrefix - Git.deprecated('Git::Base#is_local_branch? is deprecated. Use Git::Base#local_branch? instead.') + Git.deprecation('Git::Base#is_local_branch? is deprecated. Use Git::Base#local_branch? instead.') local_branch?(branch) end @@ -759,7 +769,7 @@ def status # @return [Git::Object::Tag] a tag object def tag(tag_name) - Git::Object.new(self, tag_name, 'tag', true) + Git::Object::Tag.new(self, tag_name) end # Find as good common ancestors as possible for a merge diff --git a/lib/git/object.rb b/lib/git/object.rb index f392cb6f..6c5c235f 100644 --- a/lib/git/object.rb +++ b/lib/git/object.rb @@ -251,18 +251,36 @@ def check_commit # Annotated tags contain additional metadata such as the tagger's name, email, and # the date when the tag was created, along with a message. # + # TODO: Annotated tags are not objects + # class Tag < AbstractObject attr_accessor :name - def initialize(base, sha, name) + # @overload initialize(base, name) + # @param base [Git::Base] The Git base object + # @param name [String] The name of the tag + # + # @overload initialize(base, sha, name) + # @param base [Git::Base] The Git base object + # @param sha [String] The SHA of the tag object + # @param name [String] The name of the tag + # + def initialize(base, sha, name = nil) + if name.nil? + name = sha + sha = base.lib.tag_sha(name) + raise Git::UnexpectedResultError, "Tag '#{name}' does not exist." if sha == '' + end + super(base, sha) + @name = name @annotated = nil @loaded = false end def annotated? - @annotated ||= (@base.lib.cat_file_type(name) == 'tag') + @annotated = @annotated.nil? ? (@base.lib.cat_file_type(name) == 'tag') : @annotated end def message @@ -298,12 +316,10 @@ def check_tag # if we're calling this, we don't know what type it is yet # so this is our little factory method - def self.new(base, objectish, type = nil, is_tag = false) + def self.new(base, objectish, type = nil, is_tag = false) # rubocop:disable Style/OptionalBooleanParameter if is_tag - sha = base.lib.tag_sha(objectish) - raise Git::UnexpectedResultError, "Tag '#{objectish}' does not exist." if sha == '' - - return Git::Object::Tag.new(base, sha, objectish) + Git::Deprecation.warn('Git::Object.new with is_tag argument is deprecated. Use Git::Object::Tag.new instead.') + return Git::Object::Tag.new(base, objectish) end type ||= base.lib.cat_file_type(objectish) diff --git a/lib/git/path.rb b/lib/git/path.rb index 08f15e90..a355dfe4 100644 --- a/lib/git/path.rb +++ b/lib/git/path.rb @@ -9,10 +9,15 @@ module Git class Path attr_accessor :path - def initialize(path, check_path = true) + def initialize(path, check_path = nil, must_exist: nil) + Git::Deprecation.warn('The "check_path" argument is deprecated and will be removed in a future version. Use "must_exist:" instead.') unless check_path.nil? + + # default is true + must_exist = must_exist.nil? && check_path.nil? ? true : must_exist || check_path + path = File.expand_path(path) - raise ArgumentError, 'path does not exist', [path] if check_path && !File.exist?(path) + raise ArgumentError, 'path does not exist', [path] if must_exist && !File.exist?(path) @path = path end diff --git a/lib/git/stash.rb b/lib/git/stash.rb index 6a496052..6058a489 100644 --- a/lib/git/stash.rb +++ b/lib/git/stash.rb @@ -3,10 +3,15 @@ module Git # A stash in a Git repository class Stash - def initialize(base, message, existing = false) + def initialize(base, message, existing = nil, save: nil) + Git::Deprecation.warn('The "existing" argument is deprecated and will be removed in a future version. Use "save:" instead.') unless existing.nil? + + # default is false + save = existing.nil? && save.nil? ? false : save | existing + @base = base @message = message - save unless existing + self.save unless save end def save From 93d8cb860247afdffb894b2a894db69c81867ea0 Mon Sep 17 00:00:00 2001 From: James Couball Date: Thu, 3 Jul 2025 16:05:32 -0700 Subject: [PATCH 19/19] fix: fix Rubocop Layout/LineLength offense --- .rubocop.yml | 7 ++++ .rubocop_todo.yml | 7 ---- lib/git.rb | 3 +- lib/git/base.rb | 25 +++++++++++--- lib/git/branches.rb | 3 +- lib/git/command_line.rb | 18 +++++++--- lib/git/errors.rb | 10 ++++-- lib/git/lib.rb | 74 ++++++++++++++++++++++++++++++++--------- lib/git/log.rb | 5 ++- lib/git/path.rb | 7 +++- lib/git/stash.rb | 6 +++- lib/git/status.rb | 14 ++++++-- 12 files changed, 138 insertions(+), 41 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index a42b8f79..c85b9b91 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -3,6 +3,13 @@ inherit_from: .rubocop_todo.yml inherit_gem: main_branch_shared_rubocop_config: config/rubocop.yml +# Allow test data to have long lines +Layout/LineLength: + Exclude: + - "tests/test_helper.rb" + - "tests/units/**/*" + - "*.gemspec" + # Testing and gemspec DSL results in large blocks Metrics/BlockLength: Exclude: diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index afa60ec8..fbff4782 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,13 +6,6 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 64 -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings. -# URISchemes: http, https -Layout/LineLength: - Max: 346 - # Offense count: 68 # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. Metrics/AbcSize: diff --git a/lib/git.rb b/lib/git.rb index c0537ff1..638b77d8 100644 --- a/lib/git.rb +++ b/lib/git.rb @@ -216,7 +216,8 @@ def self.clone(repository_url, directory = nil, options = {}) # @example with the logging option # logger = Logger.new(STDOUT, level: Logger::INFO) # Git.default_branch('.', log: logger) # => 'master' - # I, [2022-04-13T16:01:33.221596 #18415] INFO -- : git '-c' 'core.quotePath=true' '-c' 'color.ui=false' ls-remote '--symref' '--' '.' 'HEAD' 2>&1 + # I, [2022-04-13T16:01:33.221596 #18415] INFO -- : git '-c' 'core.quotePath=true' + # '-c' 'color.ui=false' ls-remote '--symref' '--' '.' 'HEAD' 2>&1 # # @param repository [URI, Pathname, String] The (possibly remote) repository to get the default branch name for # diff --git a/lib/git/base.rb b/lib/git/base.rb index 09974985..b75c63f4 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -91,8 +91,10 @@ def self.root_of_worktree(working_dir) raise ArgumentError, "'#{working_dir}' does not exist" unless Dir.exist?(working_dir) begin - result, status = Open3.capture2e(Git::Base.config.binary_path, '-c', 'core.quotePath=true', '-c', - 'color.ui=false', 'rev-parse', '--show-toplevel', chdir: File.expand_path(working_dir)) + result, status = Open3.capture2e( + Git::Base.config.binary_path, '-c', 'core.quotePath=true', '-c', + 'color.ui=false', 'rev-parse', '--show-toplevel', chdir: File.expand_path(working_dir) + ) result = result.chomp rescue Errno::ENOENT raise ArgumentError, 'Failed to find the root of the worktree: git binary not found' @@ -242,7 +244,12 @@ def repo_size end def set_index(index_file, check = nil, must_exist: nil) - Git::Deprecation.warn('The "check" argument is deprecated and will be removed in a future version. Use "must_exist:" instead.') unless check.nil? + unless check.nil? + Git::Deprecation.warn( + 'The "check" argument is deprecated and will be removed in a future version. ' \ + 'Use "must_exist:" instead.' + ) + end # default is true must_exist = must_exist.nil? && check.nil? ? true : must_exist | check @@ -252,7 +259,12 @@ def set_index(index_file, check = nil, must_exist: nil) end def set_working(work_dir, check = nil, must_exist: nil) - Git::Deprecation.warn('The "check" argument is deprecated and will be removed in a future version. Use "must_exist:" instead.') unless check.nil? + unless check.nil? + Git::Deprecation.warn( + 'The "check" argument is deprecated and will be removed in a future version. ' \ + 'Use "must_exist:" instead.' + ) + end # default is true must_exist = must_exist.nil? && check.nil? ? true : must_exist | check @@ -874,7 +886,10 @@ def diff_path_status(objectish = 'HEAD', obj2 = nil) File.expand_path(options[:repository] || '.git', options[:working_directory]) end - repository = File.expand_path(File.read(repository)[8..].strip, options[:working_directory]) if File.file?(repository) + if File.file?(repository) + repository = File.expand_path(File.read(repository)[8..].strip, + options[:working_directory]) + end options[:repository] = repository end diff --git a/lib/git/branches.rb b/lib/git/branches.rb index b490074e..85dfce19 100644 --- a/lib/git/branches.rb +++ b/lib/git/branches.rb @@ -51,7 +51,8 @@ def [](branch_name) branches[branch.full] ||= branch # This is how Git (version 1.7.9.5) works. - # Lets you ignore the 'remotes' if its at the beginning of the branch full name (even if is not a real remote branch). + # Lets you ignore the 'remotes' if its at the beginning of the branch full + # name (even if is not a real remote branch). branches[branch.full.sub('remotes/', '')] ||= branch if branch.full =~ %r{^remotes/.+} end[branch_name.to_s] end diff --git a/lib/git/command_line.rb b/lib/git/command_line.rb index 638db636..befa43fe 100644 --- a/lib/git/command_line.rb +++ b/lib/git/command_line.rb @@ -252,17 +252,27 @@ def build_git_cmd(args) # Post process output, log the command and result, and raise an error if the # command failed. # - # @param result [ProcessExecuter::Command::Result] the result it is a Process::Status and include command, stdout, and stderr + # @param result [ProcessExecuter::Command::Result] the result it is a + # Process::Status and include command, stdout, and stderr + # # @param normalize [Boolean] whether to normalize the output of each writer + # # @param chomp [Boolean] whether to chomp the output of each writer - # @param timeout [Numeric, nil] the maximum seconds to wait for the command to complete # - # @return [Git::CommandLineResult] the result of the command to return to the caller + # @param timeout [Numeric, nil] the maximum seconds to wait for the command to + # complete + # + # @return [Git::CommandLineResult] the result of the command to return to the + # caller # # @raise [Git::FailedError] if the command failed + # # @raise [Git::SignaledError] if the command was signaled + # # @raise [Git::TimeoutError] if the command times out - # @raise [Git::ProcessIOError] if an exception was raised while collecting subprocess output + # + # @raise [Git::ProcessIOError] if an exception was raised while collecting + # subprocess output # # @api private # diff --git a/lib/git/errors.rb b/lib/git/errors.rb index 900f858a..02bf022d 100644 --- a/lib/git/errors.rb +++ b/lib/git/errors.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true module Git + # rubocop:disable Layout/LineLength + # Base class for all custom git module errors # # The git gem will only raise an `ArgumentError` or an error that is a subclass of @@ -60,6 +62,8 @@ module Git # class Error < StandardError; end + # rubocop:enable Layout/LineLength + # An alias for Git::Error # # Git::GitExecuteError error class is an alias for Git::Error for backwards @@ -155,7 +159,8 @@ class TimeoutError < Git::SignaledError # status = ProcessExecuter.spawn(*command, timeout: timeout_duration) # result = Git::CommandLineResult.new(command, status, 'stdout', 'err output') # error = Git::TimeoutError.new(result, timeout_duration) - # error.error_message #=> '["sleep", "10"], status: pid 70144 SIGKILL (signal 9), stderr: "err output", timed out after 1s' + # error.error_message + # #=> '["sleep", "10"], status: pid 70144 SIGKILL (signal 9), stderr: "err output", timed out after 1s' # # @param result [Git::CommandLineResult] the result of the git command including # the git command, status, stdout, and stderr @@ -171,7 +176,8 @@ def initialize(result, timeout_duration) # The human readable representation of this error # # @example - # error.error_message #=> '["sleep", "10"], status: pid 88811 SIGKILL (signal 9), stderr: "err output", timed out after 1s' + # error.error_message + # #=> '["sleep", "10"], status: pid 88811 SIGKILL (signal 9), stderr: "err output", timed out after 1s' # # @return [String] # diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 59ecb230..a77dede5 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -96,6 +96,7 @@ def init(opts = {}) # Clones a repository into a newly created directory # # @param [String] repository_url the URL of the repository to clone + # # @param [String, nil] directory the directory to clone into # # If nil, the repository is cloned into a directory with the same name as @@ -104,16 +105,28 @@ def init(opts = {}) # @param [Hash] opts the options for this command # # @option opts [Boolean] :bare (false) if true, clone as a bare repository + # # @option opts [String] :branch the branch to checkout + # # @option opts [String, Array] :config one or more configuration options to set + # # @option opts [Integer] :depth the number of commits back to pull + # # @option opts [String] :filter specify partial clone + # # @option opts [String] :mirror set up a mirror of the source repository + # # @option opts [String] :origin the name of the remote + # # @option opts [String] :path an optional prefix for the directory parameter + # # @option opts [String] :remote the name of the remote - # @option opts [Boolean] :recursive after the clone is created, initialize all submodules within, using their default settings - # @option opts [Numeric, nil] :timeout the number of seconds to wait for the command to complete + # + # @option opts [Boolean] :recursive after the clone is created, initialize all + # within, using their default settings + # + # @option opts [Numeric, nil] :timeout the number of seconds to wait for the + # command to complete # # See {Git::Lib#command} for more information about :timeout # @@ -268,14 +281,23 @@ def log_commits(opts = {}) # # @param opts [Hash] the given options # - # @option opts :count [Integer] the maximum number of commits to return (maps to max-count) + # @option opts :count [Integer] the maximum number of commits to return (maps to + # max-count) + # # @option opts :all [Boolean] + # # @option opts :cherry [Boolean] + # # @option opts :since [String] + # # @option opts :until [String] + # # @option opts :grep [String] + # # @option opts :author [String] - # @option opts :between [Array] an array of two commit-ish strings to specify a revision range + # + # @option opts :between [Array] an array of two commit-ish strings to + # specify a revision range # # Only :between or :object options can be used, not both. # @@ -283,22 +305,29 @@ def log_commits(opts = {}) # # Only :between or :object options can be used, not both. # - # @option opts :path_limiter [Array, String] only include commits that impact files from the specified paths + # @option opts :path_limiter [Array, String] only include commits that + # impact files from the specified paths + # # @option opts :skip [Integer] # # @return [Array] the log output parsed into an array of hashs for each commit # # Each hash contains the following keys: + # # * 'sha' [String] the commit sha # * 'author' [String] the author of the commit # * 'message' [String] the commit message # * 'parent' [Array] the commit shas of the parent commits # * 'tree' [String] the tree sha - # * 'author' [String] the author of the commit and timestamp of when the changes were created - # * 'committer' [String] the committer of the commit and timestamp of when the commit was applied - # * 'merges' [Boolean] if truthy, only include merge commits (aka commits with 2 or more parents) + # * 'author' [String] the author of the commit and timestamp of when the + # changes were created + # * 'committer' [String] the committer of the commit and timestamp of when the + # commit was applied + # * 'merges' [Boolean] if truthy, only include merge commits (aka commits with + # 2 or more parents) # - # @raise [ArgumentError] if the revision range (specified with :between or :object) is a string starting with a hyphen + # @raise [ArgumentError] if the revision range (specified with :between or + # :object) is a string starting with a hyphen # def full_log_commits(opts = {}) assert_args_are_not_options('between', opts[:between]&.first) @@ -321,7 +350,8 @@ def full_log_commits(opts = {}) # # @see https://git-scm.com/docs/git-rev-parse git-rev-parse # @see https://git-scm.com/docs/git-rev-parse#_specifying_revisions Valid ways to specify revisions - # @see https://git-scm.com/docs/git-rev-parse#Documentation/git-rev-parse.txt-emltrefnamegtemegemmasterememheadsmasterememrefsheadsmasterem Ref disambiguation rules + # @see https://git-scm.com/docs/git-rev-parse#Documentation/git-rev-parse.txt-emltrefnamegtemegemmasterememheadsmasterememrefsheadsmasterem + # Ref disambiguation rules # # @example # lib.rev_parse('HEAD') # => '9b9b31e704c0b85ffdd8d2af2ded85170a5af87d' @@ -492,10 +522,12 @@ def each_cat_file_header(data) # Return a hash of annotated tag data # - # Does not work with lightweight tags. List all annotated tags in your repository with the following command: + # Does not work with lightweight tags. List all annotated tags in your repository + # with the following command: # # ```sh - # git for-each-ref --format='%(refname:strip=2)' refs/tags | while read tag; do git cat-file tag $tag >/dev/null 2>&1 && echo $tag; done + # git for-each-ref --format='%(refname:strip=2)' refs/tags | \ + # while read tag; do git cat-file tag $tag >/dev/null 2>&1 && echo $tag; done # ``` # # @see https://git-scm.com/docs/git-cat-file git-cat-file @@ -520,7 +552,8 @@ def each_cat_file_header(data) # * object [String] the sha of the tag object # * type [String] # * tag [String] tag name - # * tagger [String] the name and email of the user who created the tag and the timestamp of when the tag was created + # * tagger [String] the name and email of the user who created the tag + # and the timestamp of when the tag was created # * message [String] the tag message # # @raise [ArgumentError] if object is a string starting with a hyphen @@ -1300,7 +1333,10 @@ def tag(name, *opts) opts = opts.last.instance_of?(Hash) ? opts.last : {} - raise ArgumentError, 'Cannot create an annotated tag without a message.' if (opts[:a] || opts[:annotate]) && !(opts[:m] || opts[:message]) + if (opts[:a] || opts[:annotate]) && !(opts[:m] || opts[:message]) + raise ArgumentError, + 'Cannot create an annotated tag without a message.' + end arr_opts = [] @@ -1518,7 +1554,10 @@ def self.warn_if_old_command(lib) # rubocop:disable Naming/PredicateMethod return true if @version_checked @version_checked = true - warn "[WARNING] The git gem requires git #{lib.required_command_version.join('.')} or later, but only found #{lib.current_command_version.join('.')}. You should probably upgrade." unless lib.meets_required_version? + unless lib.meets_required_version? + warn "[WARNING] The git gem requires git #{lib.required_command_version.join('.')} or later, " \ + "but only found #{lib.current_command_version.join('.')}. You should probably upgrade." + end true end @@ -1664,7 +1703,10 @@ def diff_as_hash(diff_command, opts = []) def log_common_options(opts) arr_opts = [] - raise ArgumentError, "The log count option must be an Integer but was #{opts[:count].inspect}" if opts[:count] && !opts[:count].is_a?(Integer) + if opts[:count] && !opts[:count].is_a?(Integer) + raise ArgumentError, + "The log count option must be an Integer but was #{opts[:count].inspect}" + end arr_opts << "--max-count=#{opts[:count]}" if opts[:count] arr_opts << '--all' if opts[:all] diff --git a/lib/git/log.rb b/lib/git/log.rb index 76d8b6c5..1dbfc8d8 100644 --- a/lib/git/log.rb +++ b/lib/git/log.rb @@ -264,7 +264,10 @@ def [](index) private def deprecate_method(method_name) - Git::Deprecation.warn("Calling Git::Log##{method_name} is deprecated and will be removed in a future version. Call #execute and then ##{method_name} on the result object.") + Git::Deprecation.warn( + "Calling Git::Log##{method_name} is deprecated and will be removed in a future version. " \ + "Call #execute and then ##{method_name} on the result object." + ) end def dirty_log diff --git a/lib/git/path.rb b/lib/git/path.rb index a355dfe4..32b3baa4 100644 --- a/lib/git/path.rb +++ b/lib/git/path.rb @@ -10,7 +10,12 @@ class Path attr_accessor :path def initialize(path, check_path = nil, must_exist: nil) - Git::Deprecation.warn('The "check_path" argument is deprecated and will be removed in a future version. Use "must_exist:" instead.') unless check_path.nil? + unless check_path.nil? + Git::Deprecation.warn( + 'The "check_path" argument is deprecated and ' \ + 'will be removed in a future version. Use "must_exist:" instead.' + ) + end # default is true must_exist = must_exist.nil? && check_path.nil? ? true : must_exist || check_path diff --git a/lib/git/stash.rb b/lib/git/stash.rb index 6058a489..2e9af43b 100644 --- a/lib/git/stash.rb +++ b/lib/git/stash.rb @@ -4,7 +4,11 @@ module Git # A stash in a Git repository class Stash def initialize(base, message, existing = nil, save: nil) - Git::Deprecation.warn('The "existing" argument is deprecated and will be removed in a future version. Use "save:" instead.') unless existing.nil? + unless existing.nil? + Git::Deprecation.warn( + 'The "existing" argument is deprecated and will be removed in a future version. Use "save:" instead.' + ) + end # default is false save = existing.nil? && save.nil? ? false : save | existing diff --git a/lib/git/status.rb b/lib/git/status.rb index 2e0e0b75..c18f23c2 100644 --- a/lib/git/status.rb +++ b/lib/git/status.rb @@ -250,7 +250,12 @@ def fetch_untracked def fetch_modified # Files changed between the index vs. the worktree # git diff-files - # { file => { path: file, type: 'M', mode_index: '100644', mode_repo: '100644', sha_index: '0000000', :sha_repo: '52c6c4e' } } + # { + # file => { + # path: file, type: 'M', mode_index: '100644', mode_repo: '100644', + # sha_index: '0000000', :sha_repo: '52c6c4e' + # } + # } @base.lib.diff_files.each do |path, data| @files[path] ? @files[path].merge!(data) : @files[path] = data end @@ -261,7 +266,12 @@ def fetch_added # Files changed between the repo HEAD vs. the worktree # git diff-index HEAD - # { file => { path: file, type: 'M', mode_index: '100644', mode_repo: '100644', sha_index: '0000000', :sha_repo: '52c6c4e' } } + # { + # file => { + # path: file, type: 'M', mode_index: '100644', mode_repo: '100644', + # sha_index: '0000000', :sha_repo: '52c6c4e' + # } + # } @base.lib.diff_index('HEAD').each do |path, data| @files[path] ? @files[path].merge!(data) : @files[path] = data end