puppetfile-resolver 0.5.0 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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