From 9aad6074fad5fd5fbe15d5b29450fb1563c0c56a Mon Sep 17 00:00:00 2001 From: Craig Gumbley Date: Mon, 23 Jan 2023 19:27:04 +0000 Subject: [PATCH 1/3] (CONT-515) Fix uninitialized constant error --- lib/puppetlabs_spec_helper/tasks/fixtures.rb | 697 ++++++++++--------- 1 file changed, 349 insertions(+), 348 deletions(-) diff --git a/lib/puppetlabs_spec_helper/tasks/fixtures.rb b/lib/puppetlabs_spec_helper/tasks/fixtures.rb index d1519700..c427cd40 100644 --- a/lib/puppetlabs_spec_helper/tasks/fixtures.rb +++ b/lib/puppetlabs_spec_helper/tasks/fixtures.rb @@ -4,406 +4,407 @@ require 'open3' require 'json' -# Top level namespace for spec helper tasks. -module PuppetlabsSpecHelper::Tasks end - -# Helpers for workfing with fixtures. -module PuppetlabsSpecHelper::Tasks::FixtureHelpers - # This is a helper for the self-symlink entry of fixtures.yml - def source_dir - Dir.pwd - end - - # @return [String] - the name of current module - def module_name - raise ArgumentError unless File.file?('metadata.json') && File.readable?('metadata.json') - - metadata = JSON.parse(File.read('metadata.json')) - metadata_name = metadata.fetch('name', nil) || '' - - raise ArgumentError if metadata_name.empty? +module PuppetlabsSpecHelper + module Tasks + # Helpers for working with fixtures. + module FixtureHelpers + # This is a helper for the self-symlink entry of fixtures.yml + def source_dir + Dir.pwd + end - metadata_name.split('-').last - rescue JSON::ParserError, ArgumentError - File.basename(Dir.pwd).split('-').last - end + # @return [String] - the name of current module + def module_name + raise ArgumentError unless File.file?('metadata.json') && File.readable?('metadata.json') - def module_version(path) - metadata_path = File.join(path, 'metadata.json') - raise ArgumentError unless File.file?(metadata_path) && File.readable?(metadata_path) + metadata = JSON.parse(File.read('metadata.json')) + metadata_name = metadata.fetch('name', nil) || '' - metadata = JSON.parse(File.read(metadata_path)) - metadata.fetch('version', nil) || '0.0.1' - rescue JSON::ParserError, ArgumentError - logger.warn "Failed to find module version at path #{path}" - '0.0.1' - end + raise ArgumentError if metadata_name.empty? - # @return [Hash] - returns a hash of all the fixture repositories - # @example - # {"puppetlabs-stdlib"=>{"target"=>"https://gitlab.com/puppetlabs/puppet-stdlib.git", - # "ref"=>nil, "branch"=>"main", "scm"=>nil, - # }} - def repositories - @repositories ||= fixtures('repositories') || {} - end + metadata_name.split('-').last + rescue JSON::ParserError, ArgumentError + File.basename(Dir.pwd).split('-').last + end - # @return [Hash] - returns a hash of all the fixture forge modules - # @example - # {"puppetlabs-stdlib"=>{"target"=>"spec/fixtures/modules/stdlib", - # "ref"=>nil, "branch"=>nil, "scm"=>nil, - # "flags"=>"--module_repository=https://myforge.example.com/", "subdir"=>nil}} - def forge_modules - @forge_modules ||= fixtures('forge_modules') || {} - end + def module_version(path) + metadata_path = File.join(path, 'metadata.json') + raise ArgumentError unless File.file?(metadata_path) && File.readable?(metadata_path) - # @return [Hash] - a hash of symlinks specified in the fixtures file - def symlinks - @symlinks ||= fixtures('symlinks') || {} - end + metadata = JSON.parse(File.read(metadata_path)) + metadata.fetch('version', nil) || '0.0.1' + rescue JSON::ParserError, ArgumentError + logger.warn "Failed to find module version at path #{path}" + '0.0.1' + end - # @return [Hash] - returns a hash with the module name and the source directory - def auto_symlink - { module_name => "\#{source_dir}" } - end + # @return [Hash] - returns a hash of all the fixture repositories + # @example + # {"puppetlabs-stdlib"=>{"target"=>"https://gitlab.com/puppetlabs/puppet-stdlib.git", + # "ref"=>nil, "branch"=>"main", "scm"=>nil, + # }} + def repositories + @repositories ||= fixtures('repositories') || {} + end - # @return [Boolean] - true if the os is a windows system - def windows? - !!File::ALT_SEPARATOR - end + # @return [Hash] - returns a hash of all the fixture forge modules + # @example + # {"puppetlabs-stdlib"=>{"target"=>"spec/fixtures/modules/stdlib", + # "ref"=>nil, "branch"=>nil, "scm"=>nil, + # "flags"=>"--module_repository=https://myforge.example.com/", "subdir"=>nil}} + def forge_modules + @forge_modules ||= fixtures('forge_modules') || {} + end - def fixtures(category) - fixtures_yaml = if ENV['FIXTURES_YML'] - ENV['FIXTURES_YML'] - elsif File.exist?('.fixtures.yml') - '.fixtures.yml' - elsif File.exist?('.fixtures.yaml') - '.fixtures.yaml' - else - false - end + # @return [Hash] - a hash of symlinks specified in the fixtures file + def symlinks + @symlinks ||= fixtures('symlinks') || {} + end - begin - fixtures = if fixtures_yaml - YAML.load_file(fixtures_yaml) || { 'fixtures' => {} } - else - { 'fixtures' => {} } - end - rescue Errno::ENOENT - raise("Fixtures file not found: '#{fixtures_yaml}'") - rescue Psych::SyntaxError => e - raise("Found malformed YAML in '#{fixtures_yaml}' on line #{e.line} column #{e.column}: #{e.problem}") - end + # @return [Hash] - returns a hash with the module name and the source directory + def auto_symlink + { module_name => "\#{source_dir}" } + end - unless fixtures.include?('fixtures') - # File is non-empty, but does not specify fixtures - raise("No 'fixtures' entries found in '#{fixtures_yaml}'; required") - end + # @return [Boolean] - true if the os is a windows system + def windows? + !!File::ALT_SEPARATOR + end - fixture_defaults = if fixtures.include? 'defaults' - fixtures['defaults'] - else - {} - end + def fixtures(category) + fixtures_yaml = if ENV['FIXTURES_YML'] + ENV['FIXTURES_YML'] + elsif File.exist?('.fixtures.yml') + '.fixtures.yml' + elsif File.exist?('.fixtures.yaml') + '.fixtures.yaml' + else + false + end + + begin + fixtures = if fixtures_yaml + YAML.load_file(fixtures_yaml) || { 'fixtures' => {} } + else + { 'fixtures' => {} } + end + rescue Errno::ENOENT + raise("Fixtures file not found: '#{fixtures_yaml}'") + rescue Psych::SyntaxError => e + raise("Found malformed YAML in '#{fixtures_yaml}' on line #{e.line} column #{e.column}: #{e.problem}") + end - fixtures = fixtures['fixtures'] + unless fixtures.include?('fixtures') + # File is non-empty, but does not specify fixtures + raise("No 'fixtures' entries found in '#{fixtures_yaml}'; required") + end - if fixtures['symlinks'].nil? - fixtures['symlinks'] = auto_symlink - end + fixture_defaults = if fixtures.include? 'defaults' + fixtures['defaults'] + else + {} + end - result = {} - if fixtures.include?(category) && !fixtures[category].nil? - defaults = { 'target' => 'spec/fixtures/modules' } + fixtures = fixtures['fixtures'] - # load defaults from the `.fixtures.yml` `defaults` section - # for the requested category and merge them into my defaults - if fixture_defaults.include? category - defaults = defaults.merge(fixture_defaults[category]) - end + if fixtures['symlinks'].nil? + fixtures['symlinks'] = auto_symlink + end - fixtures[category].each do |fixture, opts| - # convert a simple string fixture to a hash, by - # using the string fixture as the `repo` option of the hash. - if opts.instance_of?(String) - opts = { 'repo' => opts } + result = {} + if fixtures.include?(category) && !fixtures[category].nil? + defaults = { 'target' => 'spec/fixtures/modules' } + + # load defaults from the `.fixtures.yml` `defaults` section + # for the requested category and merge them into my defaults + if fixture_defaults.include? category + defaults = defaults.merge(fixture_defaults[category]) + end + + fixtures[category].each do |fixture, opts| + # convert a simple string fixture to a hash, by + # using the string fixture as the `repo` option of the hash. + if opts.instance_of?(String) + opts = { 'repo' => opts } + end + # there should be a warning or something if it's not a hash... + next unless opts.instance_of?(Hash) + + # merge our options into the defaults to get the + # final option list + opts = defaults.merge(opts) + + next unless include_repo?(opts['puppet_version']) + + # rubocop:disable Security/Eval + # TODO: Remove eval + real_target = eval("\"#{opts['target']}\"", binding, __FILE__, __LINE__) # evaluating target reference in this context (see auto_symlink) + real_source = eval("\"#{opts['repo']}\"", binding, __FILE__, __LINE__) # evaluating repo reference in this context (see auto_symlink) + + result[real_source] = validate_fixture_hash!( + 'target' => File.join(real_target, fixture), + 'ref' => opts['ref'] || opts['tag'], + 'branch' => opts['branch'], + 'scm' => opts['scm'], + 'flags' => opts['flags'], + 'subdir' => opts['subdir'], + ) + end end - # there should be a warning or something if it's not a hash... - next unless opts.instance_of?(Hash) - - # merge our options into the defaults to get the - # final option list - opts = defaults.merge(opts) - - next unless include_repo?(opts['puppet_version']) - - # rubocop:disable Security/Eval - # TODO: Remove eval - real_target = eval("\"#{opts['target']}\"", binding, __FILE__, __LINE__) # evaluating target reference in this context (see auto_symlink) - real_source = eval("\"#{opts['repo']}\"", binding, __FILE__, __LINE__) # evaluating repo reference in this context (see auto_symlink) - - result[real_source] = validate_fixture_hash!( - 'target' => File.join(real_target, fixture), - 'ref' => opts['ref'] || opts['tag'], - 'branch' => opts['branch'], - 'scm' => opts['scm'], - 'flags' => opts['flags'], - 'subdir' => opts['subdir'], - ) + result end - end - result - end - def validate_fixture_hash!(hash) - # Can only validate git based scm - return hash unless hash['scm'] == 'git' + def validate_fixture_hash!(hash) + # Can only validate git based scm + return hash unless hash['scm'] == 'git' - # Forward slashes in the ref aren't allowed. And is probably a branch name. - 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?('/') + # Forward slashes in the ref aren't allowed. And is probably a branch name. + 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?('/') - hash - end + hash + end - def include_repo?(version_range) - if version_range && defined?(SemanticPuppet) - puppet_spec = Gem::Specification.find_by_name('puppet') - puppet_version = SemanticPuppet::Version.parse(puppet_spec.version.to_s) + def include_repo?(version_range) + if version_range && defined?(SemanticPuppet) + puppet_spec = Gem::Specification.find_by_name('puppet') + puppet_version = SemanticPuppet::Version.parse(puppet_spec.version.to_s) - constraint = SemanticPuppet::VersionRange.parse(version_range) - constraint.include?(puppet_version) - else - true - end - end + constraint = SemanticPuppet::VersionRange.parse(version_range) + constraint.include?(puppet_version) + else + true + end + end - def clone_repo(scm, remote, target, _subdir = nil, ref = nil, branch = nil, flags = nil) - args = [] - case scm - when 'hg' - args.push('clone') - args.push('-b', branch) if branch - args.push(flags) if flags - args.push(remote, target) - when 'git' - args.push('clone') - args.push('--depth 1') unless ref - args.push('-b', branch) if branch - args.push(flags) if flags - args.push(remote, target) - else - raise "Unfortunately #{scm} is not supported yet" - end - result = system("#{scm} #{args.flatten.join ' '}") - unless File.exist?(target) - raise "Failed to clone #{scm} repository #{remote} into #{target}" - end + def clone_repo(scm, remote, target, _subdir = nil, ref = nil, branch = nil, flags = nil) + args = [] + case scm + when 'hg' + args.push('clone') + args.push('-b', branch) if branch + args.push(flags) if flags + args.push(remote, target) + when 'git' + args.push('clone') + args.push('--depth 1') unless ref + args.push('-b', branch) if branch + args.push(flags) if flags + args.push(remote, target) + else + raise "Unfortunately #{scm} is not supported yet" + end + result = system("#{scm} #{args.flatten.join ' '}") + unless File.exist?(target) + raise "Failed to clone #{scm} repository #{remote} into #{target}" + end - result - end + result + end - def update_repo(scm, target) - args = case scm - when 'hg' - ['pull'] - when 'git' - ['fetch'].tap do |git_args| - git_args << '--unshallow' if shallow_git_repo? - end - else - raise "Unfortunately #{scm} is not supported yet" - end - system("#{scm} #{args.flatten.join(' ')}", chdir: target) - end + def update_repo(scm, target) + args = case scm + when 'hg' + ['pull'] + when 'git' + ['fetch'].tap do |git_args| + git_args << '--unshallow' if shallow_git_repo? + end + else + raise "Unfortunately #{scm} is not supported yet" + end + system("#{scm} #{args.flatten.join(' ')}", chdir: target) + end - def shallow_git_repo? - File.file?(File.join('.git', 'shallow')) - end + def shallow_git_repo? + File.file?(File.join('.git', 'shallow')) + end - def revision(scm, target, ref) - args = [] - case scm - when 'hg' - args.push('update', '--clean', '-r', ref) - when 'git' - args.push('reset', '--hard', ref) - else - raise "Unfortunately #{scm} is not supported yet" - end - result = system("#{scm} #{args.flatten.join ' '}", chdir: target) - raise "Invalid ref #{ref} for #{target}" unless result - end + def revision(scm, target, ref) + args = [] + case scm + when 'hg' + args.push('update', '--clean', '-r', ref) + when 'git' + args.push('reset', '--hard', ref) + else + raise "Unfortunately #{scm} is not supported yet" + end + result = system("#{scm} #{args.flatten.join ' '}", chdir: target) + raise "Invalid ref #{ref} for #{target}" unless result + end - def valid_repo?(scm, target, remote) - return false unless File.directory?(target) - return true if scm == 'hg' + def valid_repo?(scm, target, remote) + return false unless File.directory?(target) + return true if scm == 'hg' - return true if git_remote_url(target) == remote + return true if git_remote_url(target) == remote - warn "Git remote for #{target} has changed, recloning repository" - FileUtils.rm_rf(target) - false - end + warn "Git remote for #{target} has changed, recloning repository" + FileUtils.rm_rf(target) + false + end - def git_remote_url(target) - output, status = Open3.capture2e('git', '--git-dir', File.join(target, '.git'), 'ls-remote', '--get-url', 'origin') - status.success? ? output.strip : nil - end + def git_remote_url(target) + output, status = Open3.capture2e('git', '--git-dir', File.join(target, '.git'), 'ls-remote', '--get-url', 'origin') + status.success? ? output.strip : nil + end - def remove_subdirectory(target, subdir) - return if subdir.nil? - Dir.mktmpdir do |tmpdir| - FileUtils.mv(Dir.glob("#{target}/#{subdir}/{.[^\.]*,*}"), tmpdir) - FileUtils.rm_rf("#{target}/#{subdir}") - FileUtils.mv(Dir.glob("#{tmpdir}/{.[^\.]*,*}"), target.to_s) - end - end + def remove_subdirectory(target, subdir) + return if subdir.nil? + Dir.mktmpdir do |tmpdir| + FileUtils.mv(Dir.glob("#{target}/#{subdir}/{.[^\.]*,*}"), tmpdir) + FileUtils.rm_rf("#{target}/#{subdir}") + FileUtils.mv(Dir.glob("#{tmpdir}/{.[^\.]*,*}"), target.to_s) + end + end - # creates a logger so we can log events with certain levels - def logger - unless @logger - require 'logger' - level = if ENV['ENABLE_LOGGER'] - Logger::DEBUG - else - Logger::INFO - end - @logger = Logger.new($stderr) - @logger.level = level - end - @logger - end + # creates a logger so we can log events with certain levels + def logger + unless @logger + require 'logger' + level = if ENV['ENABLE_LOGGER'] + Logger::DEBUG + else + Logger::INFO + end + @logger = Logger.new($stderr) + @logger.level = level + end + @logger + end - def module_working_directory - # The problem with the relative path is that PMT doesn't expand the path properly and so passing in a relative path here - # becomes something like C:\somewhere\backslashes/spec/fixtures/work-dir on Windows, and then PMT barfs itself. - # This has been reported as https://tickets.puppetlabs.com/browse/PUP-4884 - File.expand_path(ENV['MODULE_WORKING_DIR'] || 'spec/fixtures/work-dir') - end + def module_working_directory + # The problem with the relative path is that PMT doesn't expand the path properly and so passing in a relative path here + # becomes something like C:\somewhere\backslashes/spec/fixtures/work-dir on Windows, and then PMT barfs itself. + # This has been reported as https://tickets.puppetlabs.com/browse/PUP-4884 + File.expand_path(ENV['MODULE_WORKING_DIR'] || 'spec/fixtures/work-dir') + end - # returns the current thread count that is currently active - # a status of false or nil means the thread completed - # so when anything else we count that as a active thread - # @return [Integer] - current thread count - def current_thread_count(items) - active_threads = items.select do |_item, opts| - if opts[:thread] - opts[:thread].status - else - false + # returns the current thread count that is currently active + # a status of false or nil means the thread completed + # so when anything else we count that as a active thread + # @return [Integer] - current thread count + def current_thread_count(items) + active_threads = items.select do |_item, opts| + if opts[:thread] + opts[:thread].status + else + false + end + end + logger.debug "Current thread count #{active_threads.count}" + active_threads.count end - end - logger.debug "Current thread count #{active_threads.count}" - active_threads.count - end - # @summary Set a limit on the amount threads used, defaults to 10 - # MAX_FIXTURE_THREAD_COUNT can be used to set this limit - # @return [Integer] - returns the max_thread_count - def max_thread_limit - @max_thread_limit ||= (ENV['MAX_FIXTURE_THREAD_COUNT'] || 10).to_i - end + # @summary Set a limit on the amount threads used, defaults to 10 + # MAX_FIXTURE_THREAD_COUNT can be used to set this limit + # @return [Integer] - returns the max_thread_count + def max_thread_limit + @max_thread_limit ||= (ENV['MAX_FIXTURE_THREAD_COUNT'] || 10).to_i + end - # @param items [Hash] - a hash of either repositories or forge modules - # @param [Block] - the method you wish to use to download the item - def download_items(items) - items.each do |remote, opts| - # get the current active threads that are alive - count = current_thread_count(items) - if count < max_thread_limit - logger.debug "New Thread started for #{remote}" - # start up a new thread and store it in the opts hash - opts[:thread] = Thread.new do - yield(remote, opts) + # @param items [Hash] - a hash of either repositories or forge modules + # @param [Block] - the method you wish to use to download the item + def download_items(items) + items.each do |remote, opts| + # get the current active threads that are alive + count = current_thread_count(items) + if count < max_thread_limit + logger.debug "New Thread started for #{remote}" + # start up a new thread and store it in the opts hash + opts[:thread] = Thread.new do + yield(remote, opts) + end + else + # the last thread started should be the longest wait + item, item_opts = items.reverse.find { |_i, o| o.key?(:thread) } + logger.debug "Waiting on #{item}" + item_opts[:thread].join # wait for the thread to finish + # now that we waited lets try again + redo + end end - else - # the last thread started should be the longest wait - item, item_opts = items.reverse.find { |_i, o| o.key?(:thread) } - logger.debug "Waiting on #{item}" - item_opts[:thread].join # wait for the thread to finish - # now that we waited lets try again - redo + # wait for all the threads to finish + items.each { |_remote, opts| opts[:thread].join } end - end - # wait for all the threads to finish - items.each { |_remote, opts| opts[:thread].join } - end - # @param target [String] - the target directory - # @param link [String] - the name of the link you wish to create - # works on windows and linux - def setup_symlink(target, link) - link = link['target'] - return if File.symlink?(link) - - logger.info("Creating symlink from #{link} to #{target}") - if windows? - target = File.join(File.dirname(link), target) unless Pathname.new(target).absolute? - if Dir.respond_to?(:create_junction) - Dir.create_junction(link, target) - else - system("call mklink /J \"#{link.tr('/', '\\')}\" \"#{target.tr('/', '\\')}\"") + # @param target [String] - the target directory + # @param link [String] - the name of the link you wish to create + # works on windows and linux + def setup_symlink(target, link) + link = link['target'] + return if File.symlink?(link) + + logger.info("Creating symlink from #{link} to #{target}") + if windows? + target = File.join(File.dirname(link), target) unless Pathname.new(target).absolute? + if Dir.respond_to?(:create_junction) + Dir.create_junction(link, target) + else + system("call mklink /J \"#{link.tr('/', '\\')}\" \"#{target.tr('/', '\\')}\"") + end + else + FileUtils.ln_sf(target, link) + end end - else - FileUtils.ln_sf(target, link) - end - end - # @return [Boolean] - returns true if the module was downloaded successfully, false otherwise - # @param [String] - the remote url or namespace/name of the module to download - # @param [Hash] - list of options such as version, branch, ref - def download_repository(remote, opts) - scm = 'git' - target = opts['target'] - subdir = opts['subdir'] - ref = opts['ref'] - scm = opts['scm'] if opts['scm'] - branch = opts['branch'] if opts['branch'] - flags = opts['flags'] - if valid_repo?(scm, target, remote) - update_repo(scm, target) - else - clone_repo(scm, remote, target, subdir, ref, branch, flags) - end - revision(scm, target, ref) if ref - remove_subdirectory(target, subdir) if subdir - end + # @return [Boolean] - returns true if the module was downloaded successfully, false otherwise + # @param [String] - the remote url or namespace/name of the module to download + # @param [Hash] - list of options such as version, branch, ref + def download_repository(remote, opts) + scm = 'git' + target = opts['target'] + subdir = opts['subdir'] + ref = opts['ref'] + scm = opts['scm'] if opts['scm'] + branch = opts['branch'] if opts['branch'] + flags = opts['flags'] + if valid_repo?(scm, target, remote) + update_repo(scm, target) + else + clone_repo(scm, remote, target, subdir, ref, branch, flags) + end + revision(scm, target, ref) if ref + remove_subdirectory(target, subdir) if subdir + end - # @return [String] - the spec/fixtures/modules directory in the module root folder - def module_target_dir - @module_target_dir ||= File.expand_path('spec/fixtures/modules') - end + # @return [String] - the spec/fixtures/modules directory in the module root folder + def module_target_dir + @module_target_dir ||= File.expand_path('spec/fixtures/modules') + end - # @return [Boolean] - returns true if the module was downloaded successfully, false otherwise - # @param [String] - the remote url or namespace/name of the module to download - # @param [Hash] - list of options such as version - def download_module(remote, opts) - ref = '' - flags = '' - if opts.instance_of?(String) - target = opts - elsif opts.instance_of?(Hash) - target = opts['target'] - ref = " --version #{opts['ref']}" unless opts['ref'].nil? - flags = " #{opts['flags']}" if opts['flags'] - end + # @return [Boolean] - returns true if the module was downloaded successfully, false otherwise + # @param [String] - the remote url or namespace/name of the module to download + # @param [Hash] - list of options such as version + def download_module(remote, opts) + ref = '' + flags = '' + if opts.instance_of?(String) + target = opts + elsif opts.instance_of?(Hash) + target = opts['target'] + ref = " --version #{opts['ref']}" unless opts['ref'].nil? + flags = " #{opts['flags']}" if opts['flags'] + end - return false if File.directory?(target) && (ref.empty? || opts['ref'] == module_version(target)) + return false if File.directory?(target) && (ref.empty? || opts['ref'] == module_version(target)) - # The PMT cannot handle multi threaded runs due to cache directory collisons - # so we randomize the directory instead. - # Does working_dir even need to be passed? - Dir.mktmpdir do |working_dir| - command = "puppet module install#{ref}#{flags} --ignore-dependencies" \ - ' --force' \ - " --module_working_dir \"#{working_dir}\"" \ - " --target-dir \"#{module_target_dir}\" \"#{remote}\"" + # The PMT cannot handle multi threaded runs due to cache directory collisons + # so we randomize the directory instead. + # Does working_dir even need to be passed? + Dir.mktmpdir do |working_dir| + command = "puppet module install#{ref}#{flags} --ignore-dependencies" \ + ' --force' \ + " --module_working_dir \"#{working_dir}\"" \ + " --target-dir \"#{module_target_dir}\" \"#{remote}\"" - unless system(command) - raise "Failed to install module #{remote} to #{module_target_dir}" + unless system(command) + raise "Failed to install module #{remote} to #{module_target_dir}" + end + end + $CHILD_STATUS.success? end end - $CHILD_STATUS.success? end end From 8a816ec34173fd3497ae95dfb05693a7ecc49a04 Mon Sep 17 00:00:00 2001 From: Craig Gumbley Date: Wed, 25 Jan 2023 10:23:30 +0000 Subject: [PATCH 2/3] (MAINT) Update rubocop config This commit allows rubocop to use the default of nested for the ClassAndModuleChildren cop. --- .rubocop.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 030714c4..133888d8 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -36,9 +36,6 @@ Style/BlockDelimiters: Description: Prefer braces for chaining. Mostly an aesthetical choice. Better to be consistent then. EnforcedStyle: braces_for_chaining -Style/ClassAndModuleChildren: - Description: Compact style reduces the required amount of indentation. - EnforcedStyle: compact Style/EmptyElse: Description: Enforce against empty else clauses, but allow `nil` for clarity. EnforcedStyle: empty From ca4e730f2d9f327dfe08ac3d346d54b1e8816677 Mon Sep 17 00:00:00 2001 From: Craig Gumbley Date: Wed, 25 Jan 2023 10:31:49 +0000 Subject: [PATCH 3/3] (MAINT) Update module and class style --- .../puppetlabs_spec/files.rb | 84 ++++++++++--------- .../puppetlabs_spec/fixtures.rb | 84 ++++++++++--------- .../puppetlabs_spec/puppet_internals.rb | 66 ++++++++------- .../tasks/check_symlinks.rb | 78 +++++++++-------- 4 files changed, 161 insertions(+), 151 deletions(-) diff --git a/lib/puppetlabs_spec_helper/puppetlabs_spec/files.rb b/lib/puppetlabs_spec_helper/puppetlabs_spec/files.rb index 7c4cac85..5017ec32 100755 --- a/lib/puppetlabs_spec_helper/puppetlabs_spec/files.rb +++ b/lib/puppetlabs_spec_helper/puppetlabs_spec/files.rb @@ -6,56 +6,58 @@ require 'tempfile' require 'pathname' -# A support module for testing files. -module PuppetlabsSpec::Files - # This code exists only to support tests that run as root, pretty much. - # Once they have finally been eliminated this can all go... --daniel 2011-04-08 - def self.in_tmp(path) - tempdir = Dir.tmpdir - - Pathname.new(path).ascend do |dir| - return true if File.identical?(tempdir, dir) - end +module PuppetlabsSpec + # A support module for testing files. + module Files + # This code exists only to support tests that run as root, pretty much. + # Once they have finally been eliminated this can all go... --daniel 2011-04-08 + def self.in_tmp(path) + tempdir = Dir.tmpdir + + Pathname.new(path).ascend do |dir| + return true if File.identical?(tempdir, dir) + end - false - end + false + end - def self.cleanup - $global_tempfiles ||= [] - while (path = $global_tempfiles.pop) - raise "Not deleting tmpfile #{path} outside regular tmpdir" unless in_tmp(path) + def self.cleanup + $global_tempfiles ||= [] + while (path = $global_tempfiles.pop) + raise "Not deleting tmpfile #{path} outside regular tmpdir" unless in_tmp(path) - begin - FileUtils.rm_r path, secure: true - rescue Errno::ENOENT - # nothing to do + begin + FileUtils.rm_r path, secure: true + rescue Errno::ENOENT + # nothing to do + end end end - end - def make_absolute(path) - path = File.expand_path(path) - path[0] = 'c' if Puppet.features.microsoft_windows? - path - end + def make_absolute(path) + path = File.expand_path(path) + path[0] = 'c' if Puppet.features.microsoft_windows? + path + end - def tmpfilename(name) - # Generate a temporary file, just for the name... - source = Tempfile.new(name) - path = source.path - source.close! + def tmpfilename(name) + # Generate a temporary file, just for the name... + source = Tempfile.new(name) + path = source.path + source.close! - # ...record it for cleanup, - $global_tempfiles ||= [] - $global_tempfiles << File.expand_path(path) + # ...record it for cleanup, + $global_tempfiles ||= [] + $global_tempfiles << File.expand_path(path) - # ...and bam. - path - end + # ...and bam. + path + end - def tmpdir(name) - path = tmpfilename(name) - FileUtils.mkdir_p(path) - path + def tmpdir(name) + path = tmpfilename(name) + FileUtils.mkdir_p(path) + path + end end end diff --git a/lib/puppetlabs_spec_helper/puppetlabs_spec/fixtures.rb b/lib/puppetlabs_spec_helper/puppetlabs_spec/fixtures.rb index ac605990..65861e1f 100755 --- a/lib/puppetlabs_spec_helper/puppetlabs_spec/fixtures.rb +++ b/lib/puppetlabs_spec_helper/puppetlabs_spec/fixtures.rb @@ -1,53 +1,55 @@ # frozen_string_literal: true -# This module provides some helper methods to assist with fixtures. It's -# methods are designed to help when you have a conforming fixture layout so we -# get project consistency. -module PuppetlabsSpec::Fixtures - # Returns the joined path of the global FIXTURE_DIR plus any path given to it - def fixtures(*rest) - File.join(PuppetlabsSpec::FIXTURE_DIR, *rest) - end - - # Returns the path to your relative fixture dir. So if your spec test is - # /spec/unit/facter/foo_spec.rb then your relative dir will be - # /spec/fixture/unit/facter/foo - def my_fixture_dir - callers = caller - while (line = callers.shift) - next unless (found = line.match(%r{/spec/(.*)_spec\.rb:})) - - return fixtures(found[1]) +module PuppetlabsSpec + # This module provides some helper methods to assist with fixtures. It's + # methods are designed to help when you have a conforming fixture layout so we + # get project consistency. + module Fixtures + # Returns the joined path of the global FIXTURE_DIR plus any path given to it + def fixtures(*rest) + File.join(PuppetlabsSpec::FIXTURE_DIR, *rest) end - raise "sorry, I couldn't work out your path from the caller stack!" - end - # Given a name, returns the full path of a file from your relative fixture - # dir as returned by my_fixture_dir. - def my_fixture(name) - file = File.join(my_fixture_dir, name) - unless File.readable? file - raise "fixture '#{name}' for #{my_fixture_dir} is not readable" + # Returns the path to your relative fixture dir. So if your spec test is + # /spec/unit/facter/foo_spec.rb then your relative dir will be + # /spec/fixture/unit/facter/foo + def my_fixture_dir + callers = caller + while (line = callers.shift) + next unless (found = line.match(%r{/spec/(.*)_spec\.rb:})) + + return fixtures(found[1]) + end + raise "sorry, I couldn't work out your path from the caller stack!" end - file - end + # Given a name, returns the full path of a file from your relative fixture + # dir as returned by my_fixture_dir. + def my_fixture(name) + file = File.join(my_fixture_dir, name) + unless File.readable? file + raise "fixture '#{name}' for #{my_fixture_dir} is not readable" + end - # Return the contents of the file using read when given a name. Uses - # my_fixture to work out the relative path. - def my_fixture_read(name) - File.read(my_fixture(name)) - end + file + end - # Provides a block mechanism for iterating across the files in your fixture - # area. - def my_fixtures(glob = '*', flags = 0, &block) - files = Dir.glob(File.join(my_fixture_dir, glob), flags) - if files.empty? - raise "fixture '#{glob}' for #{my_fixture_dir} had no files!" + # Return the contents of the file using read when given a name. Uses + # my_fixture to work out the relative path. + def my_fixture_read(name) + File.read(my_fixture(name)) end - block && files.each(&block) - files + # Provides a block mechanism for iterating across the files in your fixture + # area. + def my_fixtures(glob = '*', flags = 0, &block) + files = Dir.glob(File.join(my_fixture_dir, glob), flags) + if files.empty? + raise "fixture '#{glob}' for #{my_fixture_dir} had no files!" + end + + block && files.each(&block) + files + end end end diff --git a/lib/puppetlabs_spec_helper/puppetlabs_spec/puppet_internals.rb b/lib/puppetlabs_spec_helper/puppetlabs_spec/puppet_internals.rb index 057866be..a50e3b84 100644 --- a/lib/puppetlabs_spec_helper/puppetlabs_spec/puppet_internals.rb +++ b/lib/puppetlabs_spec_helper/puppetlabs_spec/puppet_internals.rb @@ -4,41 +4,43 @@ # 'puppetlabs_spec_helper/puppet_spec_helper' library require 'puppetlabs_spec_helper/puppet_spec_helper' -# PuppetInternals provides a set of methods that interface -# with internal puppet implementations. -module PuppetlabsSpec::PuppetInternals - def resource(parts = {}) - resource_type = parts[:type] || :hostclass - resource_name = parts[:name] || 'testing' - Puppet::Resource::Type.new(resource_type, resource_name) - end - module_function :resource +module PuppetlabsSpec + # PuppetInternals provides a set of methods that interface + # with internal puppet implementations. + module PuppetInternals + def resource(parts = {}) + resource_type = parts[:type] || :hostclass + resource_name = parts[:name] || 'testing' + Puppet::Resource::Type.new(resource_type, resource_name) + end + module_function :resource - def compiler(parts = {}) - compiler_node = parts[:node] || node - Puppet::Parser::Compiler.new(compiler_node) - end - module_function :compiler + def compiler(parts = {}) + compiler_node = parts[:node] || node + Puppet::Parser::Compiler.new(compiler_node) + end + module_function :compiler - def node(parts = {}) - node_name = parts[:name] || 'testinghost' - options = parts[:options] || {} - node_environment = Puppet::Node::Environment.create(parts[:environment] || 'test', []) - options[:environment] = node_environment - Puppet::Node.new(node_name, options) - end - module_function :node + def node(parts = {}) + node_name = parts[:name] || 'testinghost' + options = parts[:options] || {} + node_environment = Puppet::Node::Environment.create(parts[:environment] || 'test', []) + options[:environment] = node_environment + Puppet::Node.new(node_name, options) + end + module_function :node - # Return a method instance for a given function. This is primarily useful - # for rspec-puppet - def function_method(name, parts = {}) - scope = parts[:scope] || scope() - # Ensure the method instance is defined by side-effect of checking if it - # exists. This is a hack, but at least it's a hidden hack and not an - # exposed hack. - return nil unless Puppet::Parser::Functions.function(name) + # Return a method instance for a given function. This is primarily useful + # for rspec-puppet + def function_method(name, parts = {}) + scope = parts[:scope] || scope() + # Ensure the method instance is defined by side-effect of checking if it + # exists. This is a hack, but at least it's a hidden hack and not an + # exposed hack. + return nil unless Puppet::Parser::Functions.function(name) - scope.method("function_#{name}".to_sym) + scope.method("function_#{name}".to_sym) + end + module_function :function_method end - module_function :function_method end diff --git a/lib/puppetlabs_spec_helper/tasks/check_symlinks.rb b/lib/puppetlabs_spec_helper/tasks/check_symlinks.rb index 3b86c9fc..99944ce2 100644 --- a/lib/puppetlabs_spec_helper/tasks/check_symlinks.rb +++ b/lib/puppetlabs_spec_helper/tasks/check_symlinks.rb @@ -2,48 +2,52 @@ require 'pathspec' -# Helpers for validating symlinks. -class PuppetlabsSpecHelper::Tasks::CheckSymlinks - DEFAULT_IGNORED = [ - '/.git/', - '/.bundle/', - '/vendor/', - ].freeze - - IGNORE_LIST_FILES = [ - '.pdkignore', - '.gitignore', - ].freeze - - def check(dir = Dir.pwd) - dir = Pathname.new(dir) unless dir.is_a?(Pathname) - results = [] - - dir.each_child(true) do |child| - next if ignored?(child.to_s) - - if child.symlink? - results << child - elsif child.directory? && child.basename.to_s !~ %r{^(\.git|\.?bundle)$} - results.concat(check(child)) +module PuppetlabsSpecHelper + module Tasks + # Helpers for validating symlinks. + class CheckSymlinks + DEFAULT_IGNORED = [ + '/.git/', + '/.bundle/', + '/vendor/', + ].freeze + + IGNORE_LIST_FILES = [ + '.pdkignore', + '.gitignore', + ].freeze + + def check(dir = Dir.pwd) + dir = Pathname.new(dir) unless dir.is_a?(Pathname) + results = [] + + dir.each_child(true) do |child| + next if ignored?(child.to_s) + + if child.symlink? + results << child + elsif child.directory? && child.basename.to_s !~ %r{^(\.git|\.?bundle)$} + results.concat(check(child)) + end + end + + results end - end - - results - end - def ignored?(path) - path = "#{path}/" if File.directory?(path) + def ignored?(path) + path = "#{path}/" if File.directory?(path) - !ignore_pathspec.match_paths([path], Dir.pwd).empty? - end + !ignore_pathspec.match_paths([path], Dir.pwd).empty? + end - def ignore_pathspec - @ignore_pathspec ||= PathSpec.new(DEFAULT_IGNORED).tap do |pathspec| - IGNORE_LIST_FILES.each do |f| - next unless File.file?(f) && File.readable?(f) + def ignore_pathspec + @ignore_pathspec ||= PathSpec.new(DEFAULT_IGNORED).tap do |pathspec| + IGNORE_LIST_FILES.each do |f| + next unless File.file?(f) && File.readable?(f) - File.open(f, 'r') { |fd| pathspec.add(fd) } + File.open(f, 'r') { |fd| pathspec.add(fd) } + end + end end end end