puppetfile-resolver 0.5.0 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,95 @@
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
+ METADATA_FILE = 'metadata.json'
16
+
17
+ # @summary clones the remote url and reads the metadata file
18
+ # @returns [String] the content of the metadata file
19
+ def self.metadata(puppetfile_module, resolver_ui, config)
20
+ repo_url = puppetfile_module.remote
21
+
22
+ unless PuppetfileResolver::Util.git?
23
+ resolver_ui.debug { 'Git executible not found, unable to use git clone resolution' }
24
+
25
+ return nil
26
+ end
27
+ return nil if repo_url.nil?
28
+ return nil unless valid_http_url?(repo_url)
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, 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, config)
48
+ Dir.mktmpdir(nil, config.clone_dir) do |dir|
49
+ clone = ['git', 'clone', url, dir]
50
+ clone += ['--config', "http.proxy=#{config.proxy}", '--config', "https.proxy=#{config.proxy}"] if config.proxy
51
+
52
+ bare_clone = clone + ['--bare', '--depth=1']
53
+ bare_clone.push("--branch=#{ref}") unless ref == 'HEAD'
54
+
55
+ # Try to clone a bare repository. If that fails, fall back to a full clone.
56
+ # Cloning might fail because the repo does not exist or is otherwise
57
+ # inaccessible, but it can also fail because cloning a bare repository from
58
+ # a commit/SHA1 fails. Falling back to a full clone ensures that we support
59
+ # commits/SHA1s like Puppetfile does.
60
+ _stdout, _stderr, process = ::PuppetfileResolver::Util.run_command(bare_clone)
61
+
62
+ unless process.success?
63
+ _stdout, stderr, process = ::PuppetfileResolver::Util.run_command(clone)
64
+
65
+ unless process.success?
66
+ msg = if config.proxy
67
+ "Cloning #{url} with proxy #{config.proxy} failed: #{stderr}"
68
+ else
69
+ "Cloning #{url} failed: #{stderr}"
70
+ end
71
+ raise msg
72
+ end
73
+ end
74
+
75
+ Dir.chdir(dir) do
76
+ content, stderr, process = ::PuppetfileResolver::Util.run_command(['git', 'show', "#{ref}:#{METADATA_FILE}"])
77
+ raise "Could not find #{METADATA_FILE} for ref #{ref} at #{url}: #{stderr}" unless process.success?
78
+ return content
79
+ end
80
+ end
81
+ end
82
+
83
+ def self.valid_http_url?(url)
84
+ # uri does not work with git urls, return true
85
+ return true if url.start_with?('git@')
86
+
87
+ uri = URI.parse(url)
88
+ uri.is_a?(URI::HTTP) && !uri.host.nil?
89
+ rescue URI::InvalidURIError
90
+ false
91
+ end
92
+ end
93
+ end
94
+ end
95
+ 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 nil
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 nil
49
+ end
50
+ response.body
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -3,6 +3,9 @@
3
3
  require 'puppetfile-resolver/util'
4
4
  require 'puppetfile-resolver/spec_searchers/common'
5
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'
6
9
 
7
10
  module PuppetfileResolver
8
11
  module SpecSearchers
@@ -12,54 +15,21 @@ module PuppetfileResolver
12
15
  # Has the information been cached?
13
16
  return cache.load(dep_id) if cache.exist?(dep_id)
14
17
 
15
- # We _could_ git clone this, but it'll take too long. So for now, just
16
- # try and resolve github based repositories by crafting a URL
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)
17
25
 
18
- repo_url = nil
19
- if puppetfile_module.remote.start_with?('git@github.com:')
20
- repo_url = puppetfile_module.remote.slice(15..-1)
21
- repo_url = repo_url.slice(0..-5) if repo_url.end_with?('.git')
22
- end
23
- if puppetfile_module.remote.start_with?('https://github.com/')
24
- repo_url = puppetfile_module.remote.slice(19..-1)
25
- repo_url = repo_url.slice(0..-5) if repo_url.end_with?('.git')
26
- end
27
-
28
- return [] if repo_url.nil?
29
-
30
- metadata_url = 'https://raw.githubusercontent.com/' + repo_url + '/'
31
- if puppetfile_module.ref
32
- metadata_url += puppetfile_module.ref + '/'
33
- elsif puppetfile_module.tag
34
- metadata_url += puppetfile_module.tag + '/'
35
- else
36
- # Default to master. Should it raise?
37
- metadata_url += 'master/'
38
- end
39
- metadata_url += 'metadata.json'
40
-
41
- require 'net/http'
42
- require 'uri'
43
-
44
- resolver_ui.debug { "Querying GitHub with #{metadata_url}" }
45
- err_msg = "Unable to find module at #{puppetfile_module.remote}"
46
- err_msg += config.proxy ? " with proxy #{config.proxy}: " : ': '
47
- response = nil
48
-
49
- begin
50
- response = ::PuppetfileResolver::Util.net_http_get(metadata_url, config.proxy)
51
- rescue ::StandardError => e
52
- raise err_msg + e.message
53
- end
54
-
55
- if response.code != '200'
56
- resolver_ui.debug(err_msg + "Expected HTTP Code 200, but received #{response.code}")
26
+ if metadata.nil? || metadata.empty?
27
+ # Cache that we couldn't find the metadata
57
28
  cache.save(dep_id, [])
58
29
  return []
59
30
  end
60
31
 
61
- # TODO: symbolise_object should be in a Util namespace
62
- metadata = ::PuppetfileResolver::Util.symbolise_object(::JSON.parse(response.body))
32
+ metadata = ::PuppetfileResolver::Util.symbolise_object(::JSON.parse(metadata))
63
33
  result = [Models::ModuleSpecification.new(
64
34
  name: metadata[:name],
65
35
  origin: :git,
@@ -3,7 +3,7 @@
3
3
  module PuppetfileResolver
4
4
  module SpecSearchers
5
5
  class GitConfiguration
6
- attr_accessor :proxy
6
+ attr_accessor :proxy, :clone_dir
7
7
  end
8
8
  end
9
9
  end
@@ -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)
@@ -43,5 +45,22 @@ module PuppetfileResolver
43
45
  Net::HTTP.start(*start_args, http_options) { |http| return http.request(Net::HTTP::Get.new(uri)) }
44
46
  nil
45
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
46
65
  end
47
66
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PuppetfileResolver
4
- VERSION ||= '0.5.0'
4
+ VERSION ||= '0.6.2'
5
5
  end
@@ -3,10 +3,8 @@ require 'spec_helper'
3
3
  require 'puppetfile-resolver/resolver'
4
4
  require 'puppetfile-resolver/puppetfile'
5
5
 
6
-
7
6
  describe 'KitchenSink Tests' do
8
7
  it 'should resolve a complete Puppetfile' do
9
-
10
8
  content = <<-PUPFILE
11
9
  forge 'https://forge.puppet.com'
12
10
 
@@ -14,6 +12,10 @@ describe 'KitchenSink Tests' do
14
12
  :git => 'https://github.com/puppetlabs/puppetlabs-powershell',
15
13
  :tag => 'v4.0.0'
16
14
 
15
+ mod 'simpkv',
16
+ :git => 'https://gitlab.com/simp/pupmod-simp-simpkv.git',
17
+ :tag => '0.7.1'
18
+
17
19
  mod 'puppetlabs/stdlib', '6.3.0'
18
20
 
19
21
  # Local module path module
@@ -35,6 +37,9 @@ describe 'KitchenSink Tests' do
35
37
  expect(result.specifications).to include('powershell')
36
38
  expect(result.specifications['powershell'].version.to_s).to eq('4.0.0')
37
39
 
40
+ expect(result.specifications).to include('simpkv')
41
+ expect(result.specifications['simpkv'].version.to_s).to eq('0.7.1')
42
+
38
43
  expect(result.specifications).to include('stdlib')
39
44
  expect(result.specifications['stdlib'].version.to_s).to eq('6.3.0')
40
45
 
@@ -0,0 +1,71 @@
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::GitConfiguration.new
10
+
11
+ let(:url) do
12
+ 'https://github.com/puppetlabs/puppetlabs-powershell'
13
+ end
14
+
15
+ let(:puppetfile_module) do
16
+ PuppetfileModule.new(remote: url)
17
+ end
18
+
19
+
20
+ context 'valid url' do
21
+ it 'reads metadata' do
22
+ content = subject.metadata(puppetfile_module, Logger.new(STDERR), config)
23
+ expect(JSON.parse(content)['name']).to eq('puppetlabs-powershell')
24
+ end
25
+
26
+ context 'with tag' do
27
+ let(:puppetfile_module) do
28
+ PuppetfileModule.new(remote: url, ref: '2.1.2')
29
+ end
30
+
31
+ it 'reads metadata' do
32
+ content = subject.metadata(puppetfile_module, Logger.new(STDERR), config)
33
+ expect(JSON.parse(content)['name']).to eq('puppetlabs-powershell')
34
+ end
35
+ end
36
+
37
+ context 'with commit' do
38
+ let(:puppetfile_module) do
39
+ PuppetfileModule.new(remote: url, ref: '9276de695798097e8471b877a18df27f764eecda')
40
+ end
41
+
42
+ it 'reads metadata' do
43
+ content = subject.metadata(puppetfile_module, Logger.new(STDERR), config)
44
+ expect(JSON.parse(content)['name']).to eq('puppetlabs-powershell')
45
+ end
46
+ end
47
+
48
+ context 'with invalid ref' do
49
+ let(:puppetfile_module) do
50
+ PuppetfileModule.new(remote: url, ref: '8f7d5ea3ef49dadc5e166d5d802d091abc4b02bc')
51
+ end
52
+
53
+ it 'errors gracefully' do
54
+ expect { subject.metadata(puppetfile_module, Logger.new(STDERR), config) }.to raise_error(
55
+ /Could not find metadata\.json for ref .* at .*/
56
+ )
57
+ end
58
+ end
59
+ end
60
+
61
+ context 'invalid url' do
62
+ let(:url) do
63
+ 'https://user:password@github.com/puppetlabs/puppetlabs-powershellbad'
64
+ end
65
+
66
+ it 'throws exception' do
67
+ expect{subject.metadata(puppetfile_module, Logger.new(STDERR), config)}
68
+ .to raise_exception(RuntimeError)
69
+ end
70
+ end
71
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppetfile-resolver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Glenn Sarti
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-16 00:00:00.000000000 Z
11
+ date: 2022-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: molinillo
@@ -85,6 +85,9 @@ files:
85
85
  - lib/puppetfile-resolver/spec_searchers/forge.rb
86
86
  - lib/puppetfile-resolver/spec_searchers/forge_configuration.rb
87
87
  - lib/puppetfile-resolver/spec_searchers/git.rb
88
+ - lib/puppetfile-resolver/spec_searchers/git/gclone.rb
89
+ - lib/puppetfile-resolver/spec_searchers/git/github.rb
90
+ - lib/puppetfile-resolver/spec_searchers/git/gitlab.rb
88
91
  - lib/puppetfile-resolver/spec_searchers/git_configuration.rb
89
92
  - lib/puppetfile-resolver/spec_searchers/local.rb
90
93
  - lib/puppetfile-resolver/spec_searchers/local_configuration.rb
@@ -103,11 +106,12 @@ files:
103
106
  - spec/unit/puppetfile-resolver/puppetfile/document_spec.rb
104
107
  - spec/unit/puppetfile-resolver/puppetfile/parser/r10k_eval_spec.rb
105
108
  - spec/unit/puppetfile-resolver/resolver_spec.rb
109
+ - spec/unit/puppetfile-resolver/spec_searchers/git/gclone_spec.rb
106
110
  homepage: https://glennsarti.github.io/puppetfile-resolver/
107
111
  licenses:
108
112
  - Apache-2.0
109
113
  metadata: {}
110
- post_install_message:
114
+ post_install_message:
111
115
  rdoc_options: []
112
116
  require_paths:
113
117
  - lib
@@ -122,18 +126,19 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
126
  - !ruby/object:Gem::Version
123
127
  version: '0'
124
128
  requirements: []
125
- rubygems_version: 3.1.4
126
- signing_key:
129
+ rubygems_version: 3.0.3
130
+ signing_key:
127
131
  specification_version: 4
128
132
  summary: Dependency resolver for Puppetfiles
129
133
  test_files:
130
- - spec/fixtures/modulepath/test_module/metadata.json
131
- - spec/fixtures/modulepath/test_module/README.md
132
- - spec/fixtures/proxy.rb
133
- - spec/integration/deprecation_spec.rb
134
- - spec/integration/kitchensink_spec.rb
135
- - spec/integration/proxy_spec.rb
136
- - spec/spec_helper.rb
134
+ - spec/unit/puppetfile-resolver/spec_searchers/git/gclone_spec.rb
137
135
  - spec/unit/puppetfile-resolver/puppetfile/document_spec.rb
138
136
  - spec/unit/puppetfile-resolver/puppetfile/parser/r10k_eval_spec.rb
139
137
  - spec/unit/puppetfile-resolver/resolver_spec.rb
138
+ - spec/integration/proxy_spec.rb
139
+ - spec/integration/kitchensink_spec.rb
140
+ - spec/integration/deprecation_spec.rb
141
+ - spec/spec_helper.rb
142
+ - spec/fixtures/modulepath/test_module/metadata.json
143
+ - spec/fixtures/modulepath/test_module/README.md
144
+ - spec/fixtures/proxy.rb