Skip to content

Commit

Permalink
Support the --all option for git fetch (#583)
Browse files Browse the repository at this point in the history
Signed-off-by: James Couball <jcouball@yahoo.com>
  • Loading branch information
jcouball committed May 21, 2022
1 parent 1b13ec1 commit 6f2b3fd
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 6 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -288,6 +288,7 @@ g.remote(name).merge(branch)
g.fetch
g.fetch(g.remotes.first)
g.fetch('origin', {:ref => 'some/ref/head'} )
g.fetch(all: true, force: true, depth: 2)

g.pull
g.pull(Git::Repo, Git::Branch) # fetch and a merge
Expand Down
6 changes: 5 additions & 1 deletion lib/git/base.rb
Expand Up @@ -336,7 +336,11 @@ def checkout_file(version, file)

# fetches changes from a remote branch - this does not modify the working directory,
# it just gets the changes from the remote if there are any
def fetch(remote = 'origin', opts={})
def fetch(remote = 'origin', opts = {})
if remote.is_a?(Hash)
opts = remote
remote = nil
end
self.lib.fetch(remote, opts)
end

Expand Down
5 changes: 3 additions & 2 deletions lib/git/lib.rb
Expand Up @@ -877,14 +877,15 @@ def tag(name, *opts)

def fetch(remote, opts)
arr_opts = []
arr_opts << '--all' if opts[:all]
arr_opts << '--tags' if opts[:t] || opts[:tags]
arr_opts << '--prune' if opts[:p] || opts[:prune]
arr_opts << '--prune-tags' if opts[:P] || opts[:'prune-tags']
arr_opts << '--force' if opts[:f] || opts[:force]
arr_opts << '--unshallow' if opts[:unshallow]
arr_opts << '--depth' << opts[:depth] if opts[:depth]
arr_opts << '--'
arr_opts << remote
arr_opts << '--' if remote || opts[:ref]
arr_opts << remote if remote
arr_opts << opts[:ref] if opts[:ref]

command('fetch', arr_opts)
Expand Down
63 changes: 63 additions & 0 deletions tests/test_helper.rb
Expand Up @@ -97,4 +97,67 @@ def with_custom_env_variables(&block)
Git::Lib::ENV_VARIABLE_NAMES.each { |k| ENV[k] = saved_env[k] }
end
end

# Assert that the expected command line args are generated for a given Git::Lib method
#
# This assertion generates an empty git repository and then runs calls
# Git::Base method named by `git_cmd` passing that method `git_cmd_args`.
#
# Before calling `git_cmd`, this method stubs the `Git::Lib#command` method to
# capture the args sent to it by `git_cmd`. These args are captured into
# `actual_command_line`.
#
# assert_equal is called comparing the given `expected_command_line` to
# `actual_command_line`.
#
# @example Fetch with no args
# expected_command_line = ['fetch', '--', 'origin']
# git_cmd = :fetch
# git_cmd_args = []
# assert_command_line(expected_command_line, git_cmd, git_cmd_args)
#
# @example Fetch with some args
# expected_command_line = ['fetch', '--depth', '2', '--', 'origin', 'master']
# git_cmd = :fetch
# git_cmd_args = ['origin', ref: 'master', depth: '2']
# assert_command_line(expected_command_line, git_cmd, git_cmd_args)
#
# @example Fetch all
# expected_command_line = ['fetch', '--all']
# git_cmd = :fetch
# git_cmd_args = [all: true]
# assert_command_line(expected_command_line, git_cmd, git_cmd_args)
#
# @param expected_command_line [Array<String>] The expected arguments to be sent to Git::Lib#command
# @param git_cmd [Symbol] the method to be called on the Git::Base object
# @param git_cmd_args [Array<Object>] The arguments to be sent to the git_cmd method
#
# @yield [git] An initialization block
# The initialization block is called after a test project is created with Git.init.
# The current working directory is set to the root of the test project's working tree.
# @yieldparam git [Git::Base] The Git::Base object resulting from initializing the test project
# @yieldreturn [void] the return value of the block is ignored
#
# @return [void]
#
def assert_command_line(expected_command_line, git_cmd, git_cmd_args)
actual_command_line = nil

in_temp_dir do |path|
git = Git.init('test_project')

Dir.chdir 'test_project' do
yield(git) if block_given?

# Mock the Git::Lib#command method to capture the actual command line args
git.lib.define_singleton_method(:command) do |cmd, *opts, &block|
actual_command_line = [cmd, *opts.flatten]
end

git.send(git_cmd, *git_cmd_args)
end
end

assert_equal(expected_command_line, actual_command_line)
end
end
32 changes: 29 additions & 3 deletions tests/units/test_remotes.rb
@@ -1,6 +1,6 @@
#!/usr/bin/env ruby

require File.dirname(__FILE__) + '/../test_helper'
require_relative '../test_helper'

class TestRemotes < Test::Unit::TestCase
def setup
Expand Down Expand Up @@ -123,6 +123,34 @@ def test_fetch
end
end

def test_fetch_cmd_with_no_args
expected_command_line = ['fetch', '--', 'origin']
git_cmd = :fetch
git_cmd_args = []
assert_command_line(expected_command_line, git_cmd, git_cmd_args)
end

def test_fetch_cmd_with_origin_and_branch
expected_command_line = ['fetch', '--depth', '2', '--', 'origin', 'master']
git_cmd = :fetch
git_cmd_args = ['origin', ref: 'master', depth: '2']
assert_command_line(expected_command_line, git_cmd, git_cmd_args)
end

def test_fetch_cmd_with_all
expected_command_line = ['fetch', '--all']
git_cmd = :fetch
git_cmd_args = [all: true]
assert_command_line(expected_command_line, git_cmd, git_cmd_args)
end

def test_fetch_cmd_with_all_with_other_args
expected_command_line = ['fetch', '--all', '--force', '--depth', '2']
git_cmd = :fetch
git_cmd_args = [all: true, force: true, depth: '2']
assert_command_line(expected_command_line, git_cmd, git_cmd_args)
end

def test_fetch_command_injection
test_file = 'VULNERABILITY_EXISTS'
vulnerability_exists = false
Expand Down Expand Up @@ -208,6 +236,4 @@ def test_push
assert(rem.tag('test-tag'))
end
end


end

0 comments on commit 6f2b3fd

Please sign in to comment.