Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Git::URL.clone_to handle cloning to bare and mirror repos #577

Merged
merged 1 commit into from Apr 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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