puppetfile-resolver 0.3.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/puppetfile-resolver/data/ruby_ca_certs.pem +732 -851
- data/lib/puppetfile-resolver/puppetfile/parser/r10k_eval/module/forge.rb +8 -2
- data/lib/puppetfile-resolver/resolution_provider.rb +15 -8
- data/lib/puppetfile-resolver/resolution_result.rb +1 -1
- data/lib/puppetfile-resolver/resolver.rb +3 -2
- data/lib/puppetfile-resolver/spec_searchers/configuration.rb +21 -0
- data/lib/puppetfile-resolver/spec_searchers/forge.rb +17 -19
- data/lib/puppetfile-resolver/spec_searchers/forge_configuration.rb +17 -0
- data/lib/puppetfile-resolver/spec_searchers/git/gclone.rb +82 -0
- data/lib/puppetfile-resolver/spec_searchers/git/github.rb +53 -0
- data/lib/puppetfile-resolver/spec_searchers/git/gitlab.rb +55 -0
- data/lib/puppetfile-resolver/spec_searchers/git.rb +16 -34
- data/lib/puppetfile-resolver/spec_searchers/git_configuration.rb +9 -0
- data/lib/puppetfile-resolver/spec_searchers/local.rb +3 -2
- data/lib/puppetfile-resolver/spec_searchers/local_configuration.rb +13 -0
- data/lib/puppetfile-resolver/util.rb +43 -0
- data/lib/puppetfile-resolver/version.rb +1 -1
- data/puppetfile-cli.rb +14 -1
- data/spec/fixtures/modulepath/test_module/README.md +1 -0
- data/spec/fixtures/modulepath/test_module/metadata.json +9 -0
- data/spec/fixtures/proxy.rb +9 -0
- data/spec/integration/deprecation_spec.rb +32 -0
- data/spec/integration/kitchensink_spec.rb +49 -0
- data/spec/integration/proxy_spec.rb +91 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/unit/puppetfile-resolver/puppetfile/parser/r10k_eval_spec.rb +19 -4
- data/spec/unit/puppetfile-resolver/resolver_spec.rb +44 -1
- data/spec/unit/puppetfile-resolver/spec_searchers/git/gclone_spec.rb +50 -0
- metadata +29 -8
@@ -14,12 +14,12 @@ module PuppetfileResolver
|
|
14
14
|
|
15
15
|
def self.to_document_module(title, args)
|
16
16
|
mod = ::PuppetfileResolver::Puppetfile::ForgeModule.new(title)
|
17
|
-
mod.version = args if valid_version?(args)
|
17
|
+
mod.version = munge_version_string(args) if valid_version?(args)
|
18
18
|
mod
|
19
19
|
end
|
20
20
|
|
21
21
|
def self.valid_version?(value)
|
22
|
-
return false unless value.is_a?(String) || value.is_a?(Symbol)
|
22
|
+
return false unless value.is_a?(String) || value.is_a?(Symbol) || value.nil?
|
23
23
|
value == :latest || value.nil? || valid_version_string?(value)
|
24
24
|
end
|
25
25
|
private_class_method :valid_version?
|
@@ -42,6 +42,12 @@ module PuppetfileResolver
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
private_class_method :valid_version_string?
|
45
|
+
|
46
|
+
def self.munge_version_string(value)
|
47
|
+
return :latest if value.nil? || value == :latest
|
48
|
+
"=#{value}"
|
49
|
+
end
|
50
|
+
private_class_method :munge_version_string
|
45
51
|
end
|
46
52
|
end
|
47
53
|
end
|
@@ -5,27 +5,34 @@ require 'puppetfile-resolver/cache/base'
|
|
5
5
|
require 'puppetfile-resolver/spec_searchers/forge'
|
6
6
|
require 'puppetfile-resolver/spec_searchers/git'
|
7
7
|
require 'puppetfile-resolver/spec_searchers/local'
|
8
|
+
require 'puppetfile-resolver/spec_searchers/configuration'
|
8
9
|
|
9
10
|
module PuppetfileResolver
|
10
11
|
class ResolutionProvider
|
11
12
|
include Molinillo::SpecificationProvider
|
12
13
|
|
13
14
|
# options
|
14
|
-
# module_paths
|
15
|
-
# strict_mode
|
15
|
+
# module_paths : Array of paths (Deprecated)
|
16
|
+
# strict_mode : [Boolean] Whether missing dependencies throw an error (default: false)
|
17
|
+
# spec_searcher_configuration : PuppetfileResolver::SpecSearchers::Configuration
|
16
18
|
def initialize(puppetfile_document, puppet_version, resolver_ui, options = {})
|
17
19
|
require 'semantic_puppet'
|
18
20
|
|
19
21
|
@puppetfile_document = puppetfile_document
|
20
22
|
raise 'The UI object must be of type Molinillo::UI' if resolver_ui.nil? || !resolver_ui.is_a?(Molinillo::UI)
|
21
23
|
@resolver_ui = resolver_ui
|
22
|
-
|
23
|
-
@puppet_module_paths = options[:module_paths].nil? ? [] : options[:module_paths]
|
24
|
+
@spec_searcher_configuration = options[:spec_searcher_configuration] || PuppetfileResolver::SpecSearchers::Configuration.new
|
24
25
|
@allow_missing_modules = options[:allow_missing_modules].nil? ? true : options[:allow_missing_modules] == true
|
25
26
|
# There can be only one puppet specification in existance so we pre-load here.
|
26
27
|
@puppet_specification = Models::PuppetSpecification.new(puppet_version)
|
27
28
|
@module_info = {}
|
28
29
|
@cache = options[:cache].nil? ? Cache::Base.new : options[:cache]
|
30
|
+
|
31
|
+
# Check for deprecated options
|
32
|
+
unless options[:module_paths].nil? # rubocop:disable Style/GuardClause
|
33
|
+
Warning.warn 'The use of the module_paths option has been deprecated'
|
34
|
+
@spec_searcher_configuration.local.puppet_module_paths = options[:module_paths]
|
35
|
+
end
|
29
36
|
end
|
30
37
|
|
31
38
|
# Search for the specifications that match the given dependency.
|
@@ -137,9 +144,9 @@ module PuppetfileResolver
|
|
137
144
|
unless mod.nil?
|
138
145
|
case mod.module_type
|
139
146
|
when Puppetfile::FORGE_MODULE
|
140
|
-
@module_info[dependency.name] = safe_spec_search(dependency) { SpecSearchers::Forge.find_all(dependency, @cache, @resolver_ui) }
|
147
|
+
@module_info[dependency.name] = safe_spec_search(dependency) { SpecSearchers::Forge.find_all(dependency, @cache, @resolver_ui, @spec_searcher_configuration.forge) }
|
141
148
|
when Puppetfile::GIT_MODULE
|
142
|
-
@module_info[dependency.name] = safe_spec_search(dependency) { SpecSearchers::Git.find_all(mod, dependency, @cache, @resolver_ui) }
|
149
|
+
@module_info[dependency.name] = safe_spec_search(dependency) { SpecSearchers::Git.find_all(mod, dependency, @cache, @resolver_ui, @spec_searcher_configuration.git) }
|
143
150
|
else # rubocop:disable Style/EmptyElse
|
144
151
|
# Errr.... Nothing
|
145
152
|
end
|
@@ -147,13 +154,13 @@ module PuppetfileResolver
|
|
147
154
|
return @module_info[dependency.name] unless @module_info[dependency.name].empty?
|
148
155
|
|
149
156
|
# It's not in the Puppetfile, so perhaps it's in our modulepath?
|
150
|
-
@module_info[dependency.name] = safe_spec_search(dependency) { SpecSearchers::Local.find_all(mod,
|
157
|
+
@module_info[dependency.name] = safe_spec_search(dependency) { SpecSearchers::Local.find_all(mod, dependency, @cache, @resolver_ui, @spec_searcher_configuration.local) }
|
151
158
|
return @module_info[dependency.name] unless @module_info[dependency.name].empty?
|
152
159
|
|
153
160
|
# It's not in the Puppetfile and not on disk, so perhaps it's on the Forge?
|
154
161
|
# The forge needs an owner and name to be able to resolve
|
155
162
|
if dependency.name && dependency.owner # rubocop:disable Style/IfUnlessModifier
|
156
|
-
@module_info[dependency.name] = safe_spec_search(dependency) { SpecSearchers::Forge.find_all(dependency, @cache, @resolver_ui) }
|
163
|
+
@module_info[dependency.name] = safe_spec_search(dependency) { SpecSearchers::Forge.find_all(dependency, @cache, @resolver_ui, @spec_searcher_configuration.forge) }
|
157
164
|
end
|
158
165
|
|
159
166
|
# If we can't find any specifications for the module and we're allowing missing modules
|
@@ -4,7 +4,7 @@ require 'molinillo'
|
|
4
4
|
|
5
5
|
module PuppetfileResolver
|
6
6
|
class ResolutionResult
|
7
|
-
attr_reader :dependency_graph
|
7
|
+
attr_reader :dependency_graph, :puppetfile_document
|
8
8
|
|
9
9
|
def initialize(dependency_graph, puppetfile_document)
|
10
10
|
raise "Expected Molinillo::DependencyGraph but got #{dependency_graph.class}" unless dependency_graph.is_a?(Molinillo::DependencyGraph)
|
@@ -20,7 +20,8 @@ module PuppetfileResolver
|
|
20
20
|
|
21
21
|
# options
|
22
22
|
# :cache => Cache Object
|
23
|
-
# :module_paths => Array[String]
|
23
|
+
# :module_paths => Array[String] (Deprecated)
|
24
|
+
# :spec_searcher_configuration => PuppetfileResolver::SpecSearchers::Configuration
|
24
25
|
def resolve(options = {})
|
25
26
|
if options[:ui]
|
26
27
|
raise 'The UI object must be of type Molinillo::UI' unless options[:ui].is_a?(Molinillo::UI)
|
@@ -55,7 +56,7 @@ module PuppetfileResolver
|
|
55
56
|
if mod.version.nil? || mod.version == :latest
|
56
57
|
version = '>= 0' # Note the `>=` is important. Don't use `>`
|
57
58
|
else
|
58
|
-
version =
|
59
|
+
version = mod.version
|
59
60
|
end
|
60
61
|
|
61
62
|
result << Models::PuppetfileDependency.new(
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'puppetfile-resolver/spec_searchers/forge_configuration'
|
4
|
+
require 'puppetfile-resolver/spec_searchers/git_configuration'
|
5
|
+
require 'puppetfile-resolver/spec_searchers/local_configuration'
|
6
|
+
|
7
|
+
module PuppetfileResolver
|
8
|
+
module SpecSearchers
|
9
|
+
class Configuration
|
10
|
+
attr_reader :local
|
11
|
+
attr_reader :forge
|
12
|
+
attr_reader :git
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@local = LocalConfiguration.new
|
16
|
+
@forge = ForgeConfiguration.new
|
17
|
+
@git = GitConfiguration.new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'puppetfile-resolver/util'
|
3
4
|
require 'puppetfile-resolver/spec_searchers/common'
|
5
|
+
require 'puppetfile-resolver/spec_searchers/forge_configuration'
|
4
6
|
require 'uri'
|
5
7
|
require 'net/http'
|
6
8
|
require 'openssl'
|
@@ -9,9 +11,7 @@ require 'json'
|
|
9
11
|
module PuppetfileResolver
|
10
12
|
module SpecSearchers
|
11
13
|
module Forge
|
12
|
-
|
13
|
-
|
14
|
-
def self.find_all(dependency, cache, resolver_ui)
|
14
|
+
def self.find_all(dependency, cache, resolver_ui, config)
|
15
15
|
dep_id = ::PuppetfileResolver::SpecSearchers::Common.dependency_cache_id(self, dependency)
|
16
16
|
|
17
17
|
# Has the information been cached?
|
@@ -19,7 +19,7 @@ module PuppetfileResolver
|
|
19
19
|
|
20
20
|
result = []
|
21
21
|
# Query the forge
|
22
|
-
fetch_all_module_releases(dependency.owner, dependency.name, resolver_ui) do |partial_releases|
|
22
|
+
fetch_all_module_releases(dependency.owner, dependency.name, resolver_ui, config) do |partial_releases|
|
23
23
|
partial_releases.each do |release|
|
24
24
|
result << Models::ModuleSpecification.new(
|
25
25
|
name: release['module']['name'],
|
@@ -35,38 +35,36 @@ module PuppetfileResolver
|
|
35
35
|
result
|
36
36
|
end
|
37
37
|
|
38
|
-
def self.fetch_all_module_releases(owner, name,
|
38
|
+
def self.fetch_all_module_releases(owner, name, resolver_ui, config, &block)
|
39
39
|
raise 'Requires a block to yield' unless block
|
40
|
-
uri = ::URI.parse("#{
|
40
|
+
uri = ::URI.parse("#{config.forge_api}/v3/releases")
|
41
41
|
params = { :module => "#{owner}-#{name}", :exclude_fields => 'readme changelog license reference tasks', :limit => 50 }
|
42
42
|
uri.query = ::URI.encode_www_form(params)
|
43
43
|
|
44
44
|
loops = 0
|
45
45
|
loop do
|
46
46
|
resolver_ui.debug { "Querying the forge for a module with #{uri}" }
|
47
|
-
|
48
|
-
|
49
|
-
# Because on Windows Ruby doesn't use the Windows certificate store which has up-to date
|
50
|
-
# CA certs, we can't depend on someone setting the environment variable correctly. So use our
|
51
|
-
# static CA PEM file if SSL_CERT_FILE is not set.
|
52
|
-
http_options[:ca_file] = PuppetfileResolver::Util.static_ca_cert_file if ENV['SSL_CERT_FILE'].nil?
|
53
|
-
|
47
|
+
err_msg = "Unable to find module #{owner}-#{name} on #{config.forge_api}"
|
48
|
+
err_msg += config.proxy ? " with proxy #{config.proxy}: " : ': '
|
54
49
|
response = nil
|
55
|
-
|
56
|
-
|
57
|
-
response =
|
50
|
+
|
51
|
+
begin
|
52
|
+
response = ::PuppetfileResolver::Util.net_http_get(uri, config.proxy)
|
53
|
+
rescue ::StandardError => e
|
54
|
+
raise err_msg + e.message
|
58
55
|
end
|
59
|
-
|
56
|
+
|
57
|
+
raise err_msg + "Expected HTTP Code 200, but received #{response.code}" unless response.code == '200'
|
60
58
|
|
61
59
|
reply = ::JSON.parse(response.body)
|
62
60
|
yield reply['results']
|
63
61
|
|
64
62
|
break if reply['pagination'].nil? || reply['pagination']['next'].nil?
|
65
|
-
uri = ::URI.parse("#{
|
63
|
+
uri = ::URI.parse("#{config.forge_api}#{reply['pagination']['next']}")
|
66
64
|
|
67
65
|
# Circuit breaker in case the worst happens (max 1000 module releases)
|
68
66
|
loops += 1
|
69
|
-
raise "Too many Forge API requests #{loops
|
67
|
+
raise err_msg + "Too many Forge API requests #{loops}" if loops > 20
|
70
68
|
end
|
71
69
|
end
|
72
70
|
private_class_method :fetch_all_module_releases
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PuppetfileResolver
|
4
|
+
module SpecSearchers
|
5
|
+
class ForgeConfiguration
|
6
|
+
DEFAULT_FORGE_URI ||= 'https://forgeapi.puppet.com'
|
7
|
+
|
8
|
+
def forge_api
|
9
|
+
@forge_api || DEFAULT_FORGE_URI
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_writer :forge_api
|
13
|
+
|
14
|
+
attr_accessor :proxy
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -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
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'puppetfile-resolver/util'
|
4
|
+
require 'puppetfile-resolver/spec_searchers/common'
|
5
|
+
require 'puppetfile-resolver/spec_searchers/git_configuration'
|
6
|
+
|
7
|
+
module PuppetfileResolver
|
8
|
+
module SpecSearchers
|
9
|
+
module Git
|
10
|
+
module GitHub
|
11
|
+
def self.metadata(puppetfile_module, resolver_ui, config)
|
12
|
+
repo_url = nil
|
13
|
+
if puppetfile_module.remote.start_with?('git@github.com:')
|
14
|
+
repo_url = puppetfile_module.remote.slice(15..-1)
|
15
|
+
repo_url = repo_url.slice(0..-5) if repo_url.end_with?('.git')
|
16
|
+
elsif puppetfile_module.remote.start_with?('https://github.com/')
|
17
|
+
repo_url = puppetfile_module.remote.slice(19..-1)
|
18
|
+
repo_url = repo_url.slice(0..-5) if repo_url.end_with?('.git')
|
19
|
+
end
|
20
|
+
return nil if repo_url.nil?
|
21
|
+
|
22
|
+
metadata_url = 'https://raw.githubusercontent.com/' + repo_url + '/'
|
23
|
+
if puppetfile_module.ref
|
24
|
+
metadata_url += puppetfile_module.ref + '/'
|
25
|
+
elsif puppetfile_module.tag
|
26
|
+
metadata_url += puppetfile_module.tag + '/'
|
27
|
+
else
|
28
|
+
# Default to master. Should it raise?
|
29
|
+
metadata_url += 'master/'
|
30
|
+
end
|
31
|
+
metadata_url += 'metadata.json'
|
32
|
+
|
33
|
+
resolver_ui.debug { "Querying GitHub with #{metadata_url}" }
|
34
|
+
err_msg = "Unable to find module at #{puppetfile_module.remote}"
|
35
|
+
err_msg += config.proxy ? " with proxy #{config.proxy}: " : ': '
|
36
|
+
response = nil
|
37
|
+
|
38
|
+
begin
|
39
|
+
response = ::PuppetfileResolver::Util.net_http_get(metadata_url, config.proxy)
|
40
|
+
rescue ::StandardError => e
|
41
|
+
raise err_msg + e.message
|
42
|
+
end
|
43
|
+
|
44
|
+
if response.code != '200'
|
45
|
+
resolver_ui.debug(err_msg + "Expected HTTP Code 200, but received #{response.code}")
|
46
|
+
return ''
|
47
|
+
end
|
48
|
+
response.body
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'puppetfile-resolver/util'
|
4
|
+
require 'puppetfile-resolver/spec_searchers/common'
|
5
|
+
require 'puppetfile-resolver/spec_searchers/git_configuration'
|
6
|
+
|
7
|
+
module PuppetfileResolver
|
8
|
+
module SpecSearchers
|
9
|
+
module Git
|
10
|
+
module GitLab
|
11
|
+
def self.metadata(puppetfile_module, resolver_ui, config)
|
12
|
+
repo_url = nil
|
13
|
+
if puppetfile_module.remote.start_with?('git@gitlab.com:')
|
14
|
+
repo_url = puppetfile_module.remote.slice(15..-1)
|
15
|
+
repo_url = repo_url.slice(0..-5) if repo_url.end_with?('.git')
|
16
|
+
elsif puppetfile_module.remote.start_with?('https://gitlab.com/')
|
17
|
+
repo_url = puppetfile_module.remote.slice(19..-1)
|
18
|
+
repo_url = repo_url.slice(0..-5) if repo_url.end_with?('.git')
|
19
|
+
end
|
20
|
+
return nil if repo_url.nil?
|
21
|
+
|
22
|
+
# Example URL
|
23
|
+
# https://gitlab.com/simp/pupmod-simp-crypto_policy/-/raw/0.1.4/metadata.json
|
24
|
+
metadata_url = 'https://gitlab.com/' + repo_url + '/-/raw/'
|
25
|
+
if puppetfile_module.ref
|
26
|
+
metadata_url += puppetfile_module.ref + '/'
|
27
|
+
elsif puppetfile_module.tag
|
28
|
+
metadata_url += puppetfile_module.tag + '/'
|
29
|
+
else
|
30
|
+
# Default to master. Should it raise?
|
31
|
+
metadata_url += 'master/'
|
32
|
+
end
|
33
|
+
metadata_url += 'metadata.json'
|
34
|
+
|
35
|
+
resolver_ui.debug { "Querying GitLab with #{metadata_url}" }
|
36
|
+
err_msg = "Unable to find module at #{puppetfile_module.remote}"
|
37
|
+
err_msg += config.proxy ? " with proxy #{config.proxy}: " : ': '
|
38
|
+
response = nil
|
39
|
+
|
40
|
+
begin
|
41
|
+
response = ::PuppetfileResolver::Util.net_http_get(metadata_url, config.proxy)
|
42
|
+
rescue ::StandardError => e
|
43
|
+
raise err_msg + e.message
|
44
|
+
end
|
45
|
+
|
46
|
+
if response.code != '200'
|
47
|
+
resolver_ui.debug(err_msg + "Expected HTTP Code 200, but received #{response.code}")
|
48
|
+
return ''
|
49
|
+
end
|
50
|
+
response.body
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -1,53 +1,35 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'puppetfile-resolver/util'
|
3
4
|
require 'puppetfile-resolver/spec_searchers/common'
|
5
|
+
require 'puppetfile-resolver/spec_searchers/git_configuration'
|
6
|
+
require 'puppetfile-resolver/spec_searchers/git/github'
|
7
|
+
require 'puppetfile-resolver/spec_searchers/git/gitlab'
|
8
|
+
require 'puppetfile-resolver/spec_searchers/git/gclone'
|
4
9
|
|
5
10
|
module PuppetfileResolver
|
6
11
|
module SpecSearchers
|
7
12
|
module Git
|
8
|
-
def self.find_all(puppetfile_module, dependency, cache, resolver_ui)
|
13
|
+
def self.find_all(puppetfile_module, dependency, cache, resolver_ui, config)
|
9
14
|
dep_id = ::PuppetfileResolver::SpecSearchers::Common.dependency_cache_id(self, dependency)
|
10
15
|
# Has the information been cached?
|
11
16
|
return cache.load(dep_id) if cache.exist?(dep_id)
|
12
17
|
|
13
|
-
#
|
14
|
-
#
|
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)
|
15
25
|
|
16
|
-
|
17
|
-
|
18
|
-
repo_url = puppetfile_module.remote.slice(15..-1)
|
19
|
-
repo_url = repo_url.slice(0..-5) if repo_url.end_with?('.git')
|
20
|
-
end
|
21
|
-
if puppetfile_module.remote.start_with?('https://github.com/')
|
22
|
-
repo_url = puppetfile_module.remote.slice(19..-1)
|
23
|
-
repo_url = repo_url.slice(0..-5) if repo_url.end_with?('.git')
|
24
|
-
end
|
25
|
-
|
26
|
-
return [] if repo_url.nil?
|
27
|
-
|
28
|
-
metadata_url = 'https://raw.githubusercontent.com/' + repo_url + '/'
|
29
|
-
if puppetfile_module.ref
|
30
|
-
metadata_url += puppetfile_module.ref + '/'
|
31
|
-
elsif puppetfile_module.tag
|
32
|
-
metadata_url += puppetfile_module.tag + '/'
|
33
|
-
else
|
34
|
-
# Default to master. Should it raise?
|
35
|
-
metadata_url += 'master/'
|
36
|
-
end
|
37
|
-
metadata_url += 'metadata.json'
|
38
|
-
|
39
|
-
require 'net/http'
|
40
|
-
require 'uri'
|
41
|
-
|
42
|
-
resolver_ui.debug { "Querying the Github with #{metadata_url}" }
|
43
|
-
response = Net::HTTP.get_response(URI.parse(metadata_url))
|
44
|
-
if response.code != '200'
|
26
|
+
if metadata.nil? || metadata.empty?
|
27
|
+
# Cache that we couldn't find the metadata
|
45
28
|
cache.save(dep_id, [])
|
46
29
|
return []
|
47
30
|
end
|
48
31
|
|
49
|
-
|
50
|
-
metadata = ::PuppetfileResolver::Util.symbolise_object(::JSON.parse(response.body))
|
32
|
+
metadata = ::PuppetfileResolver::Util.symbolise_object(::JSON.parse(metadata))
|
51
33
|
result = [Models::ModuleSpecification.new(
|
52
34
|
name: metadata[:name],
|
53
35
|
origin: :git,
|
@@ -1,18 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'puppetfile-resolver/spec_searchers/common'
|
4
|
+
require 'puppetfile-resolver/spec_searchers/local_configuration'
|
4
5
|
|
5
6
|
module PuppetfileResolver
|
6
7
|
module SpecSearchers
|
7
8
|
module Local
|
8
|
-
def self.find_all(_puppetfile_module,
|
9
|
+
def self.find_all(_puppetfile_module, dependency, cache, resolver_ui, config)
|
9
10
|
dep_id = ::PuppetfileResolver::SpecSearchers::Common.dependency_cache_id(self, dependency)
|
10
11
|
# Has the information been cached?
|
11
12
|
return cache.load(dep_id) if cache.exist?(dep_id)
|
12
13
|
|
13
14
|
result = []
|
14
15
|
# Find the module in the modulepaths
|
15
|
-
puppet_module_paths.each do |module_path|
|
16
|
+
config.puppet_module_paths.each do |module_path|
|
16
17
|
next unless Dir.exist?(module_path)
|
17
18
|
module_dir = File.expand_path(File.join(module_path, dependency.name))
|
18
19
|
next unless Dir.exist?(module_dir)
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'open3'
|
4
|
+
|
3
5
|
module PuppetfileResolver
|
4
6
|
module Util
|
5
7
|
def self.symbolise_object(object)
|
@@ -19,5 +21,46 @@ module PuppetfileResolver
|
|
19
21
|
def self.static_ca_cert_file
|
20
22
|
@static_ca_cert_file ||= File.expand_path(File.join(__dir__, 'data', 'ruby_ca_certs.pem'))
|
21
23
|
end
|
24
|
+
|
25
|
+
# Execute a HTTP/S GET query and return the response
|
26
|
+
# @param [String, URI] uri The URI to request
|
27
|
+
# @param [nil, String, URI] proxy The URI of the proxy server to use. Defaults to nil (No proxy server)
|
28
|
+
# @return [Net::HTTPResponse] the response of the request
|
29
|
+
def self.net_http_get(uri, proxy = nil)
|
30
|
+
uri = URI.parse(uri) unless uri.is_a?(URI)
|
31
|
+
|
32
|
+
http_options = { :use_ssl => uri.class == URI::HTTPS }
|
33
|
+
# Because on Windows Ruby doesn't use the Windows certificate store which has up-to date
|
34
|
+
# CA certs, we can't depend on someone setting the environment variable correctly. So use our
|
35
|
+
# static CA PEM file if SSL_CERT_FILE is not set.
|
36
|
+
http_options[:ca_file] = PuppetfileResolver::Util.static_ca_cert_file if ENV['SSL_CERT_FILE'].nil?
|
37
|
+
|
38
|
+
start_args = [uri.host, uri.port]
|
39
|
+
|
40
|
+
unless proxy.nil?
|
41
|
+
proxy = URI.parse(proxy) unless proxy.is_a?(URI)
|
42
|
+
start_args.concat([proxy.host, proxy.port, proxy.user, proxy.password])
|
43
|
+
end
|
44
|
+
|
45
|
+
Net::HTTP.start(*start_args, http_options) { |http| return http.request(Net::HTTP::Get.new(uri)) }
|
46
|
+
nil
|
47
|
+
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
|
22
65
|
end
|
23
66
|
end
|
data/puppetfile-cli.rb
CHANGED
@@ -18,6 +18,7 @@ class CommandLineParser
|
|
18
18
|
cache_dir: nil,
|
19
19
|
module_paths: [],
|
20
20
|
path: nil,
|
21
|
+
proxy: nil,
|
21
22
|
puppet_version: nil,
|
22
23
|
strict: false
|
23
24
|
}
|
@@ -41,6 +42,10 @@ class CommandLineParser
|
|
41
42
|
args[:debug] = true
|
42
43
|
end
|
43
44
|
|
45
|
+
opts.on('--proxy=PROXY_URL', 'HTTP/S Proxy server to use. For example http://localhost:8888') do |proxy|
|
46
|
+
args[:proxy] = proxy
|
47
|
+
end
|
48
|
+
|
44
49
|
opts.on('-s', '--strict', 'Do not allow missing dependencies. Default false which marks dependencies as missing and does not raise an error.') do
|
45
50
|
args[:strict] = true
|
46
51
|
end
|
@@ -88,7 +93,15 @@ if options[:debug]
|
|
88
93
|
else
|
89
94
|
ui = nil
|
90
95
|
end
|
91
|
-
|
96
|
+
|
97
|
+
config = PuppetfileResolver::SpecSearchers::Configuration.new
|
98
|
+
config.local.puppet_module_paths = options[:module_paths]
|
99
|
+
unless options[:proxy].nil?
|
100
|
+
config.git.proxy = options[:proxy]
|
101
|
+
config.forge.proxy = options[:proxy]
|
102
|
+
end
|
103
|
+
|
104
|
+
opts = { cache: cache, ui: ui, spec_searcher_configuration: config, allow_missing_modules: !options[:strict] }
|
92
105
|
|
93
106
|
# Resolve
|
94
107
|
result = resolver.resolve(opts)
|
@@ -0,0 +1 @@
|
|
1
|
+
This test fixture contains a valid module with classes, types and functions.
|