Skip to content

Commit a741f06

Browse files
authored
Merge pull request glennsarti#33 from logicminds/git_spec_searcher
Adds git clone method to search for metadata file
2 parents 526d658 + a280cbf commit a741f06

File tree

6 files changed

+161
-8
lines changed

6 files changed

+161
-8
lines changed

Gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ gemspec
55

66
group :development do
77
gem 'rspec', '>= 3.2', :require => false
8-
8+
gem 'pry'
99
if RUBY_VERSION =~ /^2\.1\./
1010
gem "rubocop", "<= 0.57.2", :require => false, :platforms => [:ruby, :x64_mingw]
1111
gem 'rake', '~> 12.3', :require => false

lib/puppetfile-resolver/spec_searchers/git.rb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
require 'puppetfile-resolver/spec_searchers/git_configuration'
66
require 'puppetfile-resolver/spec_searchers/git/github'
77
require 'puppetfile-resolver/spec_searchers/git/gitlab'
8+
require 'puppetfile-resolver/spec_searchers/git/gclone'
89

910
module PuppetfileResolver
1011
module SpecSearchers
@@ -14,12 +15,13 @@ def self.find_all(puppetfile_module, dependency, cache, resolver_ui, config)
1415
# Has the information been cached?
1516
return cache.load(dep_id) if cache.exist?(dep_id)
1617

17-
# We _could_ git clone this, but it'll take too long. So for now, just
18-
# try and resolve github based repositories by crafting a URL
19-
metadata = GitHub.metadata(puppetfile_module, resolver_ui, config)
20-
metadata = GitLab.metadata(puppetfile_module, resolver_ui, config) if metadata.nil?
21-
22-
# TODO: Once we've exhausted using alternate methods lets just `git clone` it
18+
# The git clone method takes around (1s) depending on repo size. Not sure if the
19+
# other methods take longer or shorter but I preserved the legacy code for now.
20+
# Technically, the gclone class could replace the other classes and speed up
21+
# this process here.
22+
metadata = GitHub.metadata(puppetfile_module, resolver_ui, config) ||
23+
GitLab.metadata(puppetfile_module, resolver_ui, config) ||
24+
GClone.metadata(puppetfile_module, resolver_ui, config)
2325

2426
if metadata.nil? || metadata.empty?
2527
# Cache that we couldn't find the metadata
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# frozen_string_literal: true
2+
3+
require 'tempfile'
4+
require 'English'
5+
require 'puppetfile-resolver/util'
6+
require 'puppetfile-resolver/spec_searchers/common'
7+
require 'puppetfile-resolver/spec_searchers/git_configuration'
8+
require 'puppetfile-resolver/util'
9+
require 'uri'
10+
11+
module PuppetfileResolver
12+
module SpecSearchers
13+
module Git
14+
module GClone
15+
# @summary clones the remote url and reads the metadata file
16+
# @returns [String] the content of the metadata file
17+
def self.metadata(puppetfile_module, resolver_ui, config)
18+
repo_url = puppetfile_module.remote
19+
20+
unless PuppetfileResolver::Util.git?
21+
resolver_ui.debug { 'Git executible not found, unable to use git clone resolution' }
22+
23+
return nil
24+
end
25+
return nil if repo_url.nil?
26+
return nil unless valid_http_url?(repo_url)
27+
28+
metadata_file = 'metadata.json'
29+
30+
ref = puppetfile_module.ref ||
31+
puppetfile_module.tag ||
32+
puppetfile_module.commit ||
33+
puppetfile_module.branch ||
34+
'HEAD'
35+
36+
resolver_ui.debug { "Querying git repository #{repo_url}" }
37+
38+
clone_and_read_file(repo_url, ref, metadata_file, config)
39+
end
40+
41+
# @summary clones the git url and reads the file at the given ref
42+
# a temp directory will be created and then destroyed during
43+
# the cloning and reading process
44+
# @param ref [String] the git ref, branch, commit, tag
45+
# @param file [String] the file you wish to read
46+
# @returns [String] the content of the file
47+
def self.clone_and_read_file(url, ref, file, config)
48+
clone_cmd = ['git', 'clone', '--bare', '--depth=1', '--single-branch']
49+
err_msg = ''
50+
if config.git.proxy
51+
err_msg += " with proxy #{config.git.proxy}: "
52+
proxy = "--config \"http.proxy=#{config.git.proxy}\" --config \"https.proxy=#{config.proxy}\""
53+
clone_cmd.push(proxy)
54+
end
55+
56+
Dir.mktmpdir(nil, config.git.clone_dir) do |dir|
57+
clone_cmd.push("--branch=#{ref}") if ref != 'HEAD'
58+
clone_cmd.push(url, dir)
59+
out, err_out, process = ::PuppetfileResolver::Util.run_command(clone_cmd)
60+
err_msg += out
61+
raise err_msg unless process.success?
62+
Dir.chdir(dir) do
63+
content, err_out, process = ::PuppetfileResolver::Util.run_command(['git', 'show', "#{ref}:#{file}"])
64+
raise 'InvalidContent' unless process.success? && content.length > 2
65+
return content
66+
end
67+
end
68+
end
69+
70+
def self.valid_http_url?(url)
71+
# uri does not work with git urls, return true
72+
return true if url.start_with?('git@')
73+
74+
uri = URI.parse(url)
75+
uri.is_a?(URI::HTTP) && !uri.host.nil?
76+
rescue URI::InvalidURIError
77+
false
78+
end
79+
end
80+
end
81+
end
82+
end

lib/puppetfile-resolver/spec_searchers/git_configuration.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module PuppetfileResolver
44
module SpecSearchers
55
class GitConfiguration
6-
attr_accessor :proxy
6+
attr_accessor :proxy, :clone_dir
77
end
88
end
99
end

lib/puppetfile-resolver/util.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# frozen_string_literal: true
22

3+
require 'open3'
4+
35
module PuppetfileResolver
46
module Util
57
def self.symbolise_object(object)
@@ -43,5 +45,22 @@ def self.net_http_get(uri, proxy = nil)
4345
Net::HTTP.start(*start_args, http_options) { |http| return http.request(Net::HTTP::Get.new(uri)) }
4446
nil
4547
end
48+
49+
# @summary runs the command on the shell
50+
# @param cmd [Array] an array of command and args
51+
# @returns [Array] the result of running the comand and the process
52+
# @example run_command(['git', '--version'])
53+
def self.run_command(cmd)
54+
Open3.capture3(*cmd)
55+
end
56+
57+
# @summary checks if git is installed and on the path
58+
# @returns [Boolean] true if git is found in the path
59+
def self.git?
60+
Open3.capture3('git', '--version')
61+
true
62+
rescue Errno::ENOENT
63+
false
64+
end
4665
end
4766
end
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
require 'spec_helper'
2+
require 'puppetfile-resolver/spec_searchers/git/gclone'
3+
require 'puppetfile-resolver/spec_searchers/git_configuration'
4+
require 'logger'
5+
require 'json'
6+
7+
describe PuppetfileResolver::SpecSearchers::Git::GClone do
8+
PuppetfileModule = Struct.new(:remote, :ref, :branch, :commit, :tag, keyword_init: true)
9+
config = PuppetfileResolver::SpecSearchers::Configuration.new
10+
config.local.puppet_module_paths = [File.join(FIXTURES_DIR, 'modulepath')]
11+
12+
let(:url) do
13+
'https://github.com/puppetlabs/puppetlabs-powershell'
14+
end
15+
16+
let(:puppetfile_module) do
17+
PuppetfileModule.new(remote: url)
18+
end
19+
20+
21+
context 'valid url' do
22+
it 'reads metadata' do
23+
content = subject.metadata(puppetfile_module, Logger.new(STDERR), config)
24+
expect(JSON.parse(content)['name']).to eq('puppetlabs-powershell')
25+
end
26+
27+
context 'with ref' do
28+
29+
let(:puppetfile_module) do
30+
PuppetfileModule.new(remote: url, ref: '2.1.2')
31+
end
32+
33+
it 'reads metadata' do
34+
content = subject.metadata(puppetfile_module, Logger.new(STDERR), config)
35+
expect(JSON.parse(content)['name']).to eq('puppetlabs-powershell')
36+
end
37+
end
38+
end
39+
40+
context 'invalid url' do
41+
let(:url) do
42+
'https://github.com/puppetlabs/puppetlabs-powershellbad'
43+
end
44+
45+
it 'throws exception' do
46+
expect{subject.metadata(puppetfile_module, Logger.new(STDERR), config)}
47+
.to raise_exception(RuntimeError)
48+
end
49+
end
50+
end

0 commit comments

Comments
 (0)