puppetlabs_spec_helper 2.6.2 → 4.0.1
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 +5 -5
- data/.github/dependabot.yml +15 -0
- data/.rspec +1 -1
- data/.rubocop.yml +114 -463
- data/.rubocop_todo.yml +119 -0
- data/.travis.yml +17 -16
- data/CHANGELOG.md +256 -5
- data/CODEOWNERS +2 -0
- data/Gemfile +32 -12
- data/HISTORY.md +498 -0
- data/README.md +130 -100
- data/Rakefile +37 -7
- data/lib/puppetlabs_spec_helper/module_spec_helper.rb +48 -1
- data/lib/puppetlabs_spec_helper/puppet_spec_helper.rb +32 -16
- data/lib/puppetlabs_spec_helper/puppetlabs_spec/files.rb +5 -3
- data/lib/puppetlabs_spec_helper/puppetlabs_spec/fixtures.rb +14 -10
- data/lib/puppetlabs_spec_helper/puppetlabs_spec/matchers.rb +12 -13
- data/lib/puppetlabs_spec_helper/puppetlabs_spec/puppet_internals.rb +20 -17
- data/lib/puppetlabs_spec_helper/puppetlabs_spec_helper.rb +3 -1
- data/lib/puppetlabs_spec_helper/rake_tasks.rb +252 -525
- data/lib/puppetlabs_spec_helper/tasks/check_symlinks.rb +52 -0
- data/lib/puppetlabs_spec_helper/tasks/fixtures.rb +462 -0
- data/lib/puppetlabs_spec_helper/version.rb +3 -1
- data/puppet_spec_helper.rb +3 -1
- data/puppetlabs_spec_helper.gemspec +26 -21
- data/puppetlabs_spec_helper.rb +3 -1
- metadata +75 -31
@@ -1,10 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'fileutils'
|
2
4
|
require 'rake'
|
3
5
|
require 'rspec/core/rake_task'
|
4
6
|
require 'tmpdir'
|
5
|
-
require 'yaml'
|
6
7
|
require 'pathname'
|
7
8
|
require 'puppetlabs_spec_helper/version'
|
9
|
+
require 'puppetlabs_spec_helper/tasks/fixtures'
|
10
|
+
require 'puppetlabs_spec_helper/tasks/check_symlinks'
|
11
|
+
require 'English'
|
8
12
|
|
9
13
|
# optional gems
|
10
14
|
begin
|
@@ -13,6 +17,24 @@ rescue LoadError
|
|
13
17
|
# ignore
|
14
18
|
end
|
15
19
|
|
20
|
+
begin
|
21
|
+
require 'puppet_blacksmith/rake_tasks'
|
22
|
+
rescue LoadError
|
23
|
+
# ignore
|
24
|
+
end
|
25
|
+
|
26
|
+
begin
|
27
|
+
require 'github_changelog_generator/task'
|
28
|
+
rescue LoadError
|
29
|
+
# ignore
|
30
|
+
end
|
31
|
+
|
32
|
+
begin
|
33
|
+
require 'puppet-strings/tasks'
|
34
|
+
rescue LoadError
|
35
|
+
# ignore
|
36
|
+
end
|
37
|
+
|
16
38
|
parallel_tests_loaded = false
|
17
39
|
begin
|
18
40
|
require 'parallel_tests'
|
@@ -21,535 +43,177 @@ rescue LoadError
|
|
21
43
|
# ignore
|
22
44
|
end
|
23
45
|
|
46
|
+
task default: [:help]
|
24
47
|
|
25
|
-
|
26
|
-
|
27
|
-
pattern = 'spec/{aliases,classes,defines,unit,functions,hosts,integration,type_aliases,types}/**/*_spec.rb'
|
48
|
+
pattern = 'spec/{aliases,classes,defines,functions,hosts,integration,plans,tasks,type_aliases,types,unit}/**/*_spec.rb'
|
28
49
|
|
29
50
|
RSpec::Core::RakeTask.new(:spec_standalone) do |t, args|
|
30
|
-
t.rspec_opts = [
|
51
|
+
t.rspec_opts = []
|
31
52
|
t.rspec_opts << ENV['CI_SPEC_OPTIONS'] unless ENV['CI_SPEC_OPTIONS'].nil?
|
32
53
|
if ENV['CI_NODE_TOTAL'] && ENV['CI_NODE_INDEX']
|
33
54
|
ci_total = ENV['CI_NODE_TOTAL'].to_i
|
34
55
|
ci_index = ENV['CI_NODE_INDEX'].to_i
|
35
56
|
raise "CI_NODE_INDEX must be between 1-#{ci_total}" unless ci_index >= 1 && ci_index <= ci_total
|
57
|
+
|
36
58
|
files = Rake::FileList[pattern].to_a
|
37
59
|
per_node = (files.size / ci_total.to_f).ceil
|
38
60
|
t.pattern = if args.extras.nil? || args.extras.empty?
|
39
61
|
files.each_slice(per_node).to_a[ci_index - 1] || files.first
|
40
62
|
else
|
41
|
-
args.extras.join(
|
63
|
+
args.extras.join(',')
|
42
64
|
end
|
43
65
|
else
|
44
|
-
if args.extras.nil? || args.extras.empty?
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
66
|
+
t.pattern = if args.extras.nil? || args.extras.empty?
|
67
|
+
pattern
|
68
|
+
else
|
69
|
+
args.extras.join(',')
|
70
|
+
end
|
49
71
|
end
|
50
72
|
end
|
51
73
|
|
52
|
-
desc
|
74
|
+
desc 'List spec tests in a JSON document'
|
53
75
|
RSpec::Core::RakeTask.new(:spec_list_json) do |t|
|
54
76
|
t.rspec_opts = ['--dry-run', '--format', 'json']
|
55
77
|
t.pattern = pattern
|
56
78
|
end
|
57
79
|
|
58
|
-
desc
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
raise 'TEST_TIERS env variable must have at least 1 tier specified. low, medium or high (comma separated).' if test_tiers.count == 0
|
67
|
-
test_tiers.each do |tier|
|
68
|
-
tier_to_add = tier.strip
|
69
|
-
raise "#{tier_to_add} not a valid test tier." unless %w(low medium high).include?(tier_to_add)
|
70
|
-
tiers += "tier_#{tier_to_add},"
|
71
|
-
end
|
72
|
-
tiers = tiers.chomp(',')
|
73
|
-
t.rspec_opts.push(tiers)
|
74
|
-
else
|
75
|
-
puts 'TEST_TIERS env variable not defined. Defaulting to run all tests.'
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
module PuppetlabsSpecHelper::RakeTasks
|
80
|
-
# This is a helper for the self-symlink entry of fixtures.yml
|
81
|
-
def source_dir
|
82
|
-
Dir.pwd
|
83
|
-
end
|
84
|
-
|
85
|
-
# cache the repositories and return a hash object
|
86
|
-
def repositories
|
87
|
-
unless @repositories
|
88
|
-
@repositories = fixtures('repositories')
|
89
|
-
end
|
90
|
-
@repositories
|
91
|
-
end
|
92
|
-
|
93
|
-
# get the array of Beaker set names
|
94
|
-
# @return [Array<String>]
|
95
|
-
def beaker_node_sets
|
96
|
-
return @beaker_nodes if @beaker_nodes
|
97
|
-
@beaker_nodes = Dir['spec/acceptance/nodesets/*.yml'].sort.map do |node_set|
|
98
|
-
node_set.slice!('.yml')
|
99
|
-
File.basename(node_set)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
# Use "vagrant ssh" to login to the given node in the node set
|
104
|
-
# @param set [String] The name of the node set (yml file)
|
105
|
-
# @param node [String] The name of the node in the set. For multi-node sets.
|
106
|
-
def vagrant_ssh(set, node = nil)
|
107
|
-
vagrant_yml_dir = File.join '.vagrant', 'beaker_vagrant_files', "#{set}.yml"
|
108
|
-
vagrant_file = File.join vagrant_yml_dir, 'Vagrantfile'
|
109
|
-
unless File.file? vagrant_file
|
110
|
-
puts "There is no Vagrantfile at: '#{vagrant_file}'. Perhaps, the node is not created or is destroyed."
|
111
|
-
exit 1
|
112
|
-
end
|
113
|
-
Dir.chdir(vagrant_yml_dir) do
|
114
|
-
command = 'vagrant ssh'
|
115
|
-
command += " #{node}" if node
|
116
|
-
# Vagrant is not distributed as a normal gem
|
117
|
-
# and we should protect it from the current Ruby environment
|
118
|
-
env = {
|
119
|
-
'RUBYLIB' => nil,
|
120
|
-
'GEM_PATH' => nil,
|
121
|
-
'BUNDLE_BIN_PATH' => nil,
|
122
|
-
}
|
123
|
-
system env, command
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def auto_symlink
|
128
|
-
{ File.basename(Dir.pwd).split('-').last => '#{source_dir}' }
|
129
|
-
end
|
130
|
-
|
131
|
-
def fixtures(category)
|
132
|
-
if ENV['FIXTURES_YML']
|
133
|
-
fixtures_yaml = ENV['FIXTURES_YML']
|
134
|
-
elsif File.exists?('.fixtures.yml')
|
135
|
-
fixtures_yaml = '.fixtures.yml'
|
136
|
-
elsif File.exists?('.fixtures.yaml')
|
137
|
-
fixtures_yaml = '.fixtures.yaml'
|
138
|
-
else
|
139
|
-
fixtures_yaml = false
|
140
|
-
end
|
141
|
-
|
142
|
-
begin
|
143
|
-
if fixtures_yaml
|
144
|
-
fixtures = YAML.load_file(fixtures_yaml) || { 'fixtures' => {} }
|
145
|
-
else
|
146
|
-
fixtures = { 'fixtures' => {} }
|
147
|
-
end
|
148
|
-
rescue Errno::ENOENT
|
149
|
-
fail("Fixtures file not found: '#{fixtures_yaml}'")
|
150
|
-
rescue Psych::SyntaxError => e
|
151
|
-
fail("Found malformed YAML in '#{fixtures_yaml}' on line #{e.line} column #{e.column}: #{e.problem}")
|
152
|
-
end
|
153
|
-
|
154
|
-
unless fixtures.include?('fixtures')
|
155
|
-
# File is non-empty, but does not specify fixtures
|
156
|
-
fail("No 'fixtures' entries found in '#{fixtures_yaml}'; required")
|
157
|
-
end
|
158
|
-
|
159
|
-
if fixtures.include? 'defaults'
|
160
|
-
fixture_defaults = fixtures['defaults']
|
161
|
-
else
|
162
|
-
fixture_defaults = {}
|
163
|
-
end
|
164
|
-
|
165
|
-
fixtures = fixtures['fixtures']
|
166
|
-
|
167
|
-
if fixtures['symlinks'].nil?
|
168
|
-
fixtures['symlinks'] = auto_symlink
|
169
|
-
end
|
170
|
-
|
171
|
-
result = {}
|
172
|
-
if fixtures.include? category and fixtures[category] != nil
|
173
|
-
|
174
|
-
defaults = { "target" => "spec/fixtures/modules" }
|
175
|
-
|
176
|
-
# load defaults from the `.fixtures.yml` `defaults` section
|
177
|
-
# for the requested category and merge them into my defaults
|
178
|
-
if fixture_defaults.include? category
|
179
|
-
defaults = defaults.merge(fixture_defaults[category])
|
180
|
-
end
|
181
|
-
|
182
|
-
fixtures[category].each do |fixture, opts|
|
183
|
-
# convert a simple string fixture to a hash, by
|
184
|
-
# using the string fixture as the `repo` option of the hash.
|
185
|
-
if opts.instance_of?(String)
|
186
|
-
opts = { "repo" => opts }
|
187
|
-
end
|
188
|
-
# there should be a warning or something if it's not a hash...
|
189
|
-
if opts.instance_of?(Hash)
|
190
|
-
# merge our options into the defaults to get the
|
191
|
-
# final option list
|
192
|
-
opts = defaults.merge(opts)
|
193
|
-
|
194
|
-
real_target = eval('"'+opts["target"]+'"')
|
195
|
-
real_source = eval('"'+opts["repo"]+'"')
|
196
|
-
|
197
|
-
result[real_source] = { "target" => File.join(real_target,fixture), "ref" => opts["ref"], "branch" => opts["branch"], "scm" => opts["scm"], "flags" => opts["flags"], "subdir" => opts["subdir"]}
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
201
|
-
return result
|
202
|
-
end
|
203
|
-
|
204
|
-
def clone_repo(scm, remote, target, subdir=nil, ref=nil, branch=nil, flags = nil)
|
205
|
-
args = []
|
206
|
-
case scm
|
207
|
-
when 'hg'
|
208
|
-
args.push('clone')
|
209
|
-
args.push('-b', branch) if branch
|
210
|
-
args.push(flags) if flags
|
211
|
-
args.push(remote, target)
|
212
|
-
when 'git'
|
213
|
-
args.push('clone')
|
214
|
-
args.push('--depth 1') unless ref
|
215
|
-
args.push('-b', branch) if branch
|
216
|
-
args.push(flags) if flags
|
217
|
-
args.push(remote, target)
|
218
|
-
else
|
219
|
-
fail "Unfortunately #{scm} is not supported yet"
|
220
|
-
end
|
221
|
-
result = system("#{scm} #{args.flatten.join ' '}")
|
222
|
-
unless File::exists?(target)
|
223
|
-
fail "Failed to clone #{scm} repository #{remote} into #{target}"
|
224
|
-
end
|
225
|
-
result
|
226
|
-
end
|
227
|
-
|
228
|
-
def revision(scm, target, ref)
|
229
|
-
args = []
|
230
|
-
case scm
|
231
|
-
when 'hg'
|
232
|
-
args.push('update', '--clean', '-r', ref)
|
233
|
-
when 'git'
|
234
|
-
args.push('reset', '--hard', ref)
|
235
|
-
else
|
236
|
-
fail "Unfortunately #{scm} is not supported yet"
|
237
|
-
end
|
238
|
-
system("cd #{target} && #{scm} #{args.flatten.join ' '}")
|
239
|
-
end
|
240
|
-
|
241
|
-
def remove_subdirectory(target, subdir)
|
242
|
-
unless subdir.nil?
|
243
|
-
Dir.mktmpdir {|tmpdir|
|
244
|
-
FileUtils.mv(Dir.glob("#{target}/#{subdir}/{.[^\.]*,*}"), tmpdir)
|
245
|
-
FileUtils.rm_rf("#{target}/#{subdir}")
|
246
|
-
FileUtils.mv(Dir.glob("#{tmpdir}/{.[^\.]*,*}"), "#{target}")
|
247
|
-
}
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
# creates a logger so we can log events with certain levels
|
252
|
-
def logger
|
253
|
-
unless @logger
|
254
|
-
require 'logger'
|
255
|
-
if ENV['ENABLE_LOGGER']
|
256
|
-
level = Logger::DEBUG
|
257
|
-
else
|
258
|
-
level = Logger::INFO
|
259
|
-
end
|
260
|
-
@logger = Logger.new(STDERR)
|
261
|
-
@logger.level = level
|
262
|
-
end
|
263
|
-
@logger
|
264
|
-
end
|
265
|
-
|
266
|
-
def module_working_directory
|
267
|
-
# The problem with the relative path is that PMT doesn't expand the path properly and so passing in a relative path here
|
268
|
-
# becomes something like C:\somewhere\backslashes/spec/fixtures/work-dir on Windows, and then PMT barfs itself.
|
269
|
-
# This has been reported as https://tickets.puppetlabs.com/browse/PUP-4884
|
270
|
-
File.expand_path(ENV['MODULE_WORKING_DIR'] ? ENV['MODULE_WORKING_DIR'] : 'spec/fixtures/work-dir')
|
271
|
-
end
|
272
|
-
|
273
|
-
# returns the current thread count that is currently active
|
274
|
-
# a status of false or nil means the thread completed
|
275
|
-
# so when anything else we count that as a active thread
|
276
|
-
def current_thread_count(items)
|
277
|
-
active_threads = items.find_all do |item, opts|
|
278
|
-
if opts[:thread]
|
279
|
-
opts[:thread].status
|
280
|
-
else
|
281
|
-
false
|
282
|
-
end
|
283
|
-
end
|
284
|
-
logger.debug "Current thread count #{active_threads.count}"
|
285
|
-
active_threads.count
|
286
|
-
end
|
287
|
-
|
288
|
-
# returns the max_thread_count
|
289
|
-
# because we may want to limit ssh or https connections
|
290
|
-
def max_thread_limit
|
291
|
-
unless @max_thread_limit
|
292
|
-
# the default thread count is 10 but can be
|
293
|
-
# raised by using environment variable MAX_FIXTURE_THREAD_COUNT
|
294
|
-
if ENV['MAX_FIXTURE_THREAD_COUNT'].to_i > 0
|
295
|
-
@max_thread_limit = ENV['MAX_FIXTURE_THREAD_COUNT'].to_i
|
296
|
-
else
|
297
|
-
@max_thread_limit = 10 # the default
|
298
|
-
end
|
299
|
-
end
|
300
|
-
@max_thread_limit
|
301
|
-
end
|
302
|
-
|
303
|
-
def check_directory_for_symlinks(dir='.')
|
304
|
-
dir = Pathname.new(dir) unless dir.is_a?(Pathname)
|
305
|
-
results = []
|
306
|
-
|
307
|
-
dir.each_child(true) do |child|
|
308
|
-
if child.symlink?
|
309
|
-
results << child
|
310
|
-
elsif child.directory? && child.basename.to_s != '.git'
|
311
|
-
results.concat(check_directory_for_symlinks(child))
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
results
|
316
|
-
end
|
317
|
-
end
|
318
|
-
include PuppetlabsSpecHelper::RakeTasks
|
319
|
-
|
320
|
-
desc "Create the fixtures directory"
|
321
|
-
task :spec_prep do
|
322
|
-
# Ruby only sets File::ALT_SEPARATOR on Windows and Rubys standard library
|
323
|
-
# uses this to check for Windows
|
324
|
-
is_windows = !!File::ALT_SEPARATOR
|
325
|
-
if is_windows
|
326
|
-
begin
|
327
|
-
require 'win32/dir'
|
328
|
-
rescue LoadError
|
329
|
-
$stderr.puts "win32-dir gem not installed, falling back to executing mklink directly"
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
# git has a race condition creating that directory, that would lead to aborted clone operations
|
334
|
-
FileUtils::mkdir_p("spec/fixtures/modules")
|
335
|
-
|
336
|
-
repositories.each do |remote, opts|
|
337
|
-
scm = 'git'
|
338
|
-
target = opts["target"]
|
339
|
-
subdir = opts["subdir"]
|
340
|
-
ref = opts["ref"]
|
341
|
-
scm = opts["scm"] if opts["scm"]
|
342
|
-
branch = opts["branch"] if opts["branch"]
|
343
|
-
flags = opts["flags"]
|
344
|
-
# get the current active threads that are alive
|
345
|
-
count = current_thread_count(repositories)
|
346
|
-
if count < max_thread_limit
|
347
|
-
logger.debug "New Thread started for #{remote}"
|
348
|
-
# start up a new thread and store it in the opts hash
|
349
|
-
opts[:thread] = Thread.new do
|
350
|
-
clone_repo(scm, remote, target, subdir, ref, branch, flags)
|
351
|
-
revision(scm, target, ref) if ref
|
352
|
-
remove_subdirectory(target, subdir) if subdir
|
353
|
-
end
|
354
|
-
else
|
355
|
-
# the last thread started should be the longest wait
|
356
|
-
item, item_opts = repositories.find_all {|i,o| o.has_key?(:thread)}.last
|
357
|
-
logger.debug "Waiting on #{item}"
|
358
|
-
item_opts[:thread].join # wait for the thread to finish
|
359
|
-
# now that we waited lets try again
|
360
|
-
redo
|
361
|
-
end
|
362
|
-
end
|
363
|
-
|
364
|
-
# wait for all the threads to finish
|
365
|
-
repositories.each {|remote, opts| opts[:thread].join }
|
366
|
-
|
367
|
-
fixtures("symlinks").each do |target, link|
|
368
|
-
link = link['target']
|
369
|
-
unless File.symlink?(link)
|
370
|
-
logger.info("Creating symlink from #{link} to #{target}")
|
371
|
-
if is_windows
|
372
|
-
target = File.join(File.dirname(link), target) unless Pathname.new(target).absolute?
|
373
|
-
if Dir.respond_to?(:create_junction)
|
374
|
-
Dir.create_junction(link, target)
|
375
|
-
else
|
376
|
-
system("call mklink /J \"#{link.gsub('/', '\\')}\" \"#{target.gsub('/', '\\')}\"")
|
377
|
-
end
|
378
|
-
else
|
379
|
-
FileUtils::ln_sf(target, link)
|
380
|
-
end
|
381
|
-
end
|
382
|
-
end
|
383
|
-
|
384
|
-
fixtures("forge_modules").each do |remote, opts|
|
385
|
-
ref = ""
|
386
|
-
flags = ""
|
387
|
-
if opts.instance_of?(String)
|
388
|
-
target = opts
|
389
|
-
elsif opts.instance_of?(Hash)
|
390
|
-
target = opts["target"]
|
391
|
-
ref = " --version #{opts['ref']}" if not opts['ref'].nil?
|
392
|
-
flags = " #{opts['flags']}" if opts['flags']
|
393
|
-
end
|
394
|
-
next if File::exists?(target)
|
395
|
-
|
396
|
-
working_dir = module_working_directory
|
397
|
-
target_dir = File.expand_path('spec/fixtures/modules')
|
398
|
-
|
399
|
-
command = "puppet module install" + ref + flags + \
|
400
|
-
" --ignore-dependencies" \
|
401
|
-
" --force" \
|
402
|
-
" --module_working_dir \"#{working_dir}\"" \
|
403
|
-
" --target-dir \"#{target_dir}\" \"#{remote}\""
|
404
|
-
|
405
|
-
unless system(command)
|
406
|
-
fail "Failed to install module #{remote} to #{target_dir}"
|
407
|
-
end
|
80
|
+
desc 'Run spec tests and clean the fixtures directory if successful'
|
81
|
+
task :spec do |_t, args|
|
82
|
+
begin
|
83
|
+
Rake::Task[:spec_prep].invoke
|
84
|
+
Rake::Task[:spec_standalone].invoke(*args.extras)
|
85
|
+
Rake::Task[:spec_clean].invoke
|
86
|
+
ensure
|
87
|
+
Rake::Task[:spec_clean_symlinks].invoke
|
408
88
|
end
|
409
|
-
|
410
|
-
FileUtils::mkdir_p("spec/fixtures/manifests")
|
411
|
-
FileUtils::touch("spec/fixtures/manifests/site.pp")
|
412
89
|
end
|
413
90
|
|
414
|
-
desc
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
91
|
+
desc 'Run spec tests with ruby simplecov code coverage'
|
92
|
+
namespace :spec do
|
93
|
+
task :simplecov do
|
94
|
+
ENV['SIMPLECOV'] = 'yes'
|
95
|
+
Rake::Task['spec'].execute
|
419
96
|
end
|
420
|
-
|
421
|
-
fixtures("forge_modules").each do |remote, opts|
|
422
|
-
target = opts["target"]
|
423
|
-
FileUtils::rm_rf(target)
|
424
|
-
end
|
425
|
-
|
426
|
-
FileUtils::rm_rf(module_working_directory)
|
427
|
-
|
428
|
-
fixtures("symlinks").each do |source, opts|
|
429
|
-
target = opts["target"]
|
430
|
-
FileUtils::rm_f(target)
|
431
|
-
end
|
432
|
-
|
433
|
-
if File.zero?("spec/fixtures/manifests/site.pp")
|
434
|
-
FileUtils::rm_f("spec/fixtures/manifests/site.pp")
|
435
|
-
end
|
436
|
-
|
437
97
|
end
|
438
98
|
|
439
|
-
desc
|
440
|
-
task :
|
99
|
+
desc 'Run spec tests in parallel and clean the fixtures directory if successful'
|
100
|
+
task :parallel_spec do |_t, args|
|
441
101
|
begin
|
442
102
|
Rake::Task[:spec_prep].invoke
|
443
|
-
Rake::Task[:
|
444
|
-
ensure
|
103
|
+
Rake::Task[:parallel_spec_standalone].invoke(*args.extras)
|
445
104
|
Rake::Task[:spec_clean].invoke
|
105
|
+
ensure
|
106
|
+
Rake::Task[:spec_clean_symlinks].invoke
|
446
107
|
end
|
447
108
|
end
|
448
109
|
|
449
|
-
desc
|
450
|
-
task :
|
110
|
+
desc 'Parallel spec tests'
|
111
|
+
task :parallel_spec_standalone do |_t, args|
|
451
112
|
raise 'Add the parallel_tests gem to Gemfile to enable this task' unless parallel_tests_loaded
|
113
|
+
|
452
114
|
if Rake::FileList[pattern].to_a.empty?
|
453
|
-
warn
|
115
|
+
warn 'No files for parallel_spec to run against'
|
454
116
|
else
|
455
|
-
begin
|
456
|
-
args = ['-t', 'rspec']
|
457
|
-
args.push('--').concat(ENV['CI_SPEC_OPTIONS'].strip.split(' ')).push('--') unless ENV['CI_SPEC_OPTIONS'].nil? || ENV['CI_SPEC_OPTIONS'].strip.empty?
|
458
|
-
args.concat(Rake::FileList[pattern].to_a)
|
459
|
-
|
460
|
-
Rake::Task[:spec_prep].invoke
|
461
|
-
ParallelTests::CLI.new.run(args)
|
462
|
-
ensure
|
463
|
-
Rake::Task[:spec_clean].invoke
|
464
|
-
end
|
465
|
-
end
|
466
|
-
end
|
467
117
|
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
puts set
|
472
|
-
end
|
473
|
-
end
|
474
|
-
|
475
|
-
# alias for compatibility
|
476
|
-
task 'beaker_nodes' => 'beaker:sets'
|
118
|
+
args = ['-t', 'rspec']
|
119
|
+
args.push('--').concat(ENV['CI_SPEC_OPTIONS'].strip.split(' ')).push('--') unless ENV['CI_SPEC_OPTIONS'].nil? || ENV['CI_SPEC_OPTIONS'].strip.empty?
|
120
|
+
args.concat(Rake::FileList[pattern].to_a)
|
477
121
|
|
478
|
-
|
479
|
-
task 'beaker:ssh', [:set, :node] do |_task, args|
|
480
|
-
set = args[:set] || ENV['BEAKER_set'] || ENV['RS_SET'] || 'default'
|
481
|
-
node = args[:node]
|
482
|
-
vagrant_ssh set, node
|
483
|
-
end
|
122
|
+
ParallelTests::CLI.new.run(args)
|
484
123
|
|
485
|
-
beaker_node_sets.each do |set|
|
486
|
-
desc "Run the Beaker acceptance tests for the node set '#{set}'"
|
487
|
-
task "beaker:#{set}" do
|
488
|
-
ENV['BEAKER_set'] = set
|
489
|
-
Rake::Task['beaker'].reenable
|
490
|
-
Rake::Task['beaker'].invoke
|
491
124
|
end
|
125
|
+
end
|
492
126
|
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
127
|
+
desc 'Build puppet module package'
|
128
|
+
task :build do
|
129
|
+
if Gem::Specification.find_by_name('puppet').version < Gem::Version.new('6.0.0')
|
130
|
+
Rake::Task['build:pmt'].invoke
|
131
|
+
else
|
132
|
+
Rake::Task['build:pdk'].invoke
|
497
133
|
end
|
498
134
|
end
|
499
135
|
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
begin
|
504
|
-
Gem::Specification.find_by_name('puppet-module')
|
505
|
-
rescue Gem::LoadError, NoMethodError
|
136
|
+
namespace :build do
|
137
|
+
desc 'Build Puppet module package with PMT (Puppet < 6.0.0 only)'
|
138
|
+
task :pmt do
|
506
139
|
require 'puppet/face'
|
140
|
+
|
507
141
|
pmod = Puppet::Face['module', :current]
|
508
142
|
pmod.build('./')
|
509
143
|
end
|
144
|
+
|
145
|
+
desc 'Build Puppet module with PDK'
|
146
|
+
task :pdk do
|
147
|
+
begin
|
148
|
+
require 'pdk/util'
|
149
|
+
require 'pdk/module/build'
|
150
|
+
|
151
|
+
path = PDK::Module::Build.invoke(force: true, 'target-dir': File.join(Dir.pwd, 'pkg'))
|
152
|
+
puts "Module built: #{path}"
|
153
|
+
rescue LoadError
|
154
|
+
_ = `pdk --version`
|
155
|
+
unless $CHILD_STATUS.success?
|
156
|
+
warn 'Unable to build module. Please install PDK or add the `pdk` gem to your Gemfile.'
|
157
|
+
abort
|
158
|
+
end
|
159
|
+
|
160
|
+
system('pdk build --force')
|
161
|
+
end
|
162
|
+
end
|
510
163
|
end
|
511
164
|
|
512
|
-
desc
|
165
|
+
desc 'Clean a built module package'
|
513
166
|
task :clean do
|
514
|
-
FileUtils.rm_rf(
|
167
|
+
FileUtils.rm_rf('pkg/')
|
515
168
|
end
|
516
169
|
|
517
170
|
require 'puppet-lint/tasks/puppet-lint'
|
518
171
|
# Must clear as it will not override the existing puppet-lint rake task since we require to import for
|
519
172
|
# the PuppetLint::RakeTask
|
520
173
|
Rake::Task[:lint].clear
|
521
|
-
#
|
174
|
+
# Utilize PuppetLint global configuration so that these settings can be tweaked by
|
175
|
+
# spec_helper.rb in an individual module
|
522
176
|
PuppetLint.configuration.relative = true
|
523
|
-
PuppetLint
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
177
|
+
PuppetLint.configuration.ignore_paths ||= []
|
178
|
+
PuppetLint.configuration.ignore_paths << '.vendor/**/*.pp'
|
179
|
+
PuppetLint.configuration.ignore_paths << 'bundle/**/*.pp'
|
180
|
+
PuppetLint.configuration.ignore_paths << 'pkg/**/*.pp'
|
181
|
+
PuppetLint.configuration.ignore_paths << 'spec/**/*.pp'
|
182
|
+
PuppetLint.configuration.ignore_paths << 'tests/**/*.pp'
|
183
|
+
PuppetLint.configuration.ignore_paths << 'types/**/*.pp'
|
184
|
+
PuppetLint.configuration.ignore_paths << 'vendor/**/*.pp'
|
185
|
+
puppet_lint_disable_checks = %w[
|
186
|
+
80chars
|
187
|
+
140chars
|
188
|
+
class_inherits_from_params_class
|
189
|
+
class_parameter_defaults
|
190
|
+
disable_autoloader_layout
|
191
|
+
documentation
|
192
|
+
single_quote_string_with_variables
|
193
|
+
]
|
194
|
+
puppet_lint_disable_checks.each do |check|
|
195
|
+
PuppetLint.configuration.send("disable_#{check}")
|
196
|
+
end
|
197
|
+
PuppetLint::RakeTask.new(:lint)
|
198
|
+
|
199
|
+
desc 'Run puppet-lint and fix issues automatically'
|
200
|
+
PuppetLint::RakeTask.new(:lint_fix) do |config|
|
201
|
+
config.fix = true
|
540
202
|
end
|
541
203
|
|
542
204
|
require 'puppet-syntax/tasks/puppet-syntax'
|
543
205
|
PuppetSyntax.exclude_paths ||= []
|
544
|
-
PuppetSyntax.exclude_paths <<
|
545
|
-
PuppetSyntax.exclude_paths <<
|
546
|
-
PuppetSyntax.exclude_paths <<
|
206
|
+
PuppetSyntax.exclude_paths << 'spec/fixtures/**/*'
|
207
|
+
PuppetSyntax.exclude_paths << 'pkg/**/*'
|
208
|
+
PuppetSyntax.exclude_paths << 'vendor/**/*'
|
209
|
+
PuppetSyntax.exclude_paths << '.vendor/**/*'
|
210
|
+
PuppetSyntax.exclude_paths << 'plans/**/*'
|
547
211
|
if Puppet.version.to_f < 4.0
|
548
|
-
PuppetSyntax.exclude_paths <<
|
212
|
+
PuppetSyntax.exclude_paths << 'types/**/*'
|
549
213
|
end
|
550
214
|
PuppetSyntax.future_parser = true if ENV['FUTURE_PARSER'] == 'yes'
|
551
215
|
|
552
|
-
desc
|
216
|
+
desc 'Check syntax of Ruby files and call :syntax and :metadata_lint'
|
553
217
|
task :validate do
|
554
218
|
Dir['lib/**/*.rb'].each do |lib_file|
|
555
219
|
sh "ruby -c #{lib_file}"
|
@@ -560,7 +224,7 @@ task :validate do
|
|
560
224
|
if Rake::Task.task_defined?(:metadata_lint)
|
561
225
|
Rake::Task[:metadata_lint].invoke
|
562
226
|
else
|
563
|
-
warn
|
227
|
+
warn 'Skipping metadata validation; the metadata-json-lint gem was not found'
|
564
228
|
end
|
565
229
|
end
|
566
230
|
end
|
@@ -570,23 +234,23 @@ task :metadata do
|
|
570
234
|
if Rake::Task.task_defined?(:metadata_lint)
|
571
235
|
Rake::Task[:metadata_lint].invoke
|
572
236
|
else
|
573
|
-
warn
|
237
|
+
warn 'Skipping metadata validation; the metadata-json-lint gem was not found'
|
574
238
|
end
|
575
239
|
end
|
576
240
|
|
577
|
-
desc
|
241
|
+
desc 'Print development version of module'
|
578
242
|
task :compute_dev_version do
|
579
243
|
version = ''
|
580
|
-
if File.
|
244
|
+
if File.exist?('metadata.json')
|
581
245
|
require 'json'
|
582
246
|
|
583
|
-
modinfo = JSON.parse(File.read(
|
247
|
+
modinfo = JSON.parse(File.read('metadata.json'))
|
584
248
|
version = modinfo['version']
|
585
|
-
elsif File.
|
249
|
+
elsif File.exist?('Modulefile')
|
586
250
|
modfile = File.read('Modulefile')
|
587
|
-
version = modfile.match(
|
251
|
+
version = modfile.match(%r{\nversion +['"](.*)['"]})[1]
|
588
252
|
else
|
589
|
-
|
253
|
+
raise 'Could not find a metadata.json or Modulefile! Cannot compute dev version without one or the other!'
|
590
254
|
end
|
591
255
|
|
592
256
|
sha = `git rev-parse HEAD`[0..7]
|
@@ -594,22 +258,22 @@ task :compute_dev_version do
|
|
594
258
|
|
595
259
|
# If we're in a CI environment include our build number
|
596
260
|
# If the branch is a release branch we append an 'r' into the new_version,
|
597
|
-
# this is due to the release branch buildID conflicting with
|
261
|
+
# this is due to the release branch buildID conflicting with main branch when trying to push to the staging forge.
|
598
262
|
# More info can be found at https://tickets.puppetlabs.com/browse/FM-6170
|
599
|
-
if build = ENV['BUILD_NUMBER'] || ENV['TRAVIS_BUILD_NUMBER']
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
263
|
+
new_version = if build = (ENV['BUILD_NUMBER'] || ENV['TRAVIS_BUILD_NUMBER'])
|
264
|
+
if branch.eql? 'release'
|
265
|
+
'%s-%s%04d-%s' % [version, 'r', build, sha] # legacy support code # rubocop:disable Style/FormatStringToken
|
266
|
+
else
|
267
|
+
'%s-%04d-%s' % [version, build, sha] # legacy support code # rubocop:disable Style/FormatStringToken
|
268
|
+
end
|
269
|
+
else
|
270
|
+
"#{version}-#{sha}"
|
271
|
+
end
|
608
272
|
|
609
273
|
print new_version
|
610
274
|
end
|
611
275
|
|
612
|
-
desc
|
276
|
+
desc 'Runs all necessary checks on a module in preparation for a release'
|
613
277
|
task :release_checks do
|
614
278
|
Rake::Task[:lint].invoke
|
615
279
|
Rake::Task[:validate].invoke
|
@@ -618,56 +282,53 @@ task :release_checks do
|
|
618
282
|
else
|
619
283
|
Rake::Task[:spec].invoke
|
620
284
|
end
|
621
|
-
Rake::Task[
|
622
|
-
Rake::Task["check:test_file"].invoke
|
623
|
-
Rake::Task["check:dot_underscore"].invoke
|
624
|
-
Rake::Task["check:git_ignore"].invoke
|
285
|
+
Rake::Task[:check].invoke
|
625
286
|
end
|
626
287
|
|
627
288
|
namespace :check do
|
628
|
-
desc
|
289
|
+
desc 'Fails if symlinks are present in directory'
|
629
290
|
task :symlinks do
|
630
|
-
symlinks =
|
291
|
+
symlinks = PuppetlabsSpecHelper::Tasks::CheckSymlinks.new.check
|
631
292
|
unless symlinks.empty?
|
632
|
-
symlinks.each { |r| puts "Symlink found: #{r
|
633
|
-
|
293
|
+
symlinks.each { |r| puts "Symlink found: #{r} => #{r.readlink}" }
|
294
|
+
raise 'Symlink(s) exist within this directory'
|
634
295
|
end
|
635
296
|
end
|
636
297
|
|
637
|
-
desc
|
298
|
+
desc 'Fails if .pp files present in tests folder'
|
638
299
|
task :test_file do
|
639
|
-
|
640
|
-
|
641
|
-
ppfiles
|
642
|
-
|
643
|
-
puts ppfiles
|
644
|
-
fail ".pp files present in tests folder; Move them to an examples folder following the new convention"
|
645
|
-
end
|
300
|
+
ppfiles = Dir[File.join('tests', '**', '*.pp')]
|
301
|
+
unless ppfiles.empty?
|
302
|
+
puts ppfiles
|
303
|
+
raise '.pp files present in tests folder; Move them to an examples folder following the new convention'
|
646
304
|
end
|
647
305
|
end
|
648
306
|
|
649
|
-
desc
|
307
|
+
desc 'Fails if any ._ files are present in directory'
|
650
308
|
task :dot_underscore do
|
651
|
-
dirs = Dir[
|
309
|
+
dirs = Dir['._*']
|
652
310
|
unless dirs.empty?
|
653
311
|
puts dirs
|
654
|
-
|
312
|
+
raise '._ files are present in the directory'
|
655
313
|
end
|
656
314
|
end
|
657
315
|
|
658
|
-
desc
|
316
|
+
desc 'Fails if directories contain the files specified in .gitignore'
|
659
317
|
task :git_ignore do
|
660
318
|
matched = `git ls-files --ignored --exclude-standard`
|
661
|
-
unless matched ==
|
319
|
+
unless matched == ''
|
662
320
|
puts matched
|
663
|
-
|
321
|
+
raise 'File specified in .gitignore has been committed'
|
664
322
|
end
|
665
323
|
end
|
666
324
|
end
|
667
325
|
|
668
|
-
desc
|
326
|
+
desc 'Run static pre release checks'
|
327
|
+
task check: ['check:symlinks', 'check:test_file', 'check:dot_underscore', 'check:git_ignore']
|
328
|
+
|
329
|
+
desc 'Display the list of available rake tasks'
|
669
330
|
task :help do
|
670
|
-
system(
|
331
|
+
system('rake -T')
|
671
332
|
end
|
672
333
|
|
673
334
|
begin
|
@@ -675,33 +336,99 @@ begin
|
|
675
336
|
RuboCop::RakeTask.new(:rubocop) do |task|
|
676
337
|
# These make the rubocop experience maybe slightly less terrible
|
677
338
|
task.options = ['-D', '-S', '-E']
|
339
|
+
|
340
|
+
# Use Rubocop's Github Actions formatter if possible
|
341
|
+
if ENV['GITHUB_ACTIONS'] == 'true'
|
342
|
+
rubocop_spec = Gem::Specification.find_by_name('rubocop')
|
343
|
+
if Gem::Version.new(rubocop_spec.version) >= Gem::Version.new('1.2')
|
344
|
+
task.formatters << 'github'
|
345
|
+
end
|
346
|
+
end
|
678
347
|
end
|
679
348
|
rescue LoadError
|
680
|
-
desc
|
349
|
+
desc 'rubocop is not available in this installation'
|
681
350
|
task :rubocop do
|
682
|
-
|
351
|
+
raise 'rubocop is not available in this installation'
|
683
352
|
end
|
684
353
|
end
|
685
354
|
|
686
|
-
|
687
|
-
|
688
|
-
#
|
689
|
-
#
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
355
|
+
def create_gch_task(changelog_user = nil, changelog_project = nil, changelog_since_tag = nil, changelog_tag_pattern = 'v%s')
|
356
|
+
if Bundler.rubygems.find_name('github_changelog_generator').any?
|
357
|
+
# needed a place to hide these methods
|
358
|
+
# rubocop:disable Lint/NestedMethodDefinition
|
359
|
+
def changelog_user_from_metadata
|
360
|
+
result = JSON.parse(File.read('metadata.json'))['author']
|
361
|
+
raise 'unable to find the changelog_user in .sync.yml, or the author in metadata.json' if result.nil?
|
362
|
+
|
363
|
+
puts "GitHubChangelogGenerator user:#{result}"
|
364
|
+
result
|
365
|
+
end
|
366
|
+
|
367
|
+
def changelog_project_from_metadata
|
368
|
+
result = JSON.parse(File.read('metadata.json'))['name']
|
369
|
+
raise 'unable to find the changelog_project in .sync.yml or the name in metadata.json' if result.nil?
|
370
|
+
|
371
|
+
puts "GitHubChangelogGenerator project:#{result}"
|
372
|
+
result
|
373
|
+
end
|
374
|
+
|
375
|
+
def changelog_future_release
|
376
|
+
return unless Rake.application.top_level_tasks.include? 'changelog'
|
377
|
+
|
378
|
+
result = JSON.parse(File.read('metadata.json'))['version']
|
379
|
+
raise 'unable to find the future_release (version) in metadata.json' if result.nil?
|
380
|
+
|
381
|
+
puts "GitHubChangelogGenerator future_release:#{result}"
|
382
|
+
result
|
383
|
+
end
|
384
|
+
# rubocop:enable Lint/NestedMethodDefinition
|
385
|
+
|
386
|
+
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
387
|
+
if ENV['CHANGELOG_GITHUB_TOKEN'].nil?
|
388
|
+
raise "Set CHANGELOG_GITHUB_TOKEN environment variable eg 'export CHANGELOG_GITHUB_TOKEN=valid_token_here'"
|
702
389
|
end
|
390
|
+
|
391
|
+
config.user = changelog_user || changelog_user_from_metadata
|
392
|
+
config.project = changelog_project || changelog_project_from_metadata
|
393
|
+
config.since_tag = changelog_since_tag if changelog_since_tag
|
394
|
+
config.future_release = changelog_tag_pattern % changelog_future_release.to_s
|
395
|
+
config.exclude_labels = ['maintenance']
|
396
|
+
config.header = "# Change log\n\nAll notable changes to this project will be documented in this file. " \
|
397
|
+
'The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres ' \
|
398
|
+
'to [Semantic Versioning](https://semver.org).'
|
399
|
+
config.add_pr_wo_labels = true
|
400
|
+
config.issues = false
|
401
|
+
config.merge_prefix = '### UNCATEGORIZED PRS; GO LABEL THEM'
|
402
|
+
config.configure_sections = {
|
403
|
+
'Changed' => {
|
404
|
+
'prefix' => '### Changed',
|
405
|
+
'labels' => ['backwards-incompatible'],
|
406
|
+
},
|
407
|
+
'Added' => {
|
408
|
+
'prefix' => '### Added',
|
409
|
+
'labels' => %w[feature enhancement],
|
410
|
+
},
|
411
|
+
'Fixed' => {
|
412
|
+
'prefix' => '### Fixed',
|
413
|
+
'labels' => ['bugfix'],
|
414
|
+
},
|
415
|
+
}
|
416
|
+
end
|
417
|
+
else
|
418
|
+
desc 'Generate a Changelog from GitHub'
|
419
|
+
task :changelog do
|
420
|
+
raise <<~MESSAGE
|
421
|
+
The changelog tasks depends on unreleased features of the github_changelog_generator gem.
|
422
|
+
Please manually add it to your .sync.yml for now, and run `pdk update`:
|
423
|
+
---
|
424
|
+
Gemfile:
|
425
|
+
optional:
|
426
|
+
':development':
|
427
|
+
- gem: 'github_changelog_generator'
|
428
|
+
git: 'https://github.com/skywinder/github-changelog-generator'
|
429
|
+
ref: '20ee04ba1234e9e83eb2ffb5056e23d641c7a018'
|
430
|
+
condition: "Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.2.2')"
|
431
|
+
MESSAGE
|
703
432
|
end
|
704
|
-
rescue Gem::LoadError
|
705
|
-
puts "No gettext-setup gem found, skipping GettextSetup config initialization" if Rake.verbose == true
|
706
433
|
end
|
707
434
|
end
|