onceover 3.19.2 → 3.21.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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/devcontainer.json +33 -0
  3. data/.github/workflows/tests.yaml +5 -8
  4. data/.gitignore +0 -1
  5. data/.rubocop.yml +1 -1
  6. data/.vscode/extensions.json +4 -0
  7. data/Gemfile +9 -0
  8. data/README.md +83 -2
  9. data/Rakefile +15 -1
  10. data/factsets/Windows_Server-2008r2-64.json +184 -184
  11. data/factsets/Windows_Server-2012r2-64.json +165 -165
  12. data/factsets/windows-10-64.json +104 -104
  13. data/features/factsets.feature +33 -4
  14. data/features/step_definitions/common.rb +6 -0
  15. data/features/zzz_run.feature +8 -7
  16. data/lib/onceover/cli/run.rb +1 -0
  17. data/lib/onceover/cli/show.rb +1 -1
  18. data/lib/onceover/controlrepo.rb +64 -32
  19. data/lib/onceover/deploy.rb +6 -3
  20. data/lib/onceover/node.rb +19 -2
  21. data/lib/onceover/runner.rb +1 -0
  22. data/lib/onceover/testconfig.rb +4 -2
  23. data/onceover.gemspec +4 -2
  24. data/spec/fixtures/controlrepos/caching/Puppetfile +17 -17
  25. data/spec/fixtures/controlrepos/factsets/site/role/manifests/trusted_extensions.pp +6 -0
  26. data/spec/fixtures/controlrepos/factsets/site/role/manifests/trusted_external.pp +6 -0
  27. data/spec/fixtures/controlrepos/factsets/spec/factsets/README.md +7 -0
  28. data/spec/fixtures/controlrepos/factsets/spec/factsets/centos7_notrusted.json +530 -0
  29. data/spec/fixtures/controlrepos/factsets/spec/factsets/centos7_trusted_extensions_nested.json +535 -0
  30. data/spec/fixtures/controlrepos/factsets/spec/factsets/centos7_trusted_extensions_top.json +533 -0
  31. data/spec/fixtures/controlrepos/factsets/spec/factsets/centos7_trusted_external_nested.json +537 -0
  32. data/spec/fixtures/controlrepos/factsets/spec/factsets/centos7_trusted_external_top.json +535 -0
  33. data/templates/test_spec.rb.erb +4 -0
  34. metadata +22 -13
@@ -56,7 +56,7 @@ Useful for debugging.
56
56
  summary 'Shows the current state of the puppetfile'
57
57
  description <<-DESCRIPTION
58
58
  Shows the state of the puppetfile including current versions and
59
- laetst versions of each module. Great for checking for updates.
59
+ latest versions of each module. Great for checking for updates.
60
60
  To update all modules run `onceover update puppetfile`. (Hint: once
61
61
  you have done the update, run the tests to make sure nothing breaks.)
62
62
  DESCRIPTION
@@ -76,6 +76,10 @@ class Onceover
76
76
  @@existing_controlrepo.facts(filter, 'trusted')
77
77
  end
78
78
 
79
+ def self.trusted_external_facts(filter = nil)
80
+ @@existing_controlrepo.facts(filter, 'trusted_external')
81
+ end
82
+
79
83
  def self.hiera_config_file
80
84
  @@existing_controlrepo.hiera_config_file
81
85
  end
@@ -228,46 +232,74 @@ class Onceover
228
232
 
229
233
  output_array = []
230
234
  threads = []
235
+ error_array = []
231
236
  puppetfile.modules.each do |mod|
232
237
  threads << Thread.new do
233
- row = []
234
- logger.debug "Loading data for #{mod.full_name}"
235
- row << mod.full_name
236
- if mod.is_a?(R10K::Module::Forge)
237
- row << mod.expected_version
238
- row << mod.v3_module.current_release.version
239
-
240
- current = Versionomy.parse(mod.expected_version)
241
- latest = Versionomy.parse(mod.v3_module.current_release.version)
242
- row << if current.major < latest.major
243
- "Major".red
244
- elsif current.minor < latest.minor
245
- "Minor".yellow
246
- elsif current.tiny < latest.tiny
247
- "Tiny".green
248
- else
249
- "No".green
250
- end
251
-
252
- row << mod.v3_module.endorsement
253
- superseded_by = mod.v3_module.superseded_by
254
- row << (superseded_by.nil? ? '' : superseded_by[:slug])
255
- else
256
- row << "N/A"
257
- row << "N/A"
258
- row << "N/A"
259
- row << "N/A"
260
- row << "N/A"
238
+ begin
239
+ row = []
240
+ logger.debug "Loading data for #{mod.full_name}"
241
+ row << mod.full_name
242
+ if mod.is_a?(R10K::Module::Forge)
243
+ row << mod.expected_version
244
+ row << mod.v3_module.current_release.version
245
+
246
+ # Configure a custom version format to support modern Puppet Forge versions.
247
+ # (major.minor.tiny-patchlevel-patchlevel_minor)
248
+ # e.g. 8.5.0-0-2
249
+ puppetforge_format = Versionomy.default_format.modified_copy do
250
+ field(:patchlevel_minor) do
251
+ recognize_number(:default_value_optional => true,
252
+ :delimiter_regexp => '-',
253
+ :default_delimiter => '-')
254
+ end
255
+ end
256
+
257
+ current = puppetforge_format.parse(mod.expected_version)
258
+ latest = puppetforge_format.parse(mod.v3_module.current_release.version)
259
+ row << if current.major < latest.major
260
+ "Major".red
261
+ elsif current.minor < latest.minor
262
+ "Minor".yellow
263
+ elsif current.tiny < latest.tiny
264
+ "Tiny".green
265
+ elsif current.patchlevel < latest.patchlevel
266
+ "PatchLevel".green
267
+ elsif current.patchlevel_minor < latest.patchlevel_minor
268
+ "PatchLevel_minor".green
269
+ else
270
+ "No".green
271
+ end
272
+
273
+ row << mod.v3_module.endorsement
274
+ superseded_by = mod.v3_module.superseded_by
275
+ row << (superseded_by.nil? ? '' : superseded_by[:slug])
276
+ else
277
+ row << "N/A"
278
+ row << "N/A"
279
+ row << "N/A"
280
+ row << "N/A"
281
+ row << "N/A"
282
+ end
283
+ output_array << row
284
+ rescue RuntimeError => e
285
+ error = []
286
+ error << mod.full_name
287
+ error << mod.expected_version
288
+ error << mod.v3_module.current_release.version
289
+ error << e.message
290
+ error_array << error
291
+ logger.debug "Error loading module #{mod.full_name} - #{e.inspect}"
292
+ end
261
293
  end
262
- output_array << row
263
294
  end
264
- end
265
295
 
266
296
  threads.map(&:join)
267
297
 
268
298
  output_array.sort_by! { |line| line[0] }
299
+ error_array.sort_by! { |line| line[0] } unless error_array.empty?
269
300
 
270
301
  puts Terminal::Table.new(headings: ["Full Name", "Current Version", "Latest Version", "Out of Date?", "Endorsement", "Superseded by"], rows: output_array)
302
+ puts Terminal::Table.new(headings: ["Issue assessing module", "Current", "Latest", "Error"], rows: error_array) unless error_array.empty?
271
303
  end
272
304
 
273
305
  def update_puppetfile
@@ -571,7 +603,7 @@ class Onceover
571
603
  else
572
604
  template = File.read(File.expand_path("./#{template_name}", template_dir))
573
605
  end
574
- ERB.new(template, nil, '-').result(bind)
606
+ ERB.new(template, trim_mode: '-').result(bind)
575
607
  end
576
608
 
577
609
  def self.init_write_file(contents, out_file)
@@ -596,7 +628,7 @@ class Onceover
596
628
 
597
629
  # Loop over each test, executing the user's block on each
598
630
  tests.each do |tst|
599
- block.call(tst.classes[0].name, tst.nodes[0].name, tst.nodes[0].fact_set, testconfig.pre_condition)
631
+ block.call(tst.classes[0].name, tst.nodes[0].name, tst.nodes[0].fact_set, tst.nodes[0].trusted_set, tst.nodes[0].trusted_external_set, testconfig.pre_condition)
600
632
  end
601
633
  end
602
634
 
@@ -86,9 +86,12 @@ class Onceover
86
86
  FileUtils.copy repo.puppetfile, "#{temp_controlrepo}/Puppetfile"
87
87
  puppetfile_contents = File.read("#{temp_controlrepo}/Puppetfile")
88
88
 
89
- logger.debug "replacing :control_branch mentions in the Puppetfile with #{git_branch}"
90
- new_puppetfile_contents = puppetfile_contents.gsub(/:control_branch/, "'#{git_branch}'")
91
- File.write("#{temp_controlrepo}/Puppetfile", new_puppetfile_contents)
89
+ # Avoid touching thing if we don't need to
90
+ if /:control_branch/.match(puppetfile_contents)
91
+ logger.debug "replacing :control_branch mentions in the Puppetfile with #{git_branch}"
92
+ new_puppetfile_contents = puppetfile_contents.gsub(/:control_branch/, "'#{git_branch}'")
93
+ File.write("#{temp_controlrepo}/Puppetfile", new_puppetfile_contents)
94
+ end
92
95
  end
93
96
 
94
97
  # Remove all files written by the last onceover run, but not the ones
data/lib/onceover/node.rb CHANGED
@@ -9,6 +9,7 @@ class Onceover
9
9
  attr_accessor :beaker_node
10
10
  attr_accessor :fact_set
11
11
  attr_accessor :trusted_set
12
+ attr_accessor :trusted_external_set
12
13
 
13
14
  def initialize(name)
14
15
  @name = name
@@ -20,10 +21,26 @@ class Onceover
20
21
  File.basename(facts_file, '.json') == name
21
22
  }
22
23
  @fact_set = Onceover::Node.clean_facts(Onceover::Controlrepo.facts[facts_file_index])
24
+
25
+ # First see if we can find a 'trusted' hash at the top level of our factset
23
26
  @trusted_set = Onceover::Controlrepo.trusted_facts[facts_file_index]
27
+ # If we don't find it, attempt to find a 'trusted.extensions' hash nested in our fact_set
28
+ @trusted_set = @fact_set.dig('trusted', 'extensions') if @trusted_set.nil?
29
+ # If we still can't find any, return an empty hash so the following doesn't blow up user written tests:
30
+ # let(:trusted_facts) { trusted_facts }
31
+ @trusted_set = {} if @trusted_set.nil?
32
+
33
+ # First see if we can find a 'trusted_external' hash at the top level of our factset
34
+ @trusted_external_set = Onceover::Controlrepo.trusted_external_facts[facts_file_index]
35
+ # If we don't find it, attempt to find a 'trusted.external' hash nested in our fact_set
36
+ @trusted_external_set = @fact_set.dig('trusted', 'external') if @trusted_external_set.nil?
37
+ # If we still can't find any, return an empty hash so the following doesn't blow up user written tests:
38
+ # let(:trusted_external_data) { trusted_external_data }
39
+ @trusted_external_set = {} if @trusted_external_set.nil?
24
40
  rescue TypeError
25
- @fact_set = nil
26
- @trusted_set = nil
41
+ @fact_set = {}
42
+ @trusted_set = {}
43
+ @trusted_external_set = {}
27
44
  end
28
45
 
29
46
  @@all << self
@@ -85,6 +85,7 @@ class Onceover
85
85
  # NOTE: This is the way to provide options to rspec according to:
86
86
  # https://github.com/puppetlabs/puppetlabs_spec_helper/blob/master/lib/puppetlabs_spec_helper/rake_tasks.rb#L51
87
87
  ENV['CI_SPEC_OPTIONS'] = ENV['CI_SPEC_OPTIONS'].to_s + @config.filter_tags.map { |tag| " --tag #{tag}" }.join unless @config.filter_tags.nil?
88
+ ENV['CI_SPEC_OPTIONS'] = ENV['CI_SPEC_OPTIONS'].to_s + ' --fail-fast' if @config.fail_fast
88
89
 
89
90
  if @config.opts[:parallel]
90
91
  logger.debug "Running #{@command_prefix}rake parallel_spec from #{@repo.tempdir}"
@@ -27,12 +27,13 @@ class Onceover
27
27
  attr_accessor :after_conditions
28
28
  attr_accessor :skip_r10k
29
29
  attr_accessor :force
30
+ attr_accessor :fail_fast
30
31
  attr_accessor :strict_variables
31
32
  attr_accessor :formatters
32
33
 
33
34
  def initialize(file, opts = {})
34
35
  begin
35
- config = YAML.safe_load(File.read(file), [Symbol])
36
+ config = YAML.safe_load(File.read(file), permitted_classes: [Symbol])
36
37
  rescue Errno::ENOENT
37
38
  raise "Could not find #{file}"
38
39
  rescue Psych::SyntaxError
@@ -79,6 +80,7 @@ class Onceover
79
80
  @filter_nodes = opts[:nodes] ? [opts[:nodes].split(',')].flatten.map {|x| Onceover::Node.find(x)} : nil
80
81
  @skip_r10k = opts[:skip_r10k] ? true : false
81
82
  @force = opts[:force] || false
83
+ @fail_fast = opts[:fail_fast] || false
82
84
 
83
85
  # Validate the mock_functions
84
86
  if @mock_functions && @mock_functions.any? { |name, details| details.has_key? 'type' }
@@ -242,7 +244,7 @@ class Onceover
242
244
  source_files.each do |source_file|
243
245
  target_file = File.join(repo.tempdir, 'spec', source_file.sub(/^#{repo.spec_dir}/, ''))
244
246
  if File.directory?(source_file)
245
- FileUtils.cp_r source_file, target_file unless File.exists? target_file
247
+ FileUtils.cp_r source_file, target_file unless File.exist? target_file
246
248
  else
247
249
  FileUtils.mkdir_p File.dirname target_file
248
250
  FileUtils.cp source_file, target_file
data/onceover.gemspec CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "onceover"
7
- s.version = "3.19.2"
7
+ s.version = "3.21.0"
8
8
  s.authors = ["Dylan Ratcliffe"]
9
9
  s.email = ["dylan.ratcliffe@puppet.com"]
10
10
  s.homepage = "https://github.com/dylanratcliffe/onceover"
@@ -38,6 +38,8 @@ Gem::Specification.new do |s|
38
38
 
39
39
  s.add_development_dependency 'cucumber', '~> 4.1'
40
40
  s.add_development_dependency 'pry', '~> 0.13.1'
41
- s.add_development_dependency 'rubocop', '~> 1.6', '>= 1.6.1'
41
+ # We need to depend on rubocop <= 1.12 in order to support Ruby 2.4 (Puppet
42
+ # 5). Once we drop support for Puppet 5 we can re-open this
43
+ s.add_development_dependency 'rubocop', '>= 1.6.1', '<= 1.12'
42
44
  s.add_development_dependency 'rubygems-tasks', '~> 0.2.5'
43
45
  end
@@ -1,17 +1,17 @@
1
- forge "http://forge.puppetlabs.com"
2
- #
3
- # I want to download some modules to check if r10k feature in Onceover works correctly.
4
- #
5
-
6
- # Versions should be updated to be the latest at the time you start
7
- mod "puppetlabs/stdlib", '4.11.0'
8
-
9
- # Modules from Git
10
- # Examples: https://github.com/puppetlabs/r10k/blob/master/doc/puppetfile.mkd#examples
11
- mod 'apache',
12
- :git => 'https://github.com/puppetlabs/puppetlabs-apache',
13
- :commit => '83401079053dca11d61945bd9beef9ecf7576cbf'
14
-
15
- #mod 'apache',
16
- # :git => 'https://github.com/puppetlabs/puppetlabs-apache',
17
- # :branch => 'docs_experiment'
1
+ forge "http://forge.puppetlabs.com"
2
+ #
3
+ # I want to download some modules to check if r10k feature in Onceover works correctly.
4
+ #
5
+
6
+ # Versions should be updated to be the latest at the time you start
7
+ mod "puppetlabs/stdlib", '4.11.0'
8
+
9
+ # Modules from Git
10
+ # Examples: https://github.com/puppetlabs/r10k/blob/master/doc/puppetfile.mkd#examples
11
+ mod 'apache',
12
+ :git => 'https://github.com/puppetlabs/puppetlabs-apache',
13
+ :commit => '83401079053dca11d61945bd9beef9ecf7576cbf'
14
+
15
+ #mod 'apache',
16
+ # :git => 'https://github.com/puppetlabs/puppetlabs-apache',
17
+ # :branch => 'docs_experiment'
@@ -0,0 +1,6 @@
1
+ # Role that fails compilation if $trusted['extensions']['pp_datacenter'] is not set to 'PDX'
2
+ class role::trusted_extensions {
3
+ unless $trusted['extensions']['pp_datacenter'] == 'PDX' {
4
+ fail ( 'pp_datacenter is not set to PDX' )
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ # Role that fails compilation if $trusted['external']['example']['foo'] is not set to 'bar'
2
+ class role::trusted_external {
3
+ unless $trusted['external']['example']['foo'] == 'bar' {
4
+ fail ( "example forager didn't return foo" )
5
+ }
6
+ }
@@ -0,0 +1,7 @@
1
+ # Factsets
2
+
3
+ This directory is where we put any custom factsets that we want to use. They can be generated by running `puppet facts` on the target system.
4
+
5
+ **Hot tip:** If you already have factsets in here when you run `onceover init` they will be picked up and added to the config file Automatically
6
+
7
+ More info: https://github.com/dylanratcliffe/onceover#factsets