From 0aba9c755a430e4dee3d43a561ad9e74ebb7ff69 Mon Sep 17 00:00:00 2001 From: Michael Hashizume Date: Tue, 28 Oct 2025 09:40:39 -0700 Subject: [PATCH 1/4] (maint) Add beaker-hostgenerator version This is a follow-up to c05b7c7. PDK does not add environment variables to the Gemfile unless a version is specified in .sync.yml, so this commit adds a version for beaker-hostgenerator. --- .sync.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.sync.yml b/.sync.yml index d45e736e..8807d7ed 100644 --- a/.sync.yml +++ b/.sync.yml @@ -20,6 +20,7 @@ Gemfile: version: '~> 1.0' - gem: beaker-hostgenerator from_env: BEAKER_HOSTGENERATOR_VERSION + version: '~> 2.0' - gem: beaker-rspec from_env: BEAKER_RSPEC_VERSION # Prevent beaker-puppet from being installed on Ruby > 3.1 until beaker-puppet supports newer Rubies (PA-6136) From e6c4d1b6307576c867af830348eca2d201dc284f Mon Sep 17 00:00:00 2001 From: Michael Hashizume Date: Tue, 28 Oct 2025 09:42:53 -0700 Subject: [PATCH 2/4] (maint) Remove Ruby requirement for beaker-puppet Previously, beaker-puppet was unable to be installed with newer versions of Ruby. This was resolved in PA-6136, so we no longer need a conditional in .sync.yml for beaker-puppet. --- .sync.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.sync.yml b/.sync.yml index 8807d7ed..8205d5ea 100644 --- a/.sync.yml +++ b/.sync.yml @@ -23,11 +23,9 @@ Gemfile: version: '~> 2.0' - gem: beaker-rspec from_env: BEAKER_RSPEC_VERSION - # Prevent beaker-puppet from being installed on Ruby > 3.1 until beaker-puppet supports newer Rubies (PA-6136) - gem: beaker-puppet from_env: BEAKER_PUPPET_VERSION version: '~> 4.0' - condition: Gem::Requirement.create('< 3.2.0').satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) - gem: beaker-module_install_helper - gem: beaker-puppet_install_helper - gem: nokogiri From a82b5ec6c201fed1a67b2f1dc4fb1bd604cd88d4 Mon Sep 17 00:00:00 2001 From: Michael Hashizume Date: Tue, 28 Oct 2025 10:47:37 -0700 Subject: [PATCH 3/4] (maint) Unpin async gem Previously, the async gem needed to be pinned to 1.30 because of the version of Ruby that internal Jenkins runners were using. We are now using more modern Rubies, so we do not need to pin the gem any longer. --- .sync.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.sync.yml b/.sync.yml index 8205d5ea..26315817 100644 --- a/.sync.yml +++ b/.sync.yml @@ -40,8 +40,6 @@ Gemfile: - gem: 'orchestrator_client' version: '< 0.7.1' condition: 'ENV["GEM_BOLT"]' - - gem: async - version: '~> 1.30' # otherwise async 2.0.0(needs ruby >=3.1.0) is wrongly selected by bundler on jenkins while running with ruby 2.7.1 ":system_tests": - gem: voxpupuli-acceptance version: '~> 3' From 29a81a1aa989fa69f8d48f9b3bc584881e69abb0 Mon Sep 17 00:00:00 2001 From: Michael Hashizume Date: Tue, 28 Oct 2025 10:52:42 -0700 Subject: [PATCH 4/4] (maint) Update to PDK template 3.5.1 This commit updates this module to the latest PDK template (3.5.1). It also updates legacy facts from puppet_agent_spec, as legacy facts were removed in newer versions of FacterDB. --- .gitignore | 7 ++ .pdkignore | 7 ++ .puppet-lint.rc | 8 ++ .rubocop.yml | 2 +- .sync.yml | 3 + Gemfile | 122 +++++++++++++++++------------- Rakefile | 9 +++ metadata.json | 6 +- spec/classes/puppet_agent_spec.rb | 37 +++++---- 9 files changed, 132 insertions(+), 69 deletions(-) diff --git a/.gitignore b/.gitignore index 3f155121..2803e566 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ /spec/fixtures/modules/* /tmp/ /vendor/ +/.vendor/ /convert_report.txt /update_report.txt .DS_Store @@ -26,3 +27,9 @@ .envrc /inventory.yaml /spec/fixtures/litmus_inventory.yaml +.resource_types +.modules +.task_cache.json +.plan_cache.json +.rerun.json +bolt-debug.log diff --git a/.pdkignore b/.pdkignore index 862847a7..84684be6 100644 --- a/.pdkignore +++ b/.pdkignore @@ -19,6 +19,7 @@ /spec/fixtures/modules/* /tmp/ /vendor/ +/.vendor/ /convert_report.txt /update_report.txt .DS_Store @@ -26,6 +27,12 @@ .envrc /inventory.yaml /spec/fixtures/litmus_inventory.yaml +.resource_types +.modules +.task_cache.json +.plan_cache.json +.rerun.json +bolt-debug.log /.fixtures.yml /Gemfile /.gitattributes diff --git a/.puppet-lint.rc b/.puppet-lint.rc index 02505e80..be67cd1e 100644 --- a/.puppet-lint.rc +++ b/.puppet-lint.rc @@ -1,2 +1,10 @@ +--fail-on-warnings --relative +--no-80chars-check +--no-140chars-check +--no-class_inherits_from_params_class-check +--no-autoloader_layout-check +--no-documentation-check +--no-single_quote_string_with_variables-check --no-puppet_url_without_modules-check +--ignore-paths=.vendor/**/*.pp,.bundle/**/*.pp,pkg/**/*.pp,spec/**/*.pp,tests/**/*.pp,types/**/*.pp,vendor/**/*.pp diff --git a/.rubocop.yml b/.rubocop.yml index 8d382dab..72a1734e 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -5,7 +5,7 @@ require: AllCops: NewCops: enable DisplayCopNames: true - TargetRubyVersion: '2.6' + TargetRubyVersion: 2.7 Include: - "**/*.rb" Exclude: diff --git a/.sync.yml b/.sync.yml index 26315817..55fadbf1 100644 --- a/.sync.yml +++ b/.sync.yml @@ -1,6 +1,9 @@ --- .rubocop.yml: default_configs: + # Ruby 2.7 compatibility is needed til we drop Puppet 7 testing + AllCops: + TargetRubyVersion: 2.7 Layout/LineLength: Max: 260 RSpec/NamedSubject: diff --git a/Gemfile b/Gemfile index d7c2e970..5d0528c1 100644 --- a/Gemfile +++ b/Gemfile @@ -1,49 +1,73 @@ -source ENV['GEM_SOURCE'] || 'https://rubygems.org' +# frozen_string_literal: true -def location_for(place_or_version, fake_version = nil) - git_url_regex = %r{\A(?(https?|git)[:@][^#]*)(#(?.*))?} - file_url_regex = %r{\Afile:\/\/(?.*)} +# For puppetcore, set GEM_SOURCE_PUPPETCORE = 'https://rubygems-puppetcore.puppet.com' +gemsource_default = ENV['GEM_SOURCE'] || 'https://rubygems.org' +gemsource_puppetcore = if ENV['PUPPET_FORGE_TOKEN'] + 'https://rubygems-puppetcore.puppet.com' +else + ENV['GEM_SOURCE_PUPPETCORE'] || gemsource_default +end +source gemsource_default + +def location_for(place_or_constraint, fake_constraint = nil, opts = {}) + git_url_regex = /\A(?(?:https?|git)[:@][^#]*)(?:#(?.*))?/ + file_url_regex = %r{\Afile://(?.*)} + + if place_or_constraint && (git_url = place_or_constraint.match(git_url_regex)) + # Git source → ignore :source, keep fake_constraint + [fake_constraint, { git: git_url[:url], branch: git_url[:branch], require: false }].compact + + elsif place_or_constraint && (file_url = place_or_constraint.match(file_url_regex)) + # File source → ignore :source, keep fake_constraint or default >= 0 + [fake_constraint || '>= 0', { path: File.expand_path(file_url[:path]), require: false }] - if place_or_version && (git_url = place_or_version.match(git_url_regex)) - [fake_version, { git: git_url[:url], branch: git_url[:branch], require: false }].compact - elsif place_or_version && (file_url = place_or_version.match(file_url_regex)) - ['>= 0', { path: File.expand_path(file_url[:path]), require: false }] else - [place_or_version, { require: false }] + # Plain version constraint → merge opts (including :source if provided) + [place_or_constraint, { require: false }.merge(opts)] + end +end + +# Print debug information if DEBUG_GEMS or VERBOSE is set +def print_gem_statement_for(gems) + puts 'DEBUG: Gem definitions that will be generated:' + gems.each do |gem_name, gem_params| + puts "DEBUG: gem #{([gem_name.inspect] + gem_params.map(&:inspect)).join(', ')}" end end group :development do - gem "json", '= 2.6.1', require: false if Gem::Requirement.create(['>= 3.1.0', '< 3.1.3']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) - gem "json", '= 2.6.3', require: false if Gem::Requirement.create(['>= 3.2.0', '< 4.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) - gem "racc", '~> 1.4.0', require: false if Gem::Requirement.create(['>= 2.7.0', '< 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) - gem "deep_merge", '~> 1.2.2', require: false - gem "voxpupuli-puppet-lint-plugins", '~> 5.0', require: false - gem "facterdb", '~> 1.18', require: false - gem "metadata-json-lint", '~> 4.0', require: false - gem "rspec-puppet-facts", '~> 3.0', require: false - gem "json-schema", '< 5.1.1', require: false - gem "dependency_checker", '~> 1.0.0', require: false - gem "parallel_tests", '= 3.12.1', require: false - gem "pry", '~> 0.10', require: false - gem "simplecov-console", '~> 0.9', require: false - gem "puppet-debugger", '~> 1.6', require: false - gem "rubocop", '~> 1.50.0', require: false - gem "rubocop-performance", '= 1.16.0', require: false - gem "rubocop-rspec", '= 2.19.0', require: false - gem "rb-readline", '= 0.5.5', require: false, platforms: [:mswin, :mingw, :x64_mingw] + gem "json", '= 2.6.1', require: false if Gem::Requirement.create(['>= 3.1.0', '< 3.1.3']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "json", '= 2.6.3', require: false if Gem::Requirement.create(['>= 3.2.0', '< 4.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "racc", '~> 1.4.0', require: false if Gem::Requirement.create(['>= 2.7.0', '< 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "deep_merge", '~> 1.2.2', require: false + gem "voxpupuli-puppet-lint-plugins", '~> 5.0', require: false + gem "facterdb", '~> 2.1', require: false if Gem::Requirement.create(['< 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "facterdb", '~> 3.0', require: false if Gem::Requirement.create(['>= 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "metadata-json-lint", '~> 4.0', require: false + gem "json-schema", '< 5.1.1', require: false + gem "rspec-puppet-facts", '~> 4.0', require: false if Gem::Requirement.create(['< 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "rspec-puppet-facts", '~> 5.0', require: false if Gem::Requirement.create(['>= 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "dependency_checker", '~> 1.0.0', require: false + gem "parallel_tests", '= 3.12.1', require: false + gem "pry", '~> 0.10', require: false + gem "simplecov-console", '~> 0.9', require: false + gem "puppet-debugger", '~> 1.6', require: false + gem "rubocop", '~> 1.50.0', require: false + gem "rubocop-performance", '= 1.16.0', require: false + gem "rubocop-rspec", '= 2.19.0', require: false + gem "rb-readline", '= 0.5.5', require: false, platforms: [:mswin, :mingw, :x64_mingw] + gem "bigdecimal", '< 3.2.2', require: false, platforms: [:mswin, :mingw, :x64_mingw] gem "beaker", *location_for(ENV['BEAKER_VERSION'] || '~> 6.0') gem "beaker-abs", *location_for(ENV['BEAKER_ABS_VERSION'] || '~> 1.0') - gem "beaker-hostgenerator", *location_for(ENV['BEAKER_HOSTGENERATOR_VERSION'] || '~> 2') + gem "beaker-hostgenerator", *location_for(ENV['BEAKER_HOSTGENERATOR_VERSION'] || '~> 2.0') gem "beaker-rspec" - gem "beaker-puppet", *location_for(ENV['BEAKER_PUPPET_VERSION'] || '~> 4.0') if Gem::Requirement.create('< 3.2.0').satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) - gem "beaker-module_install_helper", require: false - gem "beaker-puppet_install_helper", require: false - gem "nokogiri", require: false - gem "bolt", '~> 3.0', require: false if ENV["GEM_BOLT"] - gem "beaker-task_helper", '~> 1.9', require: false if ENV["GEM_BOLT"] - gem "orchestrator_client", '< 0.7.1', require: false if ENV["GEM_BOLT"] - gem "async", '~> 1.30', require: false + gem "beaker-puppet", *location_for(ENV['BEAKER_PUPPET_VERSION'] || '~> 4.0') + gem "beaker-module_install_helper", require: false + gem "beaker-puppet_install_helper", require: false + gem "nokogiri", require: false + gem "bolt", '~> 3.0', require: false if ENV["GEM_BOLT"] + gem "beaker-task_helper", '~> 1.9', require: false if ENV["GEM_BOLT"] + gem "orchestrator_client", '< 0.7.1', require: false if ENV["GEM_BOLT"] end group :development, :release_prep do gem "puppet-strings", '~> 4.0', require: false @@ -61,18 +85,12 @@ puppet_version = ENV.fetch('PUPPET_GEM_VERSION', nil) facter_version = ENV.fetch('FACTER_GEM_VERSION', nil) hiera_version = ENV.fetch('HIERA_GEM_VERSION', nil) -# If PUPPET_FORGE_TOKEN is set then use authenticated source for both puppet and facter, since facter is a transitive dependency of puppet -# Otherwise, do as before and use location_for to fetch gems from the default source -if !ENV['PUPPET_FORGE_TOKEN'].to_s.empty? - gems['puppet'] = ['~> 8.11', { require: false, source: 'https://rubygems-puppetcore.puppet.com' }] - gems['facter'] = ['~> 4.11', { require: false, source: 'https://rubygems-puppetcore.puppet.com' }] -else - gems['puppet'] = location_for(puppet_version) - gems['facter'] = location_for(facter_version) if facter_version -end - -gems['hiera'] = location_for(hiera_version) if hiera_version +gems['puppet'] = location_for(puppet_version, nil, { source: gemsource_puppetcore }) +gems['facter'] = location_for(facter_version, nil, { source: gemsource_puppetcore }) +gems['hiera'] = location_for(hiera_version, nil, {}) if hiera_version +# Generate the gem definitions +print_gem_statement_for(gems) if ENV['DEBUG'] gems.each do |gem_name, gem_params| gem gem_name, *gem_params end @@ -80,12 +98,14 @@ end # Evaluate Gemfile.local and ~/.gemfile if they exist extra_gemfiles = [ "#{__FILE__}.local", - File.join(Dir.home, '.gemfile'), + File.join(Dir.home, '.gemfile') ] extra_gemfiles.each do |gemfile| - if File.file?(gemfile) && File.readable?(gemfile) - eval(File.read(gemfile), binding) - end + next unless File.file?(gemfile) && File.readable?(gemfile) + + # rubocop:disable Security/Eval + eval(File.read(gemfile), binding) + # rubocop:enable Security/Eval end # vim: syntax=ruby diff --git a/Rakefile b/Rakefile index 7101afe1..d5560851 100644 --- a/Rakefile +++ b/Rakefile @@ -8,4 +8,13 @@ require 'puppet-strings/tasks' if Gem.loaded_specs.key? 'puppet-strings' require 'voxpupuli/acceptance/rake' if Gem.loaded_specs.key? 'voxpupuli-acceptance' PuppetLint.configuration.send('disable_relative') +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.send('disable_140chars') +PuppetLint.configuration.send('disable_class_inherits_from_params_class') +PuppetLint.configuration.send('disable_autoloader_layout') +PuppetLint.configuration.send('disable_documentation') +PuppetLint.configuration.send('disable_single_quote_string_with_variables') PuppetLint.configuration.send('disable_puppet_url_without_modules') +PuppetLint.configuration.fail_on_warnings = true +PuppetLint.configuration.ignore_paths = [".vendor/**/*.pp", ".bundle/**/*.pp", "pkg/**/*.pp", "spec/**/*.pp", "tests/**/*.pp", "types/**/*.pp", "vendor/**/*.pp"] + diff --git a/metadata.json b/metadata.json index 27f52b12..0d3b36ac 100644 --- a/metadata.json +++ b/metadata.json @@ -82,7 +82,7 @@ "version_requirement": ">= 7.0.0 < 9.0.0" } ], - "pdk-version": "3.2.0", - "template-url": "https://github.com/puppetlabs/pdk-templates#3.2.0", - "template-ref": "tags/3.2.0-0-gb257ef1" + "pdk-version": "3.5.1", + "template-url": "https://github.com/puppetlabs/pdk-templates#3.5.1", + "template-ref": "tags/3.5.1-0-g9d5b193" } diff --git a/spec/classes/puppet_agent_spec.rb b/spec/classes/puppet_agent_spec.rb index 822e6608..7da68d18 100644 --- a/spec/classes/puppet_agent_spec.rb +++ b/spec/classes/puppet_agent_spec.rb @@ -4,7 +4,6 @@ # maps AIX release major fact value to the known AIX version AIX_VERSION = { - '6100': '6.1', '7100': '7.2', '7200': '7.2', }.freeze @@ -13,8 +12,10 @@ def redhat_familly_supported_os on_supported_os( supported_os: [ { - 'operatingsystem' => 'RedHat', - "operatingsystemrelease": ['5', '6', '7', '8'], + 'os' => { + 'name' => 'RedHat', + 'release' => ['6', '7', '8', '9', '10'], + } }, ], ) @@ -30,7 +31,6 @@ def global_facts(facts, os) { is_pe: true, env_temp_variable: '/tmp', - operatingsystemmajrelease: facts[:operatingsystemrelease].split('.')[0], } elsif %r{redhat|centos|fedora|scientific|oracle}.match?(os) { @@ -120,12 +120,21 @@ def global_facts(facts, os) end context 'package provider' do - # module is still pinned to older rspec-puppet and facterdb - os_name = 'fedora-41-x86_64' - os_facts = { - os_name => on_supported_os['fedora-39-x86_64'], - } - os_facts.values.first[:os]['release'] = { 'full' => '41', 'major' => '41' } + # Package provider behavior changes on Fedora in >= 41 + # Fedora 41 facts were introduced to FacterDB in 3.8.0, the PDK template + # pins FacterDB to 2.1.0 in Ruby < 3.0. + # Once we drop tests for Puppet 7, we can use just the first conditional + if on_supported_os['fedora-41-x86_64'] + os_facts = { + 'fedora-41-x86_64' => on_supported_os['fedora-41-x86_64'] + } + else + os_name = 'fedora-41-x86_64' + os_facts = { + os_name => on_supported_os['fedora-38-x86_64'], + } + os_facts.values.first[:os]['release'] = { 'full' => '41', 'major' => '41' } + end os_facts.each do |os, facts| context "on #{os}" do let(:facts) do @@ -349,10 +358,10 @@ def global_facts(facts, os) it { is_expected.to contain_class('puppet_agent::prepare') } it { is_expected.to contain_class('puppet_agent::install').that_requires('Class[puppet_agent::prepare]') } - if facts[:osfamily] == 'Debian' + if facts[:os]['family'] == 'Debian' deb_package_version = package_version + '-1' + facts.dig(:os, 'distro', 'codename') it { is_expected.to contain_package('puppet-agent').with_ensure(deb_package_version) } - elsif facts[:osfamily] == 'Solaris' + elsif facts[:os]['family'] == 'Solaris' if facts[:operatingsystemmajrelease] == '11' it { is_expected.to contain_package('puppet-agent').with_ensure('6.5.4') } else @@ -363,7 +372,7 @@ def global_facts(facts, os) ) end end - elsif facts[:osfamily] == 'windows' + elsif facts[:os]['family'] == 'windows' # Windows does not contain any Package resources else it { is_expected.to contain_package('puppet-agent').with_ensure(package_version) } @@ -377,7 +386,7 @@ def global_facts(facts, os) # Windows platform does not use Service resources; their services # are managed by the MSI installer. - unless facts[:osfamily] == 'windows' + unless facts[:os]['family'] == 'windows' if params[:service_names].nil? && os !~ %r{sles|solaris|aix} it { is_expected.to contain_service('puppet') } else