require 'fileutils' require 'rake' require 'rspec/core/rake_task' require 'tmpdir' require 'pathname' require 'puppetlabs_spec_helper/version' require 'puppetlabs_spec_helper/tasks/fixtures' require 'puppetlabs_spec_helper/tasks/check_symlinks' require 'English' # dont load beaker if litmus is present require 'puppetlabs_spec_helper/tasks/beaker' unless Bundler.rubygems.find_name('puppet_litmus').any? # optional gems begin require 'metadata-json-lint/rake_task' rescue LoadError # ignore end begin require 'puppet_blacksmith/rake_tasks' rescue LoadError # ignore end begin require 'github_changelog_generator/task' rescue LoadError # ignore end begin require 'puppet-strings/tasks' rescue LoadError # ignore end parallel_tests_loaded = false begin require 'parallel_tests' parallel_tests_loaded = true rescue LoadError # ignore end task default: [:help] pattern = 'spec/{aliases,classes,defines,functions,hosts,integration,plans,tasks,type_aliases,types,unit}/**/*_spec.rb' RSpec::Core::RakeTask.new(:spec_standalone) do |t, args| t.rspec_opts = [] t.rspec_opts << ENV['CI_SPEC_OPTIONS'] unless ENV['CI_SPEC_OPTIONS'].nil? if ENV['CI_NODE_TOTAL'] && ENV['CI_NODE_INDEX'] ci_total = ENV['CI_NODE_TOTAL'].to_i ci_index = ENV['CI_NODE_INDEX'].to_i raise "CI_NODE_INDEX must be between 1-#{ci_total}" unless ci_index >= 1 && ci_index <= ci_total files = Rake::FileList[pattern].to_a per_node = (files.size / ci_total.to_f).ceil t.pattern = if args.extras.nil? || args.extras.empty? files.each_slice(per_node).to_a[ci_index - 1] || files.first else args.extras.join(',') end else t.pattern = if args.extras.nil? || args.extras.empty? pattern else args.extras.join(',') end end end desc 'List spec tests in a JSON document' RSpec::Core::RakeTask.new(:spec_list_json) do |t| t.rspec_opts = ['--dry-run', '--format', 'json'] t.pattern = pattern end desc 'Run spec tests and clean the fixtures directory if successful' task :spec do |_t, args| begin Rake::Task[:spec_prep].invoke Rake::Task[:spec_standalone].invoke(*args.extras) Rake::Task[:spec_clean].invoke ensure Rake::Task[:spec_clean_symlinks].invoke end end desc 'Run spec tests with ruby simplecov code coverage' namespace :spec do task :simplecov do ENV['SIMPLECOV'] = 'yes' Rake::Task['spec'].execute end end desc 'Run spec tests in parallel and clean the fixtures directory if successful' task :parallel_spec do |_t, args| begin Rake::Task[:spec_prep].invoke Rake::Task[:parallel_spec_standalone].invoke(*args.extras) Rake::Task[:spec_clean].invoke ensure Rake::Task[:spec_clean_symlinks].invoke end end desc 'Parallel spec tests' task :parallel_spec_standalone do |_t, args| raise 'Add the parallel_tests gem to Gemfile to enable this task' unless parallel_tests_loaded if Rake::FileList[pattern].to_a.empty? warn 'No files for parallel_spec to run against' else begin args = ['-t', 'rspec'] args.push('--').concat(ENV['CI_SPEC_OPTIONS'].strip.split(' ')).push('--') unless ENV['CI_SPEC_OPTIONS'].nil? || ENV['CI_SPEC_OPTIONS'].strip.empty? args.concat(Rake::FileList[pattern].to_a) ParallelTests::CLI.new.run(args) end end end desc 'Build puppet module package' task :build do if Gem::Specification.find_by_name('puppet').version < Gem::Version.new('6.0.0') Rake::Task['build:pmt'].invoke else Rake::Task['build:pdk'].invoke end end namespace :build do desc 'Build Puppet module package with PMT (Puppet < 6.0.0 only)' task :pmt do require 'puppet/face' pmod = Puppet::Face['module', :current] pmod.build('./') end desc 'Build Puppet module with PDK' task :pdk do begin require 'pdk/module/build' path = PDK::Module::Build.invoke(:force => true, :'target-dir' => File.join(Dir.pwd, 'pkg')) puts "Module built: #{path}" rescue LoadError _ = `pdk --version` unless $CHILD_STATUS.success? $stderr.puts 'Unable to build module. Please install PDK or add the `pdk` gem to your Gemfile.' abort end system('pdk build --force') end end end desc 'Clean a built module package' task :clean do FileUtils.rm_rf('pkg/') end require 'puppet-lint/tasks/puppet-lint' # Must clear as it will not override the existing puppet-lint rake task since we require to import for # the PuppetLint::RakeTask Rake::Task[:lint].clear # Relative is not able to be set within the context of PuppetLint::RakeTask PuppetLint.configuration.relative = true PuppetLint::RakeTask.new(:lint) do |config| config.fail_on_warnings = true config.disable_checks = %w[ 80chars 140chars class_inherits_from_params_class class_parameter_defaults disable_autoloader_layout documentation single_quote_string_with_variables ] config.ignore_paths = [ '.vendor/**/*.pp', 'bundle/**/*.pp', 'pkg/**/*.pp', 'spec/**/*.pp', 'tests/**/*.pp', 'types/**/*.pp', 'vendor/**/*.pp', ] end desc 'Run puppet-lint and fix issues automatically' PuppetLint::RakeTask.new(:lint_fix) do |config| config.fail_on_warnings = true config.fix = true config.disable_checks = %w[ 80chars 140chars class_inherits_from_params_class class_parameter_defaults disable_autoloader_layout documentation single_quote_string_with_variables ] config.ignore_paths = [ '.vendor/**/*.pp', 'bundle/**/*.pp', 'pkg/**/*.pp', 'spec/**/*.pp', 'tests/**/*.pp', 'types/**/*.pp', 'vendor/**/*.pp', ] end require 'puppet-syntax/tasks/puppet-syntax' PuppetSyntax.exclude_paths ||= [] PuppetSyntax.exclude_paths << 'spec/fixtures/**/*' PuppetSyntax.exclude_paths << 'pkg/**/*' PuppetSyntax.exclude_paths << 'vendor/**/*' PuppetSyntax.exclude_paths << 'plans/*' if Puppet.version.to_f < 4.0 PuppetSyntax.exclude_paths << 'types/**/*' end PuppetSyntax.future_parser = true if ENV['FUTURE_PARSER'] == 'yes' desc 'Check syntax of Ruby files and call :syntax and :metadata_lint' task :validate do Dir['lib/**/*.rb'].each do |lib_file| sh "ruby -c #{lib_file}" end Rake::Task[:syntax].invoke if File.exist?('metadata.json') if Rake::Task.task_defined?(:metadata_lint) Rake::Task[:metadata_lint].invoke else warn 'Skipping metadata validation; the metadata-json-lint gem was not found' end end end task :metadata do warn "The 'metadata' task is deprecated. Please use 'metadata_lint' instead." if Rake::Task.task_defined?(:metadata_lint) Rake::Task[:metadata_lint].invoke else warn 'Skipping metadata validation; the metadata-json-lint gem was not found' end end desc 'Print development version of module' task :compute_dev_version do version = '' if File.exist?('metadata.json') require 'json' modinfo = JSON.parse(File.read('metadata.json')) version = modinfo['version'] elsif File.exist?('Modulefile') modfile = File.read('Modulefile') version = modfile.match(%r{\nversion[ ]+['"](.*)['"]})[1] else raise 'Could not find a metadata.json or Modulefile! Cannot compute dev version without one or the other!' end sha = `git rev-parse HEAD`[0..7] branch = `git rev-parse --abbrev-ref HEAD` # If we're in a CI environment include our build number # If the branch is a release branch we append an 'r' into the new_version, # this is due to the release branch buildID conflicting with master branch when trying to push to the staging forge. # More info can be found at https://tickets.puppetlabs.com/browse/FM-6170 new_version = if build = ENV['BUILD_NUMBER'] || ENV['TRAVIS_BUILD_NUMBER'] if branch.eql? 'release' '%s-%s%04d-%s' % [version, 'r', build, sha] else '%s-%04d-%s' % [version, build, sha] end else "#{version}-#{sha}" end print new_version end desc 'Runs all necessary checks on a module in preparation for a release' task :release_checks do Rake::Task[:lint].invoke Rake::Task[:validate].invoke if parallel_tests_loaded Rake::Task[:parallel_spec].invoke else Rake::Task[:spec].invoke end Rake::Task['check:symlinks'].invoke Rake::Task['check:test_file'].invoke Rake::Task['check:dot_underscore'].invoke Rake::Task['check:git_ignore'].invoke end namespace :check do desc 'Fails if symlinks are present in directory' task :symlinks do symlinks = PuppetlabsSpecHelper::Tasks::CheckSymlinks.new.check unless symlinks.empty? symlinks.each { |r| puts "Symlink found: #{r} => #{r.readlink}" } raise 'Symlink(s) exist within this directory' end end desc 'Fails if .pp files present in tests folder' task :test_file do ppfiles = Dir[File.join('tests', '**', '*.pp')] unless ppfiles.empty? puts ppfiles raise '.pp files present in tests folder; Move them to an examples folder following the new convention' end end desc 'Fails if any ._ files are present in directory' task :dot_underscore do dirs = Dir['._*'] unless dirs.empty? puts dirs raise '._ files are present in the directory' end end desc 'Fails if directories contain the files specified in .gitignore' task :git_ignore do matched = `git ls-files --ignored --exclude-standard` unless matched == '' puts matched raise 'File specified in .gitignore has been committed' end end end desc 'Display the list of available rake tasks' task :help do system('rake -T') end begin require 'rubocop/rake_task' RuboCop::RakeTask.new(:rubocop) do |task| # These make the rubocop experience maybe slightly less terrible task.options = ['-D', '-S', '-E'] end rescue LoadError desc 'rubocop is not available in this installation' task :rubocop do raise 'rubocop is not available in this installation' end end module_dir = Dir.pwd locales_dir = File.absolute_path('locales', module_dir) # if the task is allowed to run when the module does not have a locales directory, # the task is run in the puppet gem instead and creates a POT there. puts 'gettext-setup tasks will only be loaded if the locales/ directory is present' if Rake.verbose == true if File.exist? locales_dir begin spec = Gem::Specification.find_by_name 'gettext-setup' load "#{spec.gem_dir}/lib/tasks/gettext.rake" # Initialization requires a valid locales directory GettextSetup.initialize_config(locales_dir) namespace :module do desc 'Runs all tasks to build a modules POT file for internationalization' task :pot_gen do Rake::Task['gettext:pot'].invoke Rake::Task['gettext:metadata_pot'].invoke("#{module_dir}/metadata.json") end end rescue Gem::LoadError puts 'No gettext-setup gem found, skipping GettextSetup config initialization' if Rake.verbose == true end end