Skip to content

Commit

Permalink
Make Git::URL.clone_to handle cloning to bare and mirror repos
Browse files Browse the repository at this point in the history
Signed-off-by: James Couball <jcouball@yahoo.com>
  • Loading branch information
jcouball committed Apr 25, 2022
1 parent 13471d7 commit 88019cf
Show file tree
Hide file tree
Showing 4 changed files with 223 additions and 148 deletions.
13 changes: 9 additions & 4 deletions lib/git/url.rb
Expand Up @@ -52,7 +52,7 @@ def self.parse(url)
end
end

# The name `git clone` would use for the repository directory for the given URL
# The directory `git clone` would use for the repository directory for the given URL
#
# @example
# Git::URL.clone_to('https://github.com/ruby-git/ruby-git.git') #=> 'ruby-git'
Expand All @@ -61,12 +61,17 @@ def self.parse(url)
#
# @return [String] the name of the repository directory
#
def self.clone_to(url)
def self.clone_to(url, bare: false, mirror: false)
uri = parse(url)
path_parts = uri.path.split('/')
path_parts.pop if path_parts.last == '.git'

path_parts.last.sub(/\.git$/, '')
directory = path_parts.last
if bare || mirror
directory += '.git' unless directory.end_with?('.git')
elsif directory.end_with?('.git')
directory = directory[0..-5]
end
directory
end
end

Expand Down
144 changes: 0 additions & 144 deletions tests/units/test_url.rb

This file was deleted.

114 changes: 114 additions & 0 deletions tests/units/test_url_clone_to.rb
@@ -0,0 +1,114 @@
# frozen_string_literal: true

require 'test/unit'
require File.join(File.dirname(__dir__), 'test_helper')

# Tests Git::URL.clone_to
#
class TestURLCloneTo < Test::Unit::TestCase
def test_clone_to_full_repo
GIT_URLS.each do |url_data|
url = url_data[:url]
expected_path = url_data[:expected_path]
actual_path = Git::URL.clone_to(url)
assert_equal(
expected_path, actual_path,
"Failed to determine the clone path for URL '#{url}' correctly"
)
end
end

def test_clone_to_bare_repo
GIT_URLS.each do |url_data|
url = url_data[:url]
expected_path = url_data[:expected_bare_path]
actual_path = Git::URL.clone_to(url, bare: true)
assert_equal(
expected_path, actual_path,
"Failed to determine the clone path for URL '#{url}' correctly"
)
end
end

def test_clone_to_mirror_repo
GIT_URLS.each do |url_data|
url = url_data[:url]
# The expected_path is the same for bare and mirror repos
expected_path = url_data[:expected_bare_path]
actual_path = Git::URL.clone_to(url, mirror: true)
assert_equal(
expected_path, actual_path,
"Failed to determine the clone path for URL '#{url}' correctly"
)
end
end

GIT_URLS = [
{
url: 'https://github.com/org/repo',
expected_path: 'repo',
expected_bare_path: 'repo.git'
},
{
url: 'https://github.com/org/repo.git',
expected_path: 'repo',
expected_bare_path: 'repo.git'
},
{
url: 'https://git.mydomain.com/org/repo/.git',
expected_path: 'repo',
expected_bare_path: 'repo.git'
}
].freeze

# Git::URL.clone_to makes some assumptions about how the `git` command names
# the directory to clone to. This test ensures that the assumptions are
# correct.
#
def test_git_clone_naming_assumptions
in_temp_dir do |_path|
setup_test_repositories

GIT_CLONE_COMMANDS.each do |command_data|
command = command_data[:command]
expected_path = command_data[:expected_path]

output = `#{command} 2>&1`

assert_match(/Cloning into (?:bare repository )?'#{expected_path}'/, output)
FileUtils.rm_rf(expected_path)
end
end
end

GIT_CLONE_COMMANDS = [
# Clone to full repository
{ command: "git clone 'server/my_project'", expected_path: 'my_project' },
{ command: "git clone 'server/my_project/.git'", expected_path: 'my_project' },
{ command: "git clone 'server/my_project.git'", expected_path: 'my_project' },

# Clone to bare repository
{ command: "git clone --bare 'server/my_project'", expected_path: 'my_project.git' },
{ command: "git clone --bare 'server/my_project/.git'", expected_path: 'my_project.git' },
{ command: "git clone --bare 'server/my_project.git'", expected_path: 'my_project.git' },

# Clone to mirror repository
{ command: "git clone --mirror 'server/my_project'", expected_path: 'my_project.git' },
{ command: "git clone --mirror 'server/my_project/.git'", expected_path: 'my_project.git' },
{ command: "git clone --mirror 'server/my_project.git'", expected_path: 'my_project.git' }
].freeze

def setup_test_repositories
# Create a repository to clone from
Dir.mkdir 'server'
remote = Git.init('server/my_project')
Dir.chdir('server/my_project') do
new_file('README.md', '# My New Project')
remote.add
remote.commit('Initial version')
end

# Create a bare repository to clone from
Git.clone('server/my_project', 'server/my_project.git', bare: true)
end
end
100 changes: 100 additions & 0 deletions tests/units/test_url_parse.rb
@@ -0,0 +1,100 @@
# frozen_string_literal: true

require 'test/unit'

# Tests Git::URL.parse
#
class TestURLParse < Test::Unit::TestCase
def test_parse_with_invalid_url
url = 'user@host.xz:/path/to/repo.git/'
assert_raise(Addressable::URI::InvalidURIError) do
Git::URL.parse(url)
end
end

def test_parse
GIT_URLS.each do |url_data|
url = url_data[:url]
expected_uri = url_data[:expected_uri]
actual_uri = Git::URL.parse(url).to_hash.delete_if { |_key, value| value.nil? }
assert_equal(expected_uri, actual_uri, "Failed to parse URL '#{url}' correctly")
end
end

# For any URL, #to_s should return the url passed to Git::URL.parse(url)
def test_to_s
GIT_URLS.each do |url_data|
url = url_data[:url]
to_s = Git::URL.parse(url).to_s
assert_equal(url, to_s, "Parsed URI#to_s does not return the original URL '#{url}' correctly")
end
end

GIT_URLS = [
{
url: 'ssh://host.xz/path/to/repo.git/',
expected_uri: { scheme: 'ssh', host: 'host.xz', path: '/path/to/repo.git/' }
},
{
url: 'ssh://host.xz:4443/path/to/repo.git/',
expected_uri: { scheme: 'ssh', host: 'host.xz', port: 4443, path: '/path/to/repo.git/' }
},
{
url: 'ssh:///path/to/repo.git/',
expected_uri: { scheme: 'ssh', host: '', path: '/path/to/repo.git/' }
},
{
url: 'user@host.xz:path/to/repo.git/',
expected_uri: { scheme: 'git-alt', user: 'user', host: 'host.xz', path: '/path/to/repo.git/' }
},
{
url: 'host.xz:path/to/repo.git/',
expected_uri: { scheme: 'git-alt', host: 'host.xz', path: '/path/to/repo.git/' }
},
{
url: 'git://host.xz:4443/path/to/repo.git/',
expected_uri: { scheme: 'git', host: 'host.xz', port: 4443, path: '/path/to/repo.git/' }
},
{
url: 'git://user@host.xz:4443/path/to/repo.git/',
expected_uri: { scheme: 'git', user: 'user', host: 'host.xz', port: 4443, path: '/path/to/repo.git/' }
},
{
url: 'https://host.xz/path/to/repo.git/',
expected_uri: { scheme: 'https', host: 'host.xz', path: '/path/to/repo.git/' }
},
{
url: 'https://host.xz:4443/path/to/repo.git/',
expected_uri: { scheme: 'https', host: 'host.xz', port: 4443, path: '/path/to/repo.git/' }
},
{
url: 'ftps://host.xz:4443/path/to/repo.git/',
expected_uri: { scheme: 'ftps', host: 'host.xz', port: 4443, path: '/path/to/repo.git/' }
},
{
url: 'ftps://host.xz:4443/path/to/repo.git/',
expected_uri: { scheme: 'ftps', host: 'host.xz', port: 4443, path: '/path/to/repo.git/' }
},
{
url: 'file:./relative-path/to/repo.git/',
expected_uri: { scheme: 'file', path: './relative-path/to/repo.git/' }
},
{
url: 'file:///path/to/repo.git/',
expected_uri: { scheme: 'file', host: '', path: '/path/to/repo.git/' }
},
{
url: 'file:///path/to/repo.git',
expected_uri: { scheme: 'file', host: '', path: '/path/to/repo.git' }
},
{
url: 'file://host.xz/path/to/repo.git',
expected_uri: { scheme: 'file', host: 'host.xz', path: '/path/to/repo.git' }
},
{ url: '/path/to/repo.git/', expected_uri: { path: '/path/to/repo.git/' } },
{ url: '/path/to/bare-repo/.git', expected_uri: { path: '/path/to/bare-repo/.git' } },
{ url: 'relative-path/to/repo.git/', expected_uri: { path: 'relative-path/to/repo.git/' } },
{ url: './relative-path/to/repo.git/', expected_uri: { path: './relative-path/to/repo.git/' } },
{ url: '../ruby-git/.git', expected_uri: { path: '../ruby-git/.git' } }
].freeze
end

0 comments on commit 88019cf

Please sign in to comment.