puppetlabs_spec_helper 5.0.0 → 6.0.0
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +13 -514
- data/README.md +2 -2
- data/lib/puppetlabs_spec_helper/module_spec_helper.rb +10 -9
- data/lib/puppetlabs_spec_helper/puppet_spec_helper.rb +1 -3
- data/lib/puppetlabs_spec_helper/puppetlabs_spec/files.rb +42 -42
- data/lib/puppetlabs_spec_helper/puppetlabs_spec/fixtures.rb +39 -41
- data/lib/puppetlabs_spec_helper/puppetlabs_spec/puppet_internals.rb +34 -32
- data/lib/puppetlabs_spec_helper/rake_tasks.rb +19 -23
- data/lib/puppetlabs_spec_helper/tasks/check_symlinks.rb +41 -37
- data/lib/puppetlabs_spec_helper/tasks/fixtures.rb +343 -353
- data/lib/puppetlabs_spec_helper/version.rb +1 -1
- data/spec/acceptance/smoke_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -2
- data/spec/unit/puppetlabs_spec_helper/tasks/check_symlinks_spec.rb +17 -17
- data/spec/unit/puppetlabs_spec_helper/tasks/check_test_file_spec.rb +4 -4
- data/spec/unit/puppetlabs_spec_helper/tasks/{fixtures_spec.rb → fixture_helpers_spec.rb} +33 -33
- data/spec/watchr.rb +3 -5
- metadata +30 -12
|
@@ -4,406 +4,398 @@ require 'yaml'
|
|
|
4
4
|
require 'open3'
|
|
5
5
|
require 'json'
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
module
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# @return [String] - the name of current module
|
|
18
|
-
def module_name
|
|
19
|
-
raise ArgumentError unless File.file?('metadata.json') && File.readable?('metadata.json')
|
|
20
|
-
|
|
21
|
-
metadata = JSON.parse(File.read('metadata.json'))
|
|
22
|
-
metadata_name = metadata.fetch('name', nil) || ''
|
|
7
|
+
module PuppetlabsSpecHelper
|
|
8
|
+
module Tasks
|
|
9
|
+
# Helpers for working with fixtures.
|
|
10
|
+
module FixtureHelpers
|
|
11
|
+
# This is a helper for the self-symlink entry of fixtures.yml
|
|
12
|
+
def source_dir
|
|
13
|
+
Dir.pwd
|
|
14
|
+
end
|
|
23
15
|
|
|
24
|
-
|
|
16
|
+
# @return [String] - the name of current module
|
|
17
|
+
def module_name
|
|
18
|
+
raise ArgumentError unless File.file?('metadata.json') && File.readable?('metadata.json')
|
|
25
19
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
File.basename(Dir.pwd).split('-').last
|
|
29
|
-
end
|
|
20
|
+
metadata = JSON.parse(File.read('metadata.json'))
|
|
21
|
+
metadata_name = metadata.fetch('name', nil) || ''
|
|
30
22
|
|
|
31
|
-
|
|
32
|
-
metadata_path = File.join(path, 'metadata.json')
|
|
33
|
-
raise ArgumentError unless File.file?(metadata_path) && File.readable?(metadata_path)
|
|
23
|
+
raise ArgumentError if metadata_name.empty?
|
|
34
24
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
'0.0.1'
|
|
40
|
-
end
|
|
25
|
+
metadata_name.split('-').last
|
|
26
|
+
rescue JSON::ParserError, ArgumentError
|
|
27
|
+
File.basename(Dir.pwd).split('-').last
|
|
28
|
+
end
|
|
41
29
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
# "ref"=>nil, "branch"=>"main", "scm"=>nil,
|
|
46
|
-
# }}
|
|
47
|
-
def repositories
|
|
48
|
-
@repositories ||= fixtures('repositories') || {}
|
|
49
|
-
end
|
|
30
|
+
def module_version(path)
|
|
31
|
+
metadata_path = File.join(path, 'metadata.json')
|
|
32
|
+
raise ArgumentError unless File.file?(metadata_path) && File.readable?(metadata_path)
|
|
50
33
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
@forge_modules ||= fixtures('forge_modules') || {}
|
|
58
|
-
end
|
|
34
|
+
metadata = JSON.parse(File.read(metadata_path))
|
|
35
|
+
metadata.fetch('version', nil) || '0.0.1'
|
|
36
|
+
rescue JSON::ParserError, ArgumentError
|
|
37
|
+
logger.warn "Failed to find module version at path #{path}"
|
|
38
|
+
'0.0.1'
|
|
39
|
+
end
|
|
59
40
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
41
|
+
# @return [Hash] - returns a hash of all the fixture repositories
|
|
42
|
+
# @example
|
|
43
|
+
# {"puppetlabs-stdlib"=>{"target"=>"https://gitlab.com/puppetlabs/puppet-stdlib.git",
|
|
44
|
+
# "ref"=>nil, "branch"=>"main", "scm"=>nil,
|
|
45
|
+
# }}
|
|
46
|
+
def repositories
|
|
47
|
+
@repositories ||= fixtures('repositories') || {}
|
|
48
|
+
end
|
|
64
49
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
50
|
+
# @return [Hash] - returns a hash of all the fixture forge modules
|
|
51
|
+
# @example
|
|
52
|
+
# {"puppetlabs-stdlib"=>{"target"=>"spec/fixtures/modules/stdlib",
|
|
53
|
+
# "ref"=>nil, "branch"=>nil, "scm"=>nil,
|
|
54
|
+
# "flags"=>"--module_repository=https://myforge.example.com/", "subdir"=>nil}}
|
|
55
|
+
def forge_modules
|
|
56
|
+
@forge_modules ||= fixtures('forge_modules') || {}
|
|
57
|
+
end
|
|
69
58
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
59
|
+
# @return [Hash] - a hash of symlinks specified in the fixtures file
|
|
60
|
+
def symlinks
|
|
61
|
+
@symlinks ||= fixtures('symlinks') || {}
|
|
62
|
+
end
|
|
74
63
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
'.fixtures.yml'
|
|
80
|
-
elsif File.exist?('.fixtures.yaml')
|
|
81
|
-
'.fixtures.yaml'
|
|
82
|
-
else
|
|
83
|
-
false
|
|
84
|
-
end
|
|
64
|
+
# @return [Hash] - returns a hash with the module name and the source directory
|
|
65
|
+
def auto_symlink
|
|
66
|
+
{ module_name => "\#{source_dir}" }
|
|
67
|
+
end
|
|
85
68
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
{ 'fixtures' => {} }
|
|
91
|
-
end
|
|
92
|
-
rescue Errno::ENOENT
|
|
93
|
-
raise("Fixtures file not found: '#{fixtures_yaml}'")
|
|
94
|
-
rescue Psych::SyntaxError => e
|
|
95
|
-
raise("Found malformed YAML in '#{fixtures_yaml}' on line #{e.line} column #{e.column}: #{e.problem}")
|
|
96
|
-
end
|
|
69
|
+
# @return [Boolean] - true if the os is a windows system
|
|
70
|
+
def windows?
|
|
71
|
+
!!File::ALT_SEPARATOR
|
|
72
|
+
end
|
|
97
73
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
74
|
+
def fixtures(category)
|
|
75
|
+
fixtures_yaml = if ENV['FIXTURES_YML']
|
|
76
|
+
ENV['FIXTURES_YML']
|
|
77
|
+
elsif File.exist?('.fixtures.yml')
|
|
78
|
+
'.fixtures.yml'
|
|
79
|
+
elsif File.exist?('.fixtures.yaml')
|
|
80
|
+
'.fixtures.yaml'
|
|
81
|
+
else
|
|
82
|
+
false
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
begin
|
|
86
|
+
fixtures = if fixtures_yaml
|
|
87
|
+
YAML.load_file(fixtures_yaml) || { 'fixtures' => {} }
|
|
88
|
+
else
|
|
89
|
+
{ 'fixtures' => {} }
|
|
90
|
+
end
|
|
91
|
+
rescue Errno::ENOENT
|
|
92
|
+
raise("Fixtures file not found: '#{fixtures_yaml}'")
|
|
93
|
+
rescue Psych::SyntaxError => e
|
|
94
|
+
raise("Found malformed YAML in '#{fixtures_yaml}' on line #{e.line} column #{e.column}: #{e.problem}")
|
|
95
|
+
end
|
|
102
96
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
end
|
|
97
|
+
unless fixtures.include?('fixtures')
|
|
98
|
+
# File is non-empty, but does not specify fixtures
|
|
99
|
+
raise("No 'fixtures' entries found in '#{fixtures_yaml}'; required")
|
|
100
|
+
end
|
|
108
101
|
|
|
109
|
-
|
|
102
|
+
fixture_defaults = if fixtures.include? 'defaults'
|
|
103
|
+
fixtures['defaults']
|
|
104
|
+
else
|
|
105
|
+
{}
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
fixtures = fixtures['fixtures']
|
|
109
|
+
|
|
110
|
+
fixtures['symlinks'] = auto_symlink if fixtures['symlinks'].nil?
|
|
111
|
+
|
|
112
|
+
result = {}
|
|
113
|
+
if fixtures.include?(category) && !fixtures[category].nil?
|
|
114
|
+
defaults = { 'target' => 'spec/fixtures/modules' }
|
|
115
|
+
|
|
116
|
+
# load defaults from the `.fixtures.yml` `defaults` section
|
|
117
|
+
# for the requested category and merge them into my defaults
|
|
118
|
+
defaults = defaults.merge(fixture_defaults[category]) if fixture_defaults.include? category
|
|
119
|
+
|
|
120
|
+
fixtures[category].each do |fixture, opts|
|
|
121
|
+
# convert a simple string fixture to a hash, by
|
|
122
|
+
# using the string fixture as the `repo` option of the hash.
|
|
123
|
+
opts = { 'repo' => opts } if opts.instance_of?(String)
|
|
124
|
+
# there should be a warning or something if it's not a hash...
|
|
125
|
+
next unless opts.instance_of?(Hash)
|
|
126
|
+
|
|
127
|
+
# merge our options into the defaults to get the
|
|
128
|
+
# final option list
|
|
129
|
+
opts = defaults.merge(opts)
|
|
130
|
+
|
|
131
|
+
next unless include_repo?(opts['puppet_version'])
|
|
132
|
+
|
|
133
|
+
real_target = eval("\"#{opts['target']}\"", binding, __FILE__, __LINE__) # evaluating target reference in this context (see auto_symlink)
|
|
134
|
+
real_source = eval("\"#{opts['repo']}\"", binding, __FILE__, __LINE__) # evaluating repo reference in this context (see auto_symlink)
|
|
135
|
+
|
|
136
|
+
result[real_source] = validate_fixture_hash!(
|
|
137
|
+
'target' => File.join(real_target, fixture),
|
|
138
|
+
'ref' => opts['ref'] || opts['tag'],
|
|
139
|
+
'branch' => opts['branch'],
|
|
140
|
+
'scm' => opts['scm'],
|
|
141
|
+
'flags' => opts['flags'],
|
|
142
|
+
'subdir' => opts['subdir'],
|
|
143
|
+
)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
result
|
|
147
|
+
end
|
|
110
148
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
149
|
+
def validate_fixture_hash!(hash)
|
|
150
|
+
# Can only validate git based scm
|
|
151
|
+
return hash unless hash['scm'] == 'git'
|
|
114
152
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
defaults = { 'target' => 'spec/fixtures/modules' }
|
|
153
|
+
# Forward slashes in the ref aren't allowed. And is probably a branch name.
|
|
154
|
+
raise ArgumentError, "The ref for #{hash['target']} is invalid (Contains a forward slash). If this is a branch name, please use the 'branch' setting instead." if hash['ref'].include?('/')
|
|
118
155
|
|
|
119
|
-
|
|
120
|
-
# for the requested category and merge them into my defaults
|
|
121
|
-
if fixture_defaults.include? category
|
|
122
|
-
defaults = defaults.merge(fixture_defaults[category])
|
|
156
|
+
hash
|
|
123
157
|
end
|
|
124
158
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
159
|
+
def include_repo?(version_range)
|
|
160
|
+
if version_range && defined?(SemanticPuppet)
|
|
161
|
+
puppet_spec = Gem::Specification.find_by_name('puppet')
|
|
162
|
+
puppet_version = SemanticPuppet::Version.parse(puppet_spec.version.to_s)
|
|
163
|
+
|
|
164
|
+
constraint = SemanticPuppet::VersionRange.parse(version_range)
|
|
165
|
+
constraint.include?(puppet_version)
|
|
166
|
+
else
|
|
167
|
+
true
|
|
130
168
|
end
|
|
131
|
-
# there should be a warning or something if it's not a hash...
|
|
132
|
-
next unless opts.instance_of?(Hash)
|
|
133
|
-
|
|
134
|
-
# merge our options into the defaults to get the
|
|
135
|
-
# final option list
|
|
136
|
-
opts = defaults.merge(opts)
|
|
137
|
-
|
|
138
|
-
next unless include_repo?(opts['puppet_version'])
|
|
139
|
-
|
|
140
|
-
# rubocop:disable Security/Eval
|
|
141
|
-
# TODO: Remove eval
|
|
142
|
-
real_target = eval("\"#{opts['target']}\"", binding, __FILE__, __LINE__) # evaluating target reference in this context (see auto_symlink)
|
|
143
|
-
real_source = eval("\"#{opts['repo']}\"", binding, __FILE__, __LINE__) # evaluating repo reference in this context (see auto_symlink)
|
|
144
|
-
|
|
145
|
-
result[real_source] = validate_fixture_hash!(
|
|
146
|
-
'target' => File.join(real_target, fixture),
|
|
147
|
-
'ref' => opts['ref'] || opts['tag'],
|
|
148
|
-
'branch' => opts['branch'],
|
|
149
|
-
'scm' => opts['scm'],
|
|
150
|
-
'flags' => opts['flags'],
|
|
151
|
-
'subdir' => opts['subdir'],
|
|
152
|
-
)
|
|
153
169
|
end
|
|
154
|
-
end
|
|
155
|
-
result
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def validate_fixture_hash!(hash)
|
|
159
|
-
# Can only validate git based scm
|
|
160
|
-
return hash unless hash['scm'] == 'git'
|
|
161
|
-
|
|
162
|
-
# Forward slashes in the ref aren't allowed. And is probably a branch name.
|
|
163
|
-
raise ArgumentError, "The ref for #{hash['target']} is invalid (Contains a forward slash). If this is a branch name, please use the 'branch' setting instead." if hash['ref'].include?('/')
|
|
164
|
-
|
|
165
|
-
hash
|
|
166
|
-
end
|
|
167
170
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
171
|
+
def clone_repo(scm, remote, target, _subdir = nil, ref = nil, branch = nil, flags = nil)
|
|
172
|
+
args = []
|
|
173
|
+
case scm
|
|
174
|
+
when 'hg'
|
|
175
|
+
args.push('clone')
|
|
176
|
+
args.push('-b', branch) if branch
|
|
177
|
+
args.push(flags) if flags
|
|
178
|
+
args.push(remote, target)
|
|
179
|
+
when 'git'
|
|
180
|
+
args.push('clone')
|
|
181
|
+
args.push('--depth 1') unless ref
|
|
182
|
+
args.push('-b', branch) if branch
|
|
183
|
+
args.push(flags) if flags
|
|
184
|
+
args.push(remote, target)
|
|
185
|
+
else
|
|
186
|
+
raise "Unfortunately #{scm} is not supported yet"
|
|
187
|
+
end
|
|
188
|
+
result = system("#{scm} #{args.flatten.join ' '}")
|
|
189
|
+
raise "Failed to clone #{scm} repository #{remote} into #{target}" unless File.exist?(target)
|
|
179
190
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
case scm
|
|
183
|
-
when 'hg'
|
|
184
|
-
args.push('clone')
|
|
185
|
-
args.push('-b', branch) if branch
|
|
186
|
-
args.push(flags) if flags
|
|
187
|
-
args.push(remote, target)
|
|
188
|
-
when 'git'
|
|
189
|
-
args.push('clone')
|
|
190
|
-
args.push('--depth 1') unless ref
|
|
191
|
-
args.push('-b', branch) if branch
|
|
192
|
-
args.push(flags) if flags
|
|
193
|
-
args.push(remote, target)
|
|
194
|
-
else
|
|
195
|
-
raise "Unfortunately #{scm} is not supported yet"
|
|
196
|
-
end
|
|
197
|
-
result = system("#{scm} #{args.flatten.join ' '}")
|
|
198
|
-
unless File.exist?(target)
|
|
199
|
-
raise "Failed to clone #{scm} repository #{remote} into #{target}"
|
|
200
|
-
end
|
|
191
|
+
result
|
|
192
|
+
end
|
|
201
193
|
|
|
202
|
-
|
|
203
|
-
|
|
194
|
+
def update_repo(scm, target)
|
|
195
|
+
args = case scm
|
|
196
|
+
when 'hg'
|
|
197
|
+
['pull']
|
|
198
|
+
when 'git'
|
|
199
|
+
['fetch'].tap do |git_args|
|
|
200
|
+
git_args << '--unshallow' if shallow_git_repo?
|
|
201
|
+
end
|
|
202
|
+
else
|
|
203
|
+
raise "Unfortunately #{scm} is not supported yet"
|
|
204
|
+
end
|
|
205
|
+
system("#{scm} #{args.flatten.join(' ')}", chdir: target)
|
|
206
|
+
end
|
|
204
207
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
['pull']
|
|
209
|
-
when 'git'
|
|
210
|
-
['fetch'].tap do |git_args|
|
|
211
|
-
git_args << '--unshallow' if shallow_git_repo?
|
|
212
|
-
end
|
|
213
|
-
else
|
|
214
|
-
raise "Unfortunately #{scm} is not supported yet"
|
|
215
|
-
end
|
|
216
|
-
system("#{scm} #{args.flatten.join(' ')}", chdir: target)
|
|
217
|
-
end
|
|
208
|
+
def shallow_git_repo?
|
|
209
|
+
File.file?(File.join('.git', 'shallow'))
|
|
210
|
+
end
|
|
218
211
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
212
|
+
def revision(scm, target, ref)
|
|
213
|
+
args = []
|
|
214
|
+
case scm
|
|
215
|
+
when 'hg'
|
|
216
|
+
args.push('update', '--clean', '-r', ref)
|
|
217
|
+
when 'git'
|
|
218
|
+
args.push('reset', '--hard', ref)
|
|
219
|
+
else
|
|
220
|
+
raise "Unfortunately #{scm} is not supported yet"
|
|
221
|
+
end
|
|
222
|
+
result = system("#{scm} #{args.flatten.join ' '}", chdir: target)
|
|
223
|
+
raise "Invalid ref #{ref} for #{target}" unless result
|
|
224
|
+
end
|
|
222
225
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
when 'hg'
|
|
227
|
-
args.push('update', '--clean', '-r', ref)
|
|
228
|
-
when 'git'
|
|
229
|
-
args.push('reset', '--hard', ref)
|
|
230
|
-
else
|
|
231
|
-
raise "Unfortunately #{scm} is not supported yet"
|
|
232
|
-
end
|
|
233
|
-
result = system("#{scm} #{args.flatten.join ' '}", chdir: target)
|
|
234
|
-
raise "Invalid ref #{ref} for #{target}" unless result
|
|
235
|
-
end
|
|
226
|
+
def valid_repo?(scm, target, remote)
|
|
227
|
+
return false unless File.directory?(target)
|
|
228
|
+
return true if scm == 'hg'
|
|
236
229
|
|
|
237
|
-
|
|
238
|
-
return false unless File.directory?(target)
|
|
239
|
-
return true if scm == 'hg'
|
|
230
|
+
return true if git_remote_url(target) == remote
|
|
240
231
|
|
|
241
|
-
|
|
232
|
+
warn "Git remote for #{target} has changed, recloning repository"
|
|
233
|
+
FileUtils.rm_rf(target)
|
|
234
|
+
false
|
|
235
|
+
end
|
|
242
236
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
237
|
+
def git_remote_url(target)
|
|
238
|
+
output, status = Open3.capture2e('git', '--git-dir', File.join(target, '.git'), 'ls-remote', '--get-url', 'origin')
|
|
239
|
+
status.success? ? output.strip : nil
|
|
240
|
+
end
|
|
247
241
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
status.success? ? output.strip : nil
|
|
251
|
-
end
|
|
242
|
+
def remove_subdirectory(target, subdir)
|
|
243
|
+
return if subdir.nil?
|
|
252
244
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
end
|
|
260
|
-
end
|
|
245
|
+
Dir.mktmpdir do |tmpdir|
|
|
246
|
+
FileUtils.mv(Dir.glob("#{target}/#{subdir}/{.[^.]*,*}"), tmpdir)
|
|
247
|
+
FileUtils.rm_rf("#{target}/#{subdir}")
|
|
248
|
+
FileUtils.mv(Dir.glob("#{tmpdir}/{.[^.]*,*}"), target.to_s)
|
|
249
|
+
end
|
|
250
|
+
end
|
|
261
251
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
252
|
+
# creates a logger so we can log events with certain levels
|
|
253
|
+
def logger
|
|
254
|
+
unless @logger
|
|
255
|
+
require 'logger'
|
|
256
|
+
level = if ENV['ENABLE_LOGGER']
|
|
257
|
+
Logger::DEBUG
|
|
258
|
+
else
|
|
259
|
+
Logger::INFO
|
|
260
|
+
end
|
|
261
|
+
@logger = Logger.new($stderr)
|
|
262
|
+
@logger.level = level
|
|
263
|
+
end
|
|
264
|
+
@logger
|
|
265
|
+
end
|
|
276
266
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
267
|
+
def module_working_directory
|
|
268
|
+
# The problem with the relative path is that PMT doesn't expand the path properly and so passing in a relative path here
|
|
269
|
+
# becomes something like C:\somewhere\backslashes/spec/fixtures/work-dir on Windows, and then PMT barfs itself.
|
|
270
|
+
# This has been reported as https://tickets.puppetlabs.com/browse/PUP-4884
|
|
271
|
+
File.expand_path(ENV['MODULE_WORKING_DIR'] || 'spec/fixtures/work-dir')
|
|
272
|
+
end
|
|
283
273
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
274
|
+
# returns the current thread count that is currently active
|
|
275
|
+
# a status of false or nil means the thread completed
|
|
276
|
+
# so when anything else we count that as a active thread
|
|
277
|
+
# @return [Integer] - current thread count
|
|
278
|
+
def current_thread_count(items)
|
|
279
|
+
active_threads = items.select do |_item, opts|
|
|
280
|
+
if opts[:thread]
|
|
281
|
+
opts[:thread].status
|
|
282
|
+
else
|
|
283
|
+
false
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
logger.debug "Current thread count #{active_threads.count}"
|
|
287
|
+
active_threads.count
|
|
294
288
|
end
|
|
295
|
-
end
|
|
296
|
-
logger.debug "Current thread count #{active_threads.count}"
|
|
297
|
-
active_threads.count
|
|
298
|
-
end
|
|
299
289
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
290
|
+
# @summary Set a limit on the amount threads used, defaults to 10
|
|
291
|
+
# MAX_FIXTURE_THREAD_COUNT can be used to set this limit
|
|
292
|
+
# @return [Integer] - returns the max_thread_count
|
|
293
|
+
def max_thread_limit
|
|
294
|
+
@max_thread_limit ||= (ENV['MAX_FIXTURE_THREAD_COUNT'] || 10).to_i
|
|
295
|
+
end
|
|
306
296
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
297
|
+
# @param items [Hash] - a hash of either repositories or forge modules
|
|
298
|
+
# @param [Block] - the method you wish to use to download the item
|
|
299
|
+
def download_items(items)
|
|
300
|
+
items.each do |remote, opts|
|
|
301
|
+
# get the current active threads that are alive
|
|
302
|
+
count = current_thread_count(items)
|
|
303
|
+
if count < max_thread_limit
|
|
304
|
+
logger.debug "New Thread started for #{remote}"
|
|
305
|
+
# start up a new thread and store it in the opts hash
|
|
306
|
+
opts[:thread] = Thread.new do
|
|
307
|
+
yield(remote, opts)
|
|
308
|
+
end
|
|
309
|
+
else
|
|
310
|
+
# the last thread started should be the longest wait
|
|
311
|
+
# Rubocop seems to push towards using select here.. however the implementation today relies on the result being
|
|
312
|
+
# an array. Select returns a hash which makes it unsuitable so we need to use find_all.last.
|
|
313
|
+
item, item_opts = items.find_all { |_i, o| o.key?(:thread) }.last # rubocop:disable Performance/Detect
|
|
314
|
+
logger.debug "Waiting on #{item}"
|
|
315
|
+
item_opts[:thread].join # wait for the thread to finish
|
|
316
|
+
# now that we waited lets try again
|
|
317
|
+
redo
|
|
318
|
+
end
|
|
318
319
|
end
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
item, item_opts = items.reverse.find { |_i, o| o.key?(:thread) }
|
|
322
|
-
logger.debug "Waiting on #{item}"
|
|
323
|
-
item_opts[:thread].join # wait for the thread to finish
|
|
324
|
-
# now that we waited lets try again
|
|
325
|
-
redo
|
|
320
|
+
# wait for all the threads to finish
|
|
321
|
+
items.each { |_remote, opts| opts[:thread].join }
|
|
326
322
|
end
|
|
327
|
-
end
|
|
328
|
-
# wait for all the threads to finish
|
|
329
|
-
items.each { |_remote, opts| opts[:thread].join }
|
|
330
|
-
end
|
|
331
323
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
324
|
+
# @param target [String] - the target directory
|
|
325
|
+
# @param link [String] - the name of the link you wish to create
|
|
326
|
+
# works on windows and linux
|
|
327
|
+
def setup_symlink(target, link)
|
|
328
|
+
link = link['target']
|
|
329
|
+
return if File.symlink?(link)
|
|
330
|
+
|
|
331
|
+
logger.info("Creating symlink from #{link} to #{target}")
|
|
332
|
+
if windows?
|
|
333
|
+
target = File.join(File.dirname(link), target) unless Pathname.new(target).absolute?
|
|
334
|
+
if Dir.respond_to?(:create_junction)
|
|
335
|
+
Dir.create_junction(link, target)
|
|
336
|
+
else
|
|
337
|
+
system("call mklink /J \"#{link.tr('/', '\\')}\" \"#{target.tr('/', '\\')}\"")
|
|
338
|
+
end
|
|
339
|
+
else
|
|
340
|
+
FileUtils.ln_sf(target, link)
|
|
341
|
+
end
|
|
346
342
|
end
|
|
347
|
-
else
|
|
348
|
-
FileUtils.ln_sf(target, link)
|
|
349
|
-
end
|
|
350
|
-
end
|
|
351
343
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
344
|
+
# @return [Boolean] - returns true if the module was downloaded successfully, false otherwise
|
|
345
|
+
# @param [String] - the remote url or namespace/name of the module to download
|
|
346
|
+
# @param [Hash] - list of options such as version, branch, ref
|
|
347
|
+
def download_repository(remote, opts)
|
|
348
|
+
scm = 'git'
|
|
349
|
+
target = opts['target']
|
|
350
|
+
subdir = opts['subdir']
|
|
351
|
+
ref = opts['ref']
|
|
352
|
+
scm = opts['scm'] if opts['scm']
|
|
353
|
+
branch = opts['branch'] if opts['branch']
|
|
354
|
+
flags = opts['flags']
|
|
355
|
+
if valid_repo?(scm, target, remote)
|
|
356
|
+
update_repo(scm, target)
|
|
357
|
+
else
|
|
358
|
+
clone_repo(scm, remote, target, subdir, ref, branch, flags)
|
|
359
|
+
end
|
|
360
|
+
revision(scm, target, ref) if ref
|
|
361
|
+
remove_subdirectory(target, subdir) if subdir
|
|
362
|
+
end
|
|
371
363
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
364
|
+
# @return [String] - the spec/fixtures/modules directory in the module root folder
|
|
365
|
+
def module_target_dir
|
|
366
|
+
@module_target_dir ||= File.expand_path('spec/fixtures/modules')
|
|
367
|
+
end
|
|
376
368
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
369
|
+
# @return [Boolean] - returns true if the module was downloaded successfully, false otherwise
|
|
370
|
+
# @param [String] - the remote url or namespace/name of the module to download
|
|
371
|
+
# @param [Hash] - list of options such as version
|
|
372
|
+
def download_module(remote, opts)
|
|
373
|
+
ref = ''
|
|
374
|
+
flags = ''
|
|
375
|
+
if opts.instance_of?(String)
|
|
376
|
+
target = opts
|
|
377
|
+
elsif opts.instance_of?(Hash)
|
|
378
|
+
target = opts['target']
|
|
379
|
+
ref = " --version #{opts['ref']}" unless opts['ref'].nil?
|
|
380
|
+
flags = " #{opts['flags']}" if opts['flags']
|
|
381
|
+
end
|
|
390
382
|
|
|
391
|
-
|
|
383
|
+
return false if File.directory?(target) && (ref.empty? || opts['ref'] == module_version(target))
|
|
392
384
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
385
|
+
# The PMT cannot handle multi threaded runs due to cache directory collisons
|
|
386
|
+
# so we randomize the directory instead.
|
|
387
|
+
# Does working_dir even need to be passed?
|
|
388
|
+
Dir.mktmpdir do |working_dir|
|
|
389
|
+
command = "puppet module install#{ref}#{flags} --ignore-dependencies " \
|
|
390
|
+
'--force ' \
|
|
391
|
+
"--module_working_dir \"#{working_dir}\" " \
|
|
392
|
+
"--target-dir \"#{module_target_dir}\" \"#{remote}\""
|
|
401
393
|
|
|
402
|
-
|
|
403
|
-
|
|
394
|
+
raise "Failed to install module #{remote} to #{module_target_dir}" unless system(command)
|
|
395
|
+
end
|
|
396
|
+
$CHILD_STATUS.success?
|
|
404
397
|
end
|
|
405
398
|
end
|
|
406
|
-
$CHILD_STATUS.success?
|
|
407
399
|
end
|
|
408
400
|
end
|
|
409
401
|
|
|
@@ -450,9 +442,7 @@ task :spec_clean do
|
|
|
450
442
|
|
|
451
443
|
Rake::Task[:spec_clean_symlinks].invoke
|
|
452
444
|
|
|
453
|
-
if File.
|
|
454
|
-
FileUtils.rm_f('spec/fixtures/manifests/site.pp')
|
|
455
|
-
end
|
|
445
|
+
FileUtils.rm_f('spec/fixtures/manifests/site.pp') if File.empty?('spec/fixtures/manifests/site.pp')
|
|
456
446
|
end
|
|
457
447
|
|
|
458
448
|
desc 'Clean up any fixture symlinks'
|