diff --git a/.fixtures.yml b/.fixtures.yml index 3c6f0b7..4d1fe61 100644 --- a/.fixtures.yml +++ b/.fixtures.yml @@ -1,3 +1,6 @@ +# This file can be used to install module dependencies for unit testing +# See https://github.com/puppetlabs/puppetlabs_spec_helper#using-fixtures for details +--- fixtures: - symlinks: - hash2stuff: "#{source_dir}" + forge_modules: + stdlib: "puppetlabs/stdlib" diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9032a01 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +*.rb eol=lf +*.erb eol=lf +*.pp eol=lf +*.sh eol=lf +*.epp eol=lf diff --git a/.gitignore b/.gitignore index b2241c1..2767022 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,27 @@ -pkg/ -spec/fixtures/ -.rspec_system/ -.vagrant/ -.bundle/ -vendor/ -Gemfile.lock -log/ +.git/ +.*.sw[op] +.metadata +.yardoc +.yardwarns +*.iml +/.bundle/ +/.idea/ +/.vagrant/ +/coverage/ +/bin/ +/doc/ +/Gemfile.local +/Gemfile.lock +/junit/ +/log/ +/pkg/ +/spec/fixtures/manifests/ +/spec/fixtures/modules/ +/tmp/ +/vendor/ +/convert_report.txt +/update_report.txt +.DS_Store +.project +.envrc +/inventory.yaml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..4868bf7 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,44 @@ +--- +stages: + - syntax + - unit + +cache: + paths: + - vendor/bundle + +before_script: + - bundle -v + - rm Gemfile.lock || true + - "# Update system gems if requested. This is useful to temporarily workaround troubles in the test runner" + - "# Set `rubygems_version` in the .sync.yml to set a value" + - "# Ignore exit code of SIGPIPE'd yes to not fail with shell's pipefail set" + - '[ -z "$RUBYGEMS_VERSION" ] || (yes || true) | gem update --system $RUBYGEMS_VERSION' + - gem --version + - bundle -v + - bundle install --without system_tests --path vendor/bundle --jobs $(nproc) + +syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop-Ruby 2.5.7-Puppet ~> 6: + stage: syntax + image: ruby:2.5.7 + script: + - bundle exec rake syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop + variables: + PUPPET_GEM_VERSION: '~> 6' + +parallel_spec-Ruby 2.5.7-Puppet ~> 6: + stage: unit + image: ruby:2.5.7 + script: + - bundle exec rake parallel_spec + variables: + PUPPET_GEM_VERSION: '~> 6' + +parallel_spec-Ruby 2.4.5-Puppet ~> 5: + stage: unit + image: ruby:2.4.5 + script: + - bundle exec rake parallel_spec + variables: + PUPPET_GEM_VERSION: '~> 5' + diff --git a/.pdkignore b/.pdkignore new file mode 100644 index 0000000..e6215cd --- /dev/null +++ b/.pdkignore @@ -0,0 +1,42 @@ +.git/ +.*.sw[op] +.metadata +.yardoc +.yardwarns +*.iml +/.bundle/ +/.idea/ +/.vagrant/ +/coverage/ +/bin/ +/doc/ +/Gemfile.local +/Gemfile.lock +/junit/ +/log/ +/pkg/ +/spec/fixtures/manifests/ +/spec/fixtures/modules/ +/tmp/ +/vendor/ +/convert_report.txt +/update_report.txt +.DS_Store +.project +.envrc +/inventory.yaml +/appveyor.yml +/.fixtures.yml +/Gemfile +/.gitattributes +/.gitignore +/.gitlab-ci.yml +/.pdkignore +/Rakefile +/rakelib/ +/.rspec +/.rubocop.yml +/.travis.yml +/.yardopts +/spec/ +/.vscode/ diff --git a/.puppet-lint.rc b/.puppet-lint.rc new file mode 100644 index 0000000..cc96ece --- /dev/null +++ b/.puppet-lint.rc @@ -0,0 +1 @@ +--relative diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..16f9cdb --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--color +--format documentation diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..5307849 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,137 @@ +--- +require: +- rubocop-rspec +- rubocop-i18n +AllCops: + DisplayCopNames: true + TargetRubyVersion: '2.1' + Include: + - "./**/*.rb" + Exclude: + - bin/* + - ".vendor/**/*" + - "**/Gemfile" + - "**/Rakefile" + - pkg/**/* + - spec/fixtures/**/* + - vendor/**/* + - "**/Puppetfile" + - "**/Vagrantfile" + - "**/Guardfile" +Metrics/LineLength: + Description: People have wide screens, use them. + Max: 200 +GetText: + Enabled: false +GetText/DecorateString: + Description: We don't want to decorate test output. + Exclude: + - spec/**/* + Enabled: false +RSpec/BeforeAfterAll: + Description: Beware of using after(:all) as it may cause state to leak between tests. + A necessary evil in acceptance testing. + Exclude: + - spec/acceptance/**/*.rb +RSpec/HookArgument: + Description: Prefer explicit :each argument, matching existing module's style + EnforcedStyle: each +Style/BlockDelimiters: + Description: Prefer braces for chaining. Mostly an aesthetical choice. Better to + be consistent then. + EnforcedStyle: braces_for_chaining +Style/BracesAroundHashParameters: + Description: Braces are required by Ruby 2.7. Cop removed from RuboCop v0.80.0. + See https://github.com/rubocop-hq/rubocop/pull/7643 + Enabled: true +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 +Style/FormatString: + Description: Following the main puppet project's style, prefer the % format format. + EnforcedStyle: percent +Style/FormatStringToken: + Description: Following the main puppet project's style, prefer the simpler template + tokens over annotated ones. + EnforcedStyle: template +Style/Lambda: + Description: Prefer the keyword for easier discoverability. + EnforcedStyle: literal +Style/RegexpLiteral: + Description: Community preference. See https://github.com/voxpupuli/modulesync_config/issues/168 + EnforcedStyle: percent_r +Style/TernaryParentheses: + Description: Checks for use of parentheses around ternary conditions. Enforce parentheses + on complex expressions for better readability, but seriously consider breaking + it up. + EnforcedStyle: require_parentheses_when_complex +Style/TrailingCommaInArguments: + Description: Prefer always trailing comma on multiline argument lists. This makes + diffs, and re-ordering nicer. + EnforcedStyleForMultiline: comma +Style/TrailingCommaInLiteral: + Description: Prefer always trailing comma on multiline literals. This makes diffs, + and re-ordering nicer. + EnforcedStyleForMultiline: comma +Style/SymbolArray: + Description: Using percent style obscures symbolic intent of array's contents. + EnforcedStyle: brackets +RSpec/MessageSpies: + EnforcedStyle: receive +Style/Documentation: + Exclude: + - lib/puppet/parser/functions/**/* + - spec/**/* +Style/WordArray: + EnforcedStyle: brackets +Style/CollectionMethods: + Enabled: true +Style/MethodCalledOnDoEndBlock: + Enabled: true +Style/StringMethods: + Enabled: true +GetText/DecorateFunctionMessage: + Enabled: false +GetText/DecorateStringFormattingUsingInterpolation: + Enabled: false +GetText/DecorateStringFormattingUsingPercent: + Enabled: false +Layout/EndOfLine: + Enabled: false +Layout/IndentHeredoc: + Enabled: false +Metrics/AbcSize: + Enabled: false +Metrics/BlockLength: + Enabled: false +Metrics/ClassLength: + Enabled: false +Metrics/CyclomaticComplexity: + Enabled: false +Metrics/MethodLength: + Enabled: false +Metrics/ModuleLength: + Enabled: false +Metrics/ParameterLists: + Enabled: false +Metrics/PerceivedComplexity: + Enabled: false +RSpec/DescribeClass: + Enabled: false +RSpec/ExampleLength: + Enabled: false +RSpec/MessageExpectation: + Enabled: false +RSpec/MultipleExpectations: + Enabled: false +RSpec/NestedGroups: + Enabled: false +Style/AsciiComments: + Enabled: false +Style/IfUnlessModifier: + Enabled: false +Style/SymbolProc: + Enabled: false diff --git a/.travis.yml b/.travis.yml index 440f56a..68d3e96 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,42 +1,49 @@ --- +os: linux +dist: xenial language: ruby -bundler_args: --without development system_tests -before_install: rm Gemfile.lock || true -matrix: +cache: bundler +before_install: + - bundle -v + - rm -f Gemfile.lock + - "# Update system gems if requested. This is useful to temporarily workaround troubles in the test runner" + - "# See https://github.com/puppetlabs/pdk-templates/commit/705154d5c437796b821691b707156e1b056d244f for an example of how this was used" + - "# Ignore exit code of SIGPIPE'd yes to not fail with shell's pipefail set" + - '[ -z "$RUBYGEMS_VERSION" ] || (yes || true) | gem update --system $RUBYGEMS_VERSION' + - gem --version + - bundle -v +script: + - 'bundle exec rake $CHECK' +bundler_args: --without system_tests +rvm: + - 2.5.7 +stages: + - static + - spec + - acceptance + - + if: tag =~ ^v\d + name: deploy +jobs: + fast_finish: true include: - # these versions of ruby were somewhat supported up to puppet 4.8, then - # deprecated in puppet 4.9. we'll keep testing them for now... - # - # https://docs.puppet.com/puppet/4.9/release_notes.html#ruby-20-series - # https://docs.puppet.com/puppet/4.8/system_requirements.html#ruby - - rvm: 2.0.0 - env: PUPPET_GEM_VERSION="~> 4.8.0" STRICT_VARIABLES=yes - - rvm: 2.2.0 - env: PUPPET_GEM_VERSION="~> 4.8.0" STRICT_VARIABLES=yes - - rvm: 2.3.0 - env: PUPPET_GEM_VERSION="~> 4.8.0" STRICT_VARIABLES=yes - - # always test the latest versions of puppet in the 3.x, 4.x, 5.x, 6.x lines - - rvm: 2.1.0 - env: PUPPET_GEM_VERSION="~> 3.0" STRICT_VARIABLES=yes - - rvm: 2.1.0 - env: PUPPET_GEM_VERSION="~> 4.0" STRICT_VARIABLES=yes DEPLOY_TO_FORGE=yes - - rvm: 2.4.0 - env: PUPPET_GEM_VERSION="~> 5.0" STRICT_VARIABLES=yes - - rvm: 2.5.0 - env: PUPPET_GEM_VERSION="~> 6.0" STRICT_VARIABLES=yes - -script: "bundle exec rake validate && bundle exec rake lint && bundle exec rake spec SPEC_OPTS='--format documentation'" + - + env: CHECK="check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop syntax lint metadata_lint" + stage: static + - + env: PUPPET_GEM_VERSION="~> 5.0" CHECK=parallel_spec + rvm: 2.4.5 + stage: spec + - + env: PUPPET_GEM_VERSION="~> 6.0" CHECK=parallel_spec + rvm: 2.5.7 + stage: spec + - + env: DEPLOY_TO_FORGE=yes + stage: deploy +branches: + only: + - master + - /^v\d/ notifications: email: false -deploy: - provider: puppetforge - user: mmckinst - password: - secure: U95IYVdpILpz3VavlT3YoTcsBe20YkG70AfXtHL526HYcBlpnmsZljsQw1arX0jfiliKhIwsl2FJhG73IBaJ5udy5tlhGmttpJJcga9SMGUIntYz+AEyvPKzClu8Cf7zWop0Rt/lv/51bSr/ICYE2R0yoasL3ScuSqKQRqf9VUULnbIghHJ6dmPQtHQRtJVaHNTWQgb6PXDOnqsjoF5B/yqTafeB+nj/v/9NOXDfcaGpaGmkiVqkZkhtjn1RjFHf5ftrIoMrdPVV3u6cFaNrTEhpFk3EpGLbvqsSyQ3e/5TINi/ni2RpW949/jZCp+AXu7Wi9eoLG72KUNMZUY5PHegu1GKq0bDV5U79sPamDdkAT2YXa+LvNkCZPLmssGe18QYFD/YQiR+ZUIRhvmno3GCXVfqdogi+AbCqVnPJk4gqKbgO9ggHKik9Px/yoS+Ic6JDTOlf535BYYlqpS6R17xTe4BIud1/XZvb6ditt6+D+A9CyosoKVg4AzdPt/zZ3sFzYzMvRAM1TRbHLtePOVztpJ/Y4F/nnMN6CLcC9SEPgCtBgqvjw/VMIs5961/wPHq5TCXngI7XcnMhYYQltgsJXi6gRlw/grgB34Q0Iy9FYSC/i6ek/LrD5xeNQIJRIXndieCBlFlLTjAMqml5LA+6+I4MUOIqmNbsmEeGWvo= - on: - tags: true - # all_branches is required to use tags - all_branches: true - # Only publish the build marked with "DEPLOY_TO_FORGE" - condition: "$DEPLOY_TO_FORGE = yes" diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..2f1e4f7 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "puppet.puppet-vscode", + "rebornix.Ruby" + ] +} diff --git a/.yardopts b/.yardopts new file mode 100644 index 0000000..29c933b --- /dev/null +++ b/.yardopts @@ -0,0 +1 @@ +--markup markdown diff --git a/CHANGELOG.md b/CHANGELOG.md index 64c17be..9755fc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## 1.3.0 (2021-02-28) - Updates contributed by southalc +- Converted to PDK, linted, validated +- Add support for Puppet 7 +- Refactored legacy 3.x functions to 4.x API +- Updated unit tests as needed for changes +- Documentation using puppet strings +- Added defined types to complement the respective functions for use from hiera +- Support all releases of puppet supported operating system + ## 1.2.1 (2019-06-25) - Document overlaps with stdlib - Test on puppet 6 diff --git a/Gemfile b/Gemfile index 635766d..8007ad0 100644 --- a/Gemfile +++ b/Gemfile @@ -1,31 +1,72 @@ -source 'https://rubygems.org' - -group :tests do - gem 'puppetlabs_spec_helper' - gem 'puppet-lint', '~>2.0' - gem 'puppet-lint-unquoted_string-check' - gem 'puppet-lint-empty_string-check' - gem 'puppet-lint-leading_zero-check' - gem 'puppet-lint-variable_contains_upcase' - gem 'puppet-lint-version_comparison-check' - gem 'rspec' - gem 'rspec-puppet' - gem 'rspec-puppet-facts' - gem 'metadata-json-lint' +source ENV['GEM_SOURCE'] || 'https://rubygems.org' + +def location_for(place_or_version, fake_version = nil) + git_url_regex = %r{\A(?(https?|git)[:@][^#]*)(#(?.*))?} + file_url_regex = %r{\Afile:\/\/(?.*)} + + 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 }] + end end +ruby_version_segments = Gem::Version.new(RUBY_VERSION.dup).segments +minor_version = ruby_version_segments[0..1].join('.') + group :development do - gem "puppet-blacksmith" + gem "fast_gettext", '1.1.0', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.1.0') + gem "fast_gettext", require: false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.1.0') + gem "json_pure", '<= 2.0.1', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0') + gem "json", '= 1.8.1', require: false if Gem::Version.new(RUBY_VERSION.dup) == Gem::Version.new('2.1.9') + gem "json", '= 2.0.4', require: false if Gem::Requirement.create('~> 2.4.2').satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "json", '= 2.1.0', require: false if Gem::Requirement.create(['>= 2.5.0', '< 2.7.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "rb-readline", '= 0.5.5', require: false, platforms: [:mswin, :mingw, :x64_mingw] + gem "puppet-module-posix-default-r#{minor_version}", '~> 0.4', require: false, platforms: [:ruby] + gem "puppet-module-posix-dev-r#{minor_version}", '~> 0.4', require: false, platforms: [:ruby] + gem "puppet-module-win-default-r#{minor_version}", '~> 0.4', require: false, platforms: [:mswin, :mingw, :x64_mingw] + gem "puppet-module-win-dev-r#{minor_version}", '~> 0.4', require: false, platforms: [:mswin, :mingw, :x64_mingw] end -if facterversion = ENV['FACTER_GEM_VERSION'] - gem 'facter', facterversion, :require => false -else - gem 'facter', :require => false +puppet_version = ENV['PUPPET_GEM_VERSION'] +facter_version = ENV['FACTER_GEM_VERSION'] +hiera_version = ENV['HIERA_GEM_VERSION'] + +gems = {} + +gems['puppet'] = location_for(puppet_version) + +# If facter or hiera versions have been specified via the environment +# variables + +gems['facter'] = location_for(facter_version) if facter_version +gems['hiera'] = location_for(hiera_version) if hiera_version + +if Gem.win_platform? && puppet_version =~ %r{^(file:///|git://)} + # If we're using a Puppet gem on Windows which handles its own win32-xxx gem + # dependencies (>= 3.5.0), set the maximum versions (see PUP-6445). + gems['win32-dir'] = ['<= 0.4.9', require: false] + gems['win32-eventlog'] = ['<= 0.6.5', require: false] + gems['win32-process'] = ['<= 0.7.5', require: false] + gems['win32-security'] = ['<= 0.2.5', require: false] + gems['win32-service'] = ['0.8.8', require: false] end -if puppetversion = ENV['PUPPET_GEM_VERSION'] - gem 'puppet', puppetversion, :require => false -else - gem 'puppet', :require => false +gems.each do |gem_name, gem_params| + gem gem_name, *gem_params +end + +# Evaluate Gemfile.local and ~/.gemfile if they exist +extra_gemfiles = [ + "#{__FILE__}.local", + File.join(Dir.home, '.gemfile'), +] + +extra_gemfiles.each do |gemfile| + if File.file?(gemfile) && File.readable?(gemfile) + eval(File.read(gemfile), binding) + end end +# vim: syntax=ruby diff --git a/README.md b/README.md index 789b4c9..f9c3259 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,11 @@ to use something like ## Usage +The value of the module is in the custom functions that convert the input hash to the +specified output format. Defined types have been added to implement each function so +they can be used from hiera without writing more puppet manifests. See the reference +for details on the defined types. The core functions are documented in detail here. + ### `hash2ini` Converts a hash into an diff --git a/REFERENCE.md b/REFERENCE.md new file mode 100644 index 0000000..e106426 --- /dev/null +++ b/REFERENCE.md @@ -0,0 +1,372 @@ +# Reference + + + +## Table of Contents + +### Classes + +* [`hash2stuff`](#hash2stuff): Provide an entry point for module defined types. The class does nothing without hiera data + +### Defined types + +* [`hash2stuff::hash2ini`](#hash2stuffhash2ini): Defined type provides an implementation of the hash2ini function, creating an INI file from the input hash +* [`hash2stuff::hash2json`](#hash2stuffhash2json): Defined type provides an implementation of the hash2json function, creating a JSON file from the input hash +* [`hash2stuff::hash2kv`](#hash2stuffhash2kv): Defined type provides an implementation of the hash2kv function, creating a key-value/shellvar file from the input hash +* [`hash2stuff::hash2properties`](#hash2stuffhash2properties): Defined type provides an implementation of the hash2properties function, creating a Java properties file from the input hash +* [`hash2stuff::hash2yaml`](#hash2stuffhash2yaml): Defined type provides an implementation of the hash2yaml function, creating a YAML file from the input hash + +### Functions + +* [`hash2ini`](#hash2ini): This converts a puppet hash to an INI string. +* [`hash2json`](#hash2json): This converts a puppet hash to JSON string. +* [`hash2kv`](#hash2kv): This converts a puppet hash to an key-value string. +* [`hash2properties`](#hash2properties): This converts a puppet hash to an properties string. +* [`hash2yaml`](#hash2yaml): This converts a puppet hash to YAML string. + +## Classes + +### `hash2stuff` + +Provide an entry point for module defined types. The class does nothing without hiera data + +#### Parameters + +The following parameters are available in the `hash2stuff` class. + +##### `hash2ini` + +Data type: `Hash` + + + +Default value: `{}` + +##### `hash2json` + +Data type: `Hash` + + + +Default value: `{}` + +##### `hash2kv` + +Data type: `Hash` + + + +Default value: `{}` + +##### `hash2properties` + +Data type: `Hash` + + + +Default value: `{}` + +##### `hash2yaml` + +Data type: `Hash` + + + +Default value: `{}` + +## Defined types + +### `hash2stuff::hash2ini` + +Defined type provides an implementation of the hash2ini function, creating an INI file from the input hash + +#### Examples + +##### + +```puppet +hash2stuff::hash2ini { 'namevar': + file_props => { + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + } + data_hash => { + section1 => { + key1 => 'value1', + } + } +} +``` + +#### Parameters + +The following parameters are available in the `hash2stuff::hash2ini` defined type. + +##### `file_props` + +Data type: `Hash` + +Properties of the target file resource. Accepts and requires the same parameters of a puppet "file" + +##### `data_hash` + +Data type: `Hash` + +Hash representation of the INI file, to include section names and key/value pairs + +##### `options` + +Data type: `Hash` + +Hash of optional values to pass to the "hash2ini" function. See the function for details. + +Default value: `{}` + +### `hash2stuff::hash2json` + +Defined type provides an implementation of the hash2json function, creating a JSON file from the input hash + +#### Examples + +##### + +```puppet +hash2stuff::hash2json { 'namevar': + file_props => { + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + } + data_hash => { + section1 => { + key1 => 'value1', + } + } +} +``` + +#### Parameters + +The following parameters are available in the `hash2stuff::hash2json` defined type. + +##### `file_props` + +Data type: `Hash` + +Properties of the target file resource. Accepts and requires the same parameters of a puppet "file" + +##### `data_hash` + +Data type: `Hash` + +Hash representation of the JSON file. + +### `hash2stuff::hash2kv` + +Defined type provides an implementation of the hash2kv function, creating a key-value/shellvar file from the input hash + +#### Examples + +##### + +```puppet +hash2stuff::hash2kv { 'namevar': + file_props => { + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + } + data_hash => { + section1 => { + key1 => 'value1', + } + } +} +``` + +#### Parameters + +The following parameters are available in the `hash2stuff::hash2kv` defined type. + +##### `file_props` + +Data type: `Hash` + +Properties of the target file resource. Accepts and requires the same parameters of a puppet "file" + +##### `data_hash` + +Data type: `Hash` + +Hash representation of the key-value/shellvar file. + +##### `options` + +Data type: `Hash` + +Hash of optional values to pass to the "hash2kv" function. See function for details. + +Default value: `{}` + +### `hash2stuff::hash2properties` + +Defined type provides an implementation of the hash2properties function, creating a Java properties file from the input hash + +#### Examples + +##### + +```puppet +hash2stuff::hash2properties { 'namevar': + file_props => { + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + } + data_hash => { + section1 => { + key1 => 'value1', + } + } +} +``` + +#### Parameters + +The following parameters are available in the `hash2stuff::hash2properties` defined type. + +##### `file_props` + +Data type: `Hash` + +Properties of the target file resource. Accepts and requires the same parameters of a puppet "file" + +##### `data_hash` + +Data type: `Hash` + +Hash representation of the properties file. + +##### `options` + +Data type: `Hash` + +Hash of optional values to pass to the "hash2properties" function. See function for details. + +Default value: `{}` + +### `hash2stuff::hash2yaml` + +Defined type provides an implementation of the hash2yaml function, creating a YAML file from the input hash + +#### Examples + +##### + +```puppet +hash2stuff::hash2yaml { 'namevar': + file_props => { + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + } + data_hash => { + section1 => { + key1 => 'value1', + } + } +} +``` + +#### Parameters + +The following parameters are available in the `hash2stuff::hash2yaml` defined type. + +##### `file_props` + +Data type: `Hash` + +Properties of the target file resource. Accepts and requires the same parameters of a puppet "file" + +##### `data_hash` + +Data type: `Hash` + +Hash representation of the YAML file. + +##### `options` + +Data type: `Hash` + +Hash of optional values to pass to the "hash2yaml" function. See function for details. + +Default value: `{}` + +## Functions + +### `hash2ini` + +Type: Ruby 3.x API + +This converts a puppet hash to an INI string. + +#### `hash2ini()` + +This converts a puppet hash to an INI string. + +Returns: `Any` + +### `hash2json` + +Type: Ruby 3.x API + +This converts a puppet hash to JSON string. + +#### `hash2json()` + +This converts a puppet hash to JSON string. + +Returns: `Any` + +### `hash2kv` + +Type: Ruby 3.x API + +This converts a puppet hash to an key-value string. + +#### `hash2kv()` + +This converts a puppet hash to an key-value string. + +Returns: `Any` + +### `hash2properties` + +Type: Ruby 3.x API + +This converts a puppet hash to an properties string. + +#### `hash2properties()` + +This converts a puppet hash to an properties string. + +Returns: `Any` + +### `hash2yaml` + +Type: Ruby 3.x API + +This converts a puppet hash to YAML string. + +#### `hash2yaml()` + +This converts a puppet hash to YAML string. + +Returns: `Any` + diff --git a/Rakefile b/Rakefile index 92aa778..0a5093b 100644 --- a/Rakefile +++ b/Rakefile @@ -1,30 +1,87 @@ -require 'puppetlabs_spec_helper/rake_tasks' -require 'puppet-lint/tasks/puppet-lint' +# frozen_string_literal: true -PuppetLint.configuration.send('disable_80chars') -PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"] +require 'puppet_litmus/rake_tasks' if Bundler.rubygems.find_name('puppet_litmus').any? +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-syntax/tasks/puppet-syntax' +require 'puppet_blacksmith/rake_tasks' if Bundler.rubygems.find_name('puppet-blacksmith').any? +require 'github_changelog_generator/task' if Bundler.rubygems.find_name('github_changelog_generator').any? +require 'puppet-strings/tasks' if Bundler.rubygems.find_name('puppet-strings').any? -# These gems aren't always present, for instance -# on Travis with --without development -begin - require 'puppet_blacksmith/rake_tasks' -rescue LoadError # rubocop:disable Lint/HandleExceptions +def changelog_user + return unless Rake.application.top_level_tasks.include? "changelog" + returnVal = nil || JSON.load(File.read('metadata.json'))['author'] + raise "unable to find the changelog_user in .sync.yml, or the author in metadata.json" if returnVal.nil? + puts "GitHubChangelogGenerator user:#{returnVal}" + returnVal end -desc "Validate manifests, templates, and ruby files" -task :validate do - Dir['manifests/**/*.pp'].each do |manifest| - sh "puppet parser validate --noop #{manifest}" +def changelog_project + return unless Rake.application.top_level_tasks.include? "changelog" + + returnVal = nil + returnVal ||= begin + metadata_source = JSON.load(File.read('metadata.json'))['source'] + metadata_source_match = metadata_source && metadata_source.match(%r{.*\/([^\/]*?)(?:\.git)?\Z}) + + metadata_source_match && metadata_source_match[1] end - Dir['spec/**/*.rb','lib/**/*.rb'].each do |ruby_file| - sh "ruby -c #{ruby_file}" unless ruby_file =~ /spec\/fixtures/ + + raise "unable to find the changelog_project in .sync.yml or calculate it from the source in metadata.json" if returnVal.nil? + + puts "GitHubChangelogGenerator project:#{returnVal}" + returnVal +end + +def changelog_future_release + return unless Rake.application.top_level_tasks.include? "changelog" + returnVal = "v%s" % JSON.load(File.read('metadata.json'))['version'] + raise "unable to find the future_release (version) in metadata.json" if returnVal.nil? + puts "GitHubChangelogGenerator future_release:#{returnVal}" + returnVal +end + +PuppetLint.configuration.send('disable_relative') + +if Bundler.rubygems.find_name('github_changelog_generator').any? + GitHubChangelogGenerator::RakeTask.new :changelog do |config| + raise "Set CHANGELOG_GITHUB_TOKEN environment variable eg 'export CHANGELOG_GITHUB_TOKEN=valid_token_here'" if Rake.application.top_level_tasks.include? "changelog" and ENV['CHANGELOG_GITHUB_TOKEN'].nil? + config.user = "#{changelog_user}" + config.project = "#{changelog_project}" + config.future_release = "#{changelog_future_release}" + config.exclude_labels = ['maintenance'] + config.header = "# Change log\n\nAll notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org)." + config.add_pr_wo_labels = true + config.issues = false + config.merge_prefix = "### UNCATEGORIZED PRS; LABEL THEM ON GITHUB" + config.configure_sections = { + "Changed" => { + "prefix" => "### Changed", + "labels" => ["backwards-incompatible"], + }, + "Added" => { + "prefix" => "### Added", + "labels" => ["enhancement", "feature"], + }, + "Fixed" => { + "prefix" => "### Fixed", + "labels" => ["bug", "documentation", "bugfix"], + }, + } end - Dir['templates/**/*.erb'].each do |template| - sh "erb -P -x -T '-' #{template} | ruby -c" +else + desc 'Generate a Changelog from GitHub' + task :changelog do + raise < 1.15' + condition: "Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.3.0')" +EOM end end -desc "Run acceptance tests" -RSpec::Core::RakeTask.new(:acceptance) do |t| - t.pattern = 'spec/acceptance' -end diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..ec38949 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,56 @@ +--- +version: 1.1.x.{build} +branches: + only: + - master + - release +skip_commits: + message: /^\(?doc\)?.*/ +clone_depth: 10 +init: + - SET + - 'mkdir C:\ProgramData\PuppetLabs\code && exit 0' + - 'mkdir C:\ProgramData\PuppetLabs\facter && exit 0' + - 'mkdir C:\ProgramData\PuppetLabs\hiera && exit 0' + - 'mkdir C:\ProgramData\PuppetLabs\puppet\var && exit 0' +environment: + matrix: + - + RUBY_VERSION: 24-x64 + CHECK: syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop + - + PUPPET_GEM_VERSION: ~> 5.0 + RUBY_VERSION: 24 + CHECK: parallel_spec + - + PUPPET_GEM_VERSION: ~> 5.0 + RUBY_VERSION: 24-x64 + CHECK: parallel_spec + - + PUPPET_GEM_VERSION: ~> 6.0 + RUBY_VERSION: 25 + CHECK: parallel_spec + - + PUPPET_GEM_VERSION: ~> 6.0 + RUBY_VERSION: 25-x64 + CHECK: parallel_spec +matrix: + fast_finish: true +install: + - set PATH=C:\Ruby%RUBY_VERSION%\bin;%PATH% + - bundle install --jobs 4 --retry 2 --without system_tests + - type Gemfile.lock +build: off +test_script: + - bundle exec puppet -V + - ruby -v + - gem -v + - bundle -v + - bundle exec rake %CHECK% +notifications: + - provider: Email + to: + - nobody@nowhere.com + on_build_success: false + on_build_failure: false + on_build_status_changed: false diff --git a/data/common.yaml b/data/common.yaml new file mode 100644 index 0000000..2fbf0ff --- /dev/null +++ b/data/common.yaml @@ -0,0 +1 @@ +--- {} diff --git a/hiera.yaml b/hiera.yaml new file mode 100644 index 0000000..545fff3 --- /dev/null +++ b/hiera.yaml @@ -0,0 +1,21 @@ +--- +version: 5 + +defaults: # Used for any hierarchy level that omits these keys. + datadir: data # This path is relative to hiera.yaml's directory. + data_hash: yaml_data # Use the built-in YAML backend. + +hierarchy: + - name: "osfamily/major release" + paths: + # Used to distinguish between Debian and Ubuntu + - "os/%{facts.os.name}/%{facts.os.release.major}.yaml" + - "os/%{facts.os.family}/%{facts.os.release.major}.yaml" + # Used for Solaris + - "os/%{facts.os.family}/%{facts.kernelrelease}.yaml" + - name: "osfamily" + paths: + - "os/%{facts.os.name}.yaml" + - "os/%{facts.os.family}.yaml" + - name: 'common' + path: 'common.yaml' diff --git a/lib/puppet/functions/hash2ini.rb b/lib/puppet/functions/hash2ini.rb new file mode 100644 index 0000000..80b3a73 --- /dev/null +++ b/lib/puppet/functions/hash2ini.rb @@ -0,0 +1,42 @@ +# @summary Converts a puppet hash to INI file string. +Puppet::Functions.create_function(:hash2ini) do + # @param input The hash to be converted to INI file + # @param options A hash of options to control INI file format + # @return [String] An INI file formatted string + # @example Call the function with the $input and $options hashes + # hash2ini($input, $options) + dispatch :ini do + param 'Hash', :input + optional_param 'Hash', :options + end + + def ini(input, options = {}) + settings = { + 'header' => '# THIS FILE IS CONTROLLED BY PUPPET', + 'section_prefix' => '[', + 'section_suffix' => ']', + 'key_val_separator' => '=', + 'quote_char' => '"', + 'quote_booleans' => true, + 'quote_numerics' => true, + } + + settings.merge!(options) + + output = [] + output << settings['header'] << nil + input.keys.each do |section| + output << "#{settings['section_prefix']}#{section}#{settings['section_suffix']}" + input[section].each do |k, v| + v_is_a_boolean = (v.is_a?(TrueClass) || v.is_a?(FalseClass)) + output << if (v_is_a_boolean && !settings['quote_booleans']) || (v.is_a?(Numeric) && !settings['quote_numerics']) + "#{k}#{settings['key_val_separator']}#{v}" + else + "#{k}#{settings['key_val_separator']}#{settings['quote_char']}#{v}#{settings['quote_char']}" + end + end + output << nil + end + output.join("\n") + end +end diff --git a/lib/puppet/functions/hash2json.rb b/lib/puppet/functions/hash2json.rb new file mode 100644 index 0000000..00ac7a7 --- /dev/null +++ b/lib/puppet/functions/hash2json.rb @@ -0,0 +1,16 @@ +# @summary Converts a puppet hash to JSON string. +Puppet::Functions.create_function(:hash2json) do + # @param input The hash to be converted to JSON + # @return [String] A JSON formatted string + # @example Call the function with the $input hash + # hash2json($input) + dispatch :json do + param 'Hash', :input + end + + require 'json' + + def json(input) + JSON.pretty_generate(input) << "\n" + end +end diff --git a/lib/puppet/functions/hash2kv.rb b/lib/puppet/functions/hash2kv.rb new file mode 100644 index 0000000..b0b548f --- /dev/null +++ b/lib/puppet/functions/hash2kv.rb @@ -0,0 +1,30 @@ +# @summary Converts a puppet hash to key/value (SHELLVAR) file string. +Puppet::Functions.create_function(:hash2kv) do + # @param input The hash to be converted to K/V file + # @param options A hash of options to control K/V file format + # @return [String] A K/V file formatted string + # @example Call the function with the $input and $options hashes + # hash2ini($input, $options) + dispatch :kv do + param 'Hash', :input + optional_param 'Hash', :options + end + + def kv(input, options = {}) + settings = { + 'header' => '# THIS FILE IS CONTROLLED BY PUPPET', + 'key_val_separator' => '=', + 'quote_char' => '"', + } + + settings.merge!(options) + + output = [] + output << settings['header'] << nil + input.each do |k, v| + output << "#{k}#{settings['key_val_separator']}#{settings['quote_char']}#{v}#{settings['quote_char']}" + end + output << nil + output.join("\n") + end +end diff --git a/lib/puppet/functions/hash2properties.rb b/lib/puppet/functions/hash2properties.rb new file mode 100644 index 0000000..57f5732 --- /dev/null +++ b/lib/puppet/functions/hash2properties.rb @@ -0,0 +1,54 @@ +# @summary Converts a puppet hash to Java properties file string. +Puppet::Functions.create_function(:hash2properties) do + # @param input The hash to be converted to properties + # @param options A hash of options to control properties file format + # @return [String] A properties formatted string + # @example Call the function with the $input hash + # hash2properties($input) + dispatch :properties do + param 'Hash', :input + optional_param 'Hash', :options + end + + def properties(input, options = {}) + settings = { + 'header' => '# THIS FILE IS CONTROLLED BY PUPPET', + 'key_val_separator' => '=', + 'quote_char' => '', + 'list_separator' => ',', + } + + settings.merge!(options) + + properties_str = [] + key_hashes = input.to_a + properties = {} + list_separator = settings['list_separator'] + until key_hashes.empty? + key_value = key_hashes.pop + if key_value[1].is_a?(Hash) + key_hashes += key_value[1].to_a.map { |key, value| ["#{key_value[0]}.#{key}", value] } + else + prop_value = if key_value[1].is_a?(Array) + key_value[1].join(list_separator) + else + prop_value = key_value[1] + end + properties[key_value[0]] = prop_value + end + end + + key_val_separator = settings['key_val_separator'] + quote_char = settings['quote_char'] + + properties.each do |property, value| + properties_str << "#{property}#{key_val_separator}#{quote_char}#{value}#{quote_char}" + end + + properties_str.sort! { |x, y| String(x) <=> String(y) } + properties_str.insert(0, settings['header'], '') + properties_str << '' + + properties_str.join("\n") + end +end diff --git a/lib/puppet/functions/hash2yaml.rb b/lib/puppet/functions/hash2yaml.rb new file mode 100644 index 0000000..e7766ec --- /dev/null +++ b/lib/puppet/functions/hash2yaml.rb @@ -0,0 +1,29 @@ +# @summary Converts a puppet hash to YAML string. +Puppet::Functions.create_function(:hash2yaml) do + # @param input The hash to be converted to YAML + # @param options A hash of options to control YAML file format + # @return [String] A YAML formatted string + # @example Call the function with the $input hash + # hash2yaml($input) + dispatch :yaml do + param 'Hash', :input + optional_param 'Hash', :options + end + + require 'yaml' + + def yaml(input, options = {}) + settings = { + 'header' => '', + } + + settings.merge!(options) + + output = if settings['header'].to_s.empty? + input.to_yaml + else + "#{settings['header']}\n#{input.to_yaml}" + end + output + end +end diff --git a/lib/puppet/parser/functions/hash2ini.rb b/lib/puppet/parser/functions/hash2ini.rb deleted file mode 100644 index c7ee0fc..0000000 --- a/lib/puppet/parser/functions/hash2ini.rb +++ /dev/null @@ -1,55 +0,0 @@ -module Puppet::Parser::Functions - newfunction(:hash2ini, :type => :rvalue, :doc => <<-EOS -This converts a puppet hash to an INI string. - EOS - ) do |arguments| - - if arguments.size < 1 - raise(Puppet::ParseError, 'hash2ini(): requires at least one argument') - end - if arguments.size >= 3 - raise(Puppet::ParseError, 'hash2ini(): too many arguments') - end - unless arguments[0].is_a?(Hash) - raise(Puppet::ParseError, 'hash2ini(): requires a hash as argument') - end - - h = arguments[0] - - settings = { - 'header' => '# THIS FILE IS CONTROLLED BY PUPPET', - 'section_prefix' => '[', - 'section_suffix' => ']', - 'key_val_separator' => '=', - 'quote_char' => '"', - "quote_booleans" => true, - "quote_numerics" => true, - } - - if arguments[1] - unless arguments[1].is_a?(Hash) - raise(Puppet::ParseError, 'hash2ini(): Requires a hash as argument') - end - settings.merge!(arguments[1]) - end - - - - ini = [] - ini << settings['header'] << nil - h.keys.each do |section| - ini << "#{settings['section_prefix']}#{section}#{settings['section_suffix']}" - h[section].each do |k, v| - v_is_a_boolean = (v.is_a?(TrueClass) or v.is_a?(FalseClass)) - - if (v_is_a_boolean and not settings['quote_booleans']) or (v.is_a?(Numeric) and not settings['quote_numerics']) - ini << "#{k}#{settings['key_val_separator']}#{v}" - else - ini << "#{k}#{settings['key_val_separator']}#{settings['quote_char']}#{v}#{settings['quote_char']}" - end - end - ini << nil - end - return ini.join("\n") - end -end diff --git a/lib/puppet/parser/functions/hash2json.rb b/lib/puppet/parser/functions/hash2json.rb deleted file mode 100644 index 3d89dfa..0000000 --- a/lib/puppet/parser/functions/hash2json.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Puppet::Parser::Functions - newfunction(:hash2json, :type => :rvalue, :doc => <<-EOS -This converts a puppet hash to JSON string. - EOS - ) do |arguments| - require 'json' - - if arguments.size != 1 - raise(Puppet::ParseError, 'hash2json(): requires one and only one argument') - end - unless arguments[0].is_a?(Hash) - raise(Puppet::ParseError, 'hash2json(): requires a hash as argument') - end - - h = arguments[0] - - return JSON.pretty_generate(h) << "\n" - end -end diff --git a/lib/puppet/parser/functions/hash2kv.rb b/lib/puppet/parser/functions/hash2kv.rb deleted file mode 100644 index 1e0450a..0000000 --- a/lib/puppet/parser/functions/hash2kv.rb +++ /dev/null @@ -1,42 +0,0 @@ -module Puppet::Parser::Functions - newfunction(:hash2kv, :type => :rvalue, :doc => <<-EOS -This converts a puppet hash to an key-value string. - EOS - ) do |arguments| - - if arguments.size < 1 - raise(Puppet::ParseError, 'hash2kv(): requires at least one argument') - end - if arguments.size >= 3 - raise(Puppet::ParseError, 'hash2kv(): too many arguments') - end - unless arguments[0].is_a?(Hash) - raise(Puppet::ParseError, 'hash2kv(): requires a hash as argument') - end - - h = arguments[0] - - settings = { - 'header' => '# THIS FILE IS CONTROLLED BY PUPPET', - 'key_val_separator' => '=', - 'quote_char' => '"', - } - - if arguments[1] - unless arguments[1].is_a?(Hash) - raise(Puppet::ParseError, 'hash2kv(): Requires a hash as argument') - end - settings.merge!(arguments[1]) - end - - - - kv = [] - kv << settings['header'] << nil - h.each do |k,v| - kv << "#{k}#{settings['key_val_separator']}#{settings['quote_char']}#{v}#{settings['quote_char']}" - end - kv << nil - return kv.join("\n") - end -end diff --git a/lib/puppet/parser/functions/hash2properties.rb b/lib/puppet/parser/functions/hash2properties.rb deleted file mode 100644 index c61b48d..0000000 --- a/lib/puppet/parser/functions/hash2properties.rb +++ /dev/null @@ -1,69 +0,0 @@ -module Puppet::Parser::Functions - newfunction(:hash2properties, :type => :rvalue, :doc => <<-EOS -This converts a puppet hash to an properties string. - EOS - ) do |arguments| - - if arguments.size < 1 - raise(Puppet::ParseError, 'hash2properties(): requires at least one argument') - end - if arguments.size >= 3 - raise(Puppet::ParseError, 'hash2properties(): too many arguments') - end - unless arguments[0].is_a?(Hash) - arg_class=arguments[0].class - raise(Puppet::ParseError, "hash2properties(): requires a hash as argument (received #{arg_class})") - end - - from_hash = arguments[0] - - settings = { - 'header' => '# THIS FILE IS CONTROLLED BY PUPPET', - 'key_val_separator' => '=', - 'quote_char' => '', - 'list_separator' => ',', - } - - if arguments[1] - unless arguments[1].is_a?(Hash) - arg_class=arguments[1].class - raise(Puppet::ParseError, "hash2properties(): Requires a hash as argument (received #{arg_class})") - end - settings.merge!(arguments[1]) - end - - properties_str=[] - - key_hashes = from_hash.to_a - # puts "Key hashes: ", String(key_hashes) - properties = {} - list_separator=settings['list_separator'] - while key_hashes.size > 0 - key_value = key_hashes.pop - if key_value[1].is_a?(Hash) - key_hashes += key_value[1].to_a.map { |key,value| [ "#{key_value[0]}.#{key}", value ] } - else - if key_value[1].is_a?(Array) - prop_value=key_value[1].join(list_separator) - else - prop_value=key_value[1] - end - properties[key_value[0]] = prop_value - end - end - - - key_val_separator=settings['key_val_separator'] - quote_char=settings['quote_char'] - - properties.each do | property, value | - properties_str << "#{property}#{key_val_separator}#{quote_char}#{value}#{quote_char}" - end - - properties_str.sort!{ |x,y| String(x) <=> String(y) } - properties_str.insert(0, settings['header'], '') - properties_str << '' - - return properties_str.join("\n") - end -end diff --git a/lib/puppet/parser/functions/hash2yaml.rb b/lib/puppet/parser/functions/hash2yaml.rb deleted file mode 100644 index 4a328f5..0000000 --- a/lib/puppet/parser/functions/hash2yaml.rb +++ /dev/null @@ -1,49 +0,0 @@ -module Puppet::Parser::Functions - newfunction(:hash2yaml, :type => :rvalue, :doc => <<-EOS -This converts a puppet hash to YAML string. - EOS - ) do |arguments| - require 'yaml' - - if arguments.size < 1 - raise(Puppet::ParseError, 'hash2yaml(): requires at least one argument') - end - if arguments.size >= 3 - raise(Puppet::ParseError, 'hash2yaml(): too many arguments') - end - unless arguments[0].is_a?(Hash) - raise(Puppet::ParseError, 'hash2yaml(): requires a hash as argument') - end - - h = arguments[0] - - settings = { - 'header' => '', - } - - if arguments[1] - unless arguments[1].is_a?(Hash) - raise(Puppet::ParseError, 'hash2yaml(): Requires a hash as second argument') - end - settings.merge!(arguments[1]) - end - - # https://github.com/hallettj/zaml/issues/3 - # https://tickets.puppetlabs.com/browse/PUP-3120 - # https://tickets.puppetlabs.com/browse/PUP-5630 - # - # puppet 3.x uses ZAML which formats YAML output differently than puppet 4.x - # including not ending the file with a new line - if Puppet.version.to_f < 4.0 - output = h.to_yaml << "\n" - else - output = h.to_yaml - end - - if settings['header'].to_s.empty? - return output - else - return "#{settings['header']}\n#{output}" - end - end -end diff --git a/manifests/hash2ini.pp b/manifests/hash2ini.pp new file mode 100644 index 0000000..14715b4 --- /dev/null +++ b/manifests/hash2ini.pp @@ -0,0 +1,36 @@ +# @summary +# Defined type provides an implementation of the hash2ini function, creating an INI file from the input hash +# +# @param file_props +# Properties of the target file resource. Accepts and requires the same parameters of a puppet "file" +# +# @param data_hash +# Hash representation of the INI file, to include section names and key/value pairs +# +# @param options +# Hash of optional values to pass to the "hash2ini" function. See the function for details. +# +# @example +# hash2stuff::hash2ini { 'namevar': +# file_props => { +# ensure => file, +# owner => 'root', +# group => 'root', +# mode => '0644', +# } +# data_hash => { +# section1 => { +# key1 => 'value1', +# } +# } +# } +# +define hash2stuff::hash2ini ( + Hash $file_props, + Hash $data_hash, + Hash $options = {}, +) { + File {$name: + * => merge($file_props, content => hash2ini($data_hash, $options)), + } +} diff --git a/manifests/hash2json.pp b/manifests/hash2json.pp new file mode 100644 index 0000000..379b616 --- /dev/null +++ b/manifests/hash2json.pp @@ -0,0 +1,32 @@ +# @summary +# Defined type provides an implementation of the hash2json function, creating a JSON file from the input hash +# +# @param file_props +# Properties of the target file resource. Accepts and requires the same parameters of a puppet "file" +# +# @param data_hash +# Hash representation of the JSON file. +# +# @example +# hash2stuff::hash2json { 'namevar': +# file_props => { +# ensure => file, +# owner => 'root', +# group => 'root', +# mode => '0644', +# } +# data_hash => { +# section1 => { +# key1 => 'value1', +# } +# } +# } +# +define hash2stuff::hash2json ( + Hash $file_props, + Hash $data_hash, +) { + File {$name: + * => merge($file_props, content => hash2json($data_hash)), + } +} diff --git a/manifests/hash2kv.pp b/manifests/hash2kv.pp new file mode 100644 index 0000000..27d166b --- /dev/null +++ b/manifests/hash2kv.pp @@ -0,0 +1,36 @@ +# @summary +# Defined type provides an implementation of the hash2kv function, creating a key-value/shellvar file from the input hash +# +# @param file_props +# Properties of the target file resource. Accepts and requires the same parameters of a puppet "file" +# +# @param data_hash +# Hash representation of the key-value/shellvar file. +# +# @param options +# Hash of optional values to pass to the "hash2kv" function. See function for details. +# +# @example +# hash2stuff::hash2kv { 'namevar': +# file_props => { +# ensure => file, +# owner => 'root', +# group => 'root', +# mode => '0644', +# } +# data_hash => { +# section1 => { +# key1 => 'value1', +# } +# } +# } +# +define hash2stuff::hash2kv ( + Hash $file_props, + Hash $data_hash, + Hash $options = {}, +) { + File {$name: + * => merge($file_props, content => hash2kv($data_hash, $options)), + } +} diff --git a/manifests/hash2properties.pp b/manifests/hash2properties.pp new file mode 100644 index 0000000..76f69ed --- /dev/null +++ b/manifests/hash2properties.pp @@ -0,0 +1,36 @@ +# @summary +# Defined type provides an implementation of the hash2properties function, creating a Java properties file from the input hash +# +# @param file_props +# Properties of the target file resource. Accepts and requires the same parameters of a puppet "file" +# +# @param data_hash +# Hash representation of the properties file. +# +# @param options +# Hash of optional values to pass to the "hash2properties" function. See function for details. +# +# @example +# hash2stuff::hash2properties { 'namevar': +# file_props => { +# ensure => file, +# owner => 'root', +# group => 'root', +# mode => '0644', +# } +# data_hash => { +# section1 => { +# key1 => 'value1', +# } +# } +# } +# +define hash2stuff::hash2properties ( + Hash $file_props, + Hash $data_hash, + Hash $options = {}, +) { + File {$name: + * => merge($file_props, content => hash2properties($data_hash, $options)), + } +} diff --git a/manifests/hash2yaml.pp b/manifests/hash2yaml.pp new file mode 100644 index 0000000..394634f --- /dev/null +++ b/manifests/hash2yaml.pp @@ -0,0 +1,36 @@ +# @summary +# Defined type provides an implementation of the hash2yaml function, creating a YAML file from the input hash +# +# @param file_props +# Properties of the target file resource. Accepts and requires the same parameters of a puppet "file" +# +# @param data_hash +# Hash representation of the YAML file. +# +# @param options +# Hash of optional values to pass to the "hash2yaml" function. See function for details. +# +# @example +# hash2stuff::hash2yaml { 'namevar': +# file_props => { +# ensure => file, +# owner => 'root', +# group => 'root', +# mode => '0644', +# } +# data_hash => { +# section1 => { +# key1 => 'value1', +# } +# } +# } +# +define hash2stuff::hash2yaml ( + Hash $file_props, + Hash $data_hash, + Hash $options = {}, +) { + File {$name: + * => merge($file_props, content => hash2yaml($data_hash, $options)), + } +} diff --git a/manifests/init.pp b/manifests/init.pp new file mode 100644 index 0000000..fe84e71 --- /dev/null +++ b/manifests/init.pp @@ -0,0 +1,16 @@ +# @summary Provide an entry point for module defined types. The class does nothing without hiera data +# +class hash2stuff ( + Hash $hash2ini = {}, + Hash $hash2json = {}, + Hash $hash2kv = {}, + Hash $hash2properties = {}, + Hash $hash2yaml = {}, +) { + # Create resources from parameter hashes using the defined types + $hash2ini.each |$name, $hash| { Resource['Hash2stuff::Hash2ini'] { $name: * => $hash, } } + $hash2json.each |$name, $hash| { Resource['Hash2stuff::Hash2json'] { $name: * => $hash, } } + $hash2kv.each |$name, $hash| { Resource['Hash2stuff::Hash2kv'] { $name: * => $hash, } } + $hash2properties.each |$name, $hash| { Resource['Hash2stuff::Hash2properties'] { $name: * => $hash, } } + $hash2yaml.each |$name, $hash| { Resource['Hash2stuff::Hash2yaml'] { $name: * => $hash, } } +} diff --git a/metadata.json b/metadata.json index 1209217..67c2758 100644 --- a/metadata.json +++ b/metadata.json @@ -1,62 +1,70 @@ { "name": "mmckinst-hash2stuff", - "version": "1.2.1", + "version": "1.3.0", "author": "mmckinst", "summary": "Convert a puppet hash to YAML, JSON, INI file, or key-value.", "license": "Apache-2.0", "source": "https://github.com/mmckinst/puppet-hash2stuff", "project_page": "https://github.com/mmckinst/puppet-hash2stuff", "issues_url": "https://github.com/mmckinst/puppet-hash2stuff/issues", - "tags": [ - "hash", - "json", - "yaml", - "shellvar", - "ini", - "inifile", - "kv", - "key-value" + "dependencies": [ + { + "name": "puppetlabs/stdlib", + "version_requirement": ">= 4.1.0 <= 7.0.0" + } ], "operatingsystem_support": [ { - "operatingsystem": "RedHat", - "operatingsystemrelease": [ - "5", - "6", - "7", - "8" - ] - }, - { - "operatingsystem": "CentOS", - "operatingsystemrelease": [ - "5", - "6", - "7", - "8" - ] - }, - { - "operatingsystem": "Debian", - "operatingsystemrelease": [ - "8", - "9" - ] - }, - { - "operatingsystem": "Ubuntu", - "operatingsystemrelease": [ - "14.04", - "16.04", - "18.04" - ] + "operatingsystem": "CentOS" + }, + { + "operatingsystem": "OracleLinux" + }, + { + "operatingsystem": "RedHat" + }, + { + "operatingsystem": "Scientific" + }, + { + "operatingsystem": "Debian" + }, + { + "operatingsystem": "Ubuntu" + }, + { + "operatingsystem": "windows" + }, + { + "operatingsystem": "Solaris" + }, + { + "operatingsystem": "SLES" + }, + { + "operatingsystem": "Darwin" + }, + { + "operatingsystem": "Fedora" } ], "requirements": [ { "name": "puppet", - "version_requirement": ">= 3.5.0 < 7.0.0" + "version_requirement": ">= 3.5.0 < 8.0.0" } ], - "dependencies": [] + "tags": [ + "hash", + "json", + "yaml", + "shellvar", + "ini", + "inifile", + "kv", + "key-value" + ], + "pdk-version": "1.18.1", + "template-url": "pdk-default#1.18.1", + "template-ref": "tags/1.18.1-0-g3d2e75c" } diff --git a/spec/classes/coverage_spec.rb b/spec/classes/coverage_spec.rb deleted file mode 100644 index 12513b8..0000000 --- a/spec/classes/coverage_spec.rb +++ /dev/null @@ -1 +0,0 @@ -at_exit { RSpec::Puppet::Coverage.report! } diff --git a/spec/classes/hashfile_spec.rb b/spec/classes/hashfile_spec.rb new file mode 100644 index 0000000..6fab5ba --- /dev/null +++ b/spec/classes/hashfile_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'hashfile' do + on_supported_os.each do |os, os_facts| + context "on #{os}" do + let(:facts) { os_facts } + + it { is_expected.to compile } + end + end +end diff --git a/spec/default_facts.yml b/spec/default_facts.yml new file mode 100644 index 0000000..f777abf --- /dev/null +++ b/spec/default_facts.yml @@ -0,0 +1,8 @@ +# Use default_module_facts.yml for module specific facts. +# +# Facts specified here will override the values provided by rspec-puppet-facts. +--- +ipaddress: "172.16.254.254" +ipaddress6: "FE80:0000:0000:0000:AAAA:AAAA:AAAA" +is_pe: false +macaddress: "AA:AA:AA:AA:AA:AA" diff --git a/spec/defines/hash2ini_spec.rb b/spec/defines/hash2ini_spec.rb new file mode 100644 index 0000000..2e107b1 --- /dev/null +++ b/spec/defines/hash2ini_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'hash2stuff::hash2ini' do + let(:params) do + { + file_props: { + ensure: 'file', + }, + data_hash: { + section1: { + key1: 'value1', + }, + }, + } + end + + on_supported_os.each do |os, os_facts| + context "on #{os}" do + let(:facts) { os_facts } + + if os =~ %r{windows}i + let(:title) { 'C:\\Temp\\spec_ini.tmp' } + else + let(:title) { '/tmp/spec_ini.tmp' } + end + it { is_expected.to compile } + end + end +end diff --git a/spec/defines/hash2json_spec.rb b/spec/defines/hash2json_spec.rb new file mode 100644 index 0000000..b631083 --- /dev/null +++ b/spec/defines/hash2json_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'hash2stuff::hash2json' do + let(:params) do + { + file_props: { + ensure: 'file', + }, + data_hash: { + section1: { + key1: 'value1', + }, + }, + } + end + + on_supported_os.each do |os, os_facts| + context "on #{os}" do + let(:facts) { os_facts } + + if os =~ %r{windows}i + let(:title) { 'C:\\Temp\\spec_ini.tmp' } + else + let(:title) { '/tmp/spec_ini.tmp' } + end + it { is_expected.to compile } + end + end +end diff --git a/spec/defines/hash2kv_spec.rb b/spec/defines/hash2kv_spec.rb new file mode 100644 index 0000000..f10921a --- /dev/null +++ b/spec/defines/hash2kv_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'hash2stuff::hash2kv' do + let(:params) do + { + file_props: { + ensure: 'file', + }, + data_hash: { + key1: 'value1', + }, + } + end + + on_supported_os.each do |os, os_facts| + context "on #{os}" do + let(:facts) { os_facts } + + if os =~ %r{windows}i + let(:title) { 'C:\\Temp\\spec_ini.tmp' } + else + let(:title) { '/tmp/spec_ini.tmp' } + end + it { is_expected.to compile } + end + end +end diff --git a/spec/defines/hash2properties_spec.rb b/spec/defines/hash2properties_spec.rb new file mode 100644 index 0000000..8cda442 --- /dev/null +++ b/spec/defines/hash2properties_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'hash2stuff::hash2properties' do + let(:params) do + { + file_props: { + ensure: 'file', + }, + data_hash: { + section1: { + key1: 'value1', + }, + }, + } + end + + on_supported_os.each do |os, os_facts| + context "on #{os}" do + let(:facts) { os_facts } + + if os =~ %r{windows}i + let(:title) { 'C:\\Temp\\spec_ini.tmp' } + else + let(:title) { '/tmp/spec_ini.tmp' } + end + it { is_expected.to compile } + end + end +end diff --git a/spec/defines/hash2yaml_spec.rb b/spec/defines/hash2yaml_spec.rb new file mode 100644 index 0000000..8935e19 --- /dev/null +++ b/spec/defines/hash2yaml_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'hash2stuff::hash2yaml' do + let(:params) do + { + file_props: { + ensure: 'file', + }, + data_hash: { + section1: { + key1: 'value1', + }, + }, + } + end + + on_supported_os.each do |os, os_facts| + context "on #{os}" do + let(:facts) { os_facts } + + if os =~ %r{windows}i + let(:title) { 'C:\\Temp\\spec_ini.tmp' } + else + let(:title) { '/tmp/spec_ini.tmp' } + end + it { is_expected.to compile } + end + end +end diff --git a/spec/fixtures/hiera.yaml b/spec/fixtures/hiera.yaml new file mode 100644 index 0000000..d1102a3 --- /dev/null +++ b/spec/fixtures/hiera.yaml @@ -0,0 +1,11 @@ +--- +version: 5 + +defaults: + datadir: data + data_hash: yaml_data + +hierarchy: + - name: 'Test data' + paths: + - 'common.yaml' diff --git a/spec/functions/hash2ini_spec.rb b/spec/functions/hash2ini_spec.rb index d1c2b33..75114f1 100644 --- a/spec/functions/hash2ini_spec.rb +++ b/spec/functions/hash2ini_spec.rb @@ -2,9 +2,9 @@ describe 'hash2ini' do it { is_expected.not_to eq(nil) } - it { is_expected.to run.with_params().and_raise_error(Puppet::ParseError, /requires at least one argument/) } - it { is_expected.to run.with_params({}, {}, {}).and_raise_error(Puppet::ParseError, /too many arguments/) } - it { is_expected.to run.with_params('some string').and_raise_error(Puppet::ParseError, /requires a hash as argument/) } + it { is_expected.to run.with_params.and_raise_error(ArgumentError, %r{'hash2ini' expects between 1 and 2 arguments, got none}) } + it { is_expected.to run.with_params({}, {}, {}).and_raise_error(ArgumentError, %r{'hash2ini' expects between 1 and 2 arguments, got 3}) } + it { is_expected.to run.with_params('some string').and_raise_error(ArgumentError, %r{'hash2ini' parameter 'input' expects a Hash value, got String}) } example_input = { 'main' => { @@ -15,11 +15,11 @@ 'dev' => { 'logging' => 'DEBUG', 'log_location' => '/var/log/dev.log', - } + }, } context 'default settings' do - output=<<-EOS + output = <<-EOS # THIS FILE IS CONTROLLED BY PUPPET [main] @@ -40,9 +40,9 @@ 'section_prefix' => '[[', 'section_suffix' => ']]', 'key_val_separator' => ': ', - 'quote_char' => "", + 'quote_char' => '', } - output=<<-EOS + output = <<-EOS ; THIS FILE IS CONTROLLED BY /dev/random [[main]] @@ -57,13 +57,12 @@ it { is_expected.to run.with_params(example_input, settings).and_return(output) } end - context 'default settings with custom quoting' do settings = { 'quote_booleans' => false, 'quote_numerics' => false, } - output=<<-EOS + output = <<-EOS # THIS FILE IS CONTROLLED BY PUPPET [main] diff --git a/spec/functions/hash2json_spec.rb b/spec/functions/hash2json_spec.rb index 1c1d4b0..cc232f5 100644 --- a/spec/functions/hash2json_spec.rb +++ b/spec/functions/hash2json_spec.rb @@ -2,9 +2,9 @@ describe 'hash2json' do it { is_expected.not_to eq(nil) } - it { is_expected.to run.with_params().and_raise_error(Puppet::ParseError, /requires one and only one argument/) } - it { is_expected.to run.with_params({}, {}, {}).and_raise_error(Puppet::ParseError, /requires one and only one argument/) } - it { is_expected.to run.with_params('some string').and_raise_error(Puppet::ParseError, /requires a hash as argument/) } + it { is_expected.to run.with_params.and_raise_error(ArgumentError, %r{'hash2json' expects 1 argument, got none}) } + it { is_expected.to run.with_params({}, {}).and_raise_error(ArgumentError, %r{'hash2json' expects 1 argument, got 2}) } + it { is_expected.to run.with_params('some string').and_raise_error(ArgumentError, %r{'hash2json' parameter 'input' expects a Hash value, got String}) } example_input = { 'domain' => 'example.com', @@ -13,11 +13,11 @@ 'user' => 'root', 'pass' => 'setec-astronomy', }, - 'awesome' => true, + 'awesome' => true, } context 'default setting' do - output=<<-EOS + output = <<-EOS { "domain": "example.com", "mysql": { diff --git a/spec/functions/hash2kv_spec.rb b/spec/functions/hash2kv_spec.rb index 2b52cee..0c88111 100644 --- a/spec/functions/hash2kv_spec.rb +++ b/spec/functions/hash2kv_spec.rb @@ -2,9 +2,9 @@ describe 'hash2kv' do it { is_expected.not_to eq(nil) } - it { is_expected.to run.with_params().and_raise_error(Puppet::ParseError, /requires at least one argument/) } - it { is_expected.to run.with_params({}, {}, {}).and_raise_error(Puppet::ParseError, /too many arguments/) } - it { is_expected.to run.with_params('some string').and_raise_error(Puppet::ParseError, /requires a hash as argument/) } + it { is_expected.to run.with_params.and_raise_error(ArgumentError, %r{'hash2kv' expects between 1 and 2 arguments, got none}) } + it { is_expected.to run.with_params({}, {}, {}).and_raise_error(ArgumentError, %r{'hash2kv' expects between 1 and 2 arguments, got 3}) } + it { is_expected.to run.with_params('some string').and_raise_error(ArgumentError, %r{'hash2kv' parameter 'input' expects a Hash value, got String}) } example_input = { 'HOSTNAME' => 'foo.example.com', @@ -13,7 +13,7 @@ } context 'no custom settings' do - output=<<-EOS + output = <<-EOS # THIS FILE IS CONTROLLED BY PUPPET HOSTNAME="foo.example.com" @@ -28,9 +28,9 @@ settings = { 'header' => '; THIS FILE IS CONTROLLED BY /dev/random', 'key_val_separator' => ': ', - 'quote_char' => "", + 'quote_char' => '', } - output=<<-EOS + output = <<-EOS ; THIS FILE IS CONTROLLED BY /dev/random HOSTNAME: foo.example.com diff --git a/spec/functions/hash2properties_spec.rb b/spec/functions/hash2properties_spec.rb index 4ecfb4c..03fcbe2 100644 --- a/spec/functions/hash2properties_spec.rb +++ b/spec/functions/hash2properties_spec.rb @@ -2,9 +2,9 @@ describe 'hash2properties' do it { is_expected.not_to eq(nil) } - it { is_expected.to run.with_params().and_raise_error(Puppet::ParseError, /requires at least one argument/) } - it { is_expected.to run.with_params({}, {}, {}).and_raise_error(Puppet::ParseError, /too many arguments/) } - it { is_expected.to run.with_params('some string').and_raise_error(Puppet::ParseError, /requires a hash as argument/) } + it { is_expected.to run.with_params.and_raise_error(ArgumentError, %r{'hash2properties' expects between 1 and 2 arguments, got none}) } + it { is_expected.to run.with_params({}, {}, {}).and_raise_error(ArgumentError, %r{'hash2properties' expects between 1 and 2 arguments, got 3}) } + it { is_expected.to run.with_params('some string').and_raise_error(ArgumentError, %r{'hash2properties' parameter 'input' expects a Hash value, got String}) } example_input = { 'main' => { @@ -20,17 +20,17 @@ 'list' => [ 'item1', 'item2', - ] - } + ], + }, }, 'dev' => { 'logging' => 'DEBUG', 'log_location' => '/var/log/dev.log', - } + }, } context 'no custom settings' do - output=<<-EOS + output = <<-EOS # THIS FILE IS CONTROLLED BY PUPPET dev.log_location=/var/log/dev.log @@ -52,7 +52,7 @@ 'key_val_separator' => ': ', 'quote_char' => '"', } - output=<<-EOS + output = <<-EOS # THIS FILE IS CONTROLLED BY /dev/random dev.log_location: "/var/log/dev.log" diff --git a/spec/functions/hash2yaml_spec.rb b/spec/functions/hash2yaml_spec.rb index 5009dda..e249f84 100644 --- a/spec/functions/hash2yaml_spec.rb +++ b/spec/functions/hash2yaml_spec.rb @@ -2,9 +2,9 @@ describe 'hash2yaml' do it { is_expected.not_to eq(nil) } - it { is_expected.to run.with_params().and_raise_error(Puppet::ParseError, /requires at least one argument/) } - it { is_expected.to run.with_params({}, {}, {}).and_raise_error(Puppet::ParseError, /too many arguments/) } - it { is_expected.to run.with_params('some string').and_raise_error(Puppet::ParseError, /requires a hash as argument/) } + it { is_expected.to run.with_params.and_raise_error(ArgumentError, %r{'hash2yaml' expects between 1 and 2 arguments, got none}) } + it { is_expected.to run.with_params({}, {}, {}).and_raise_error(ArgumentError, %r{'hash2yaml' expects between 1 and 2 arguments, got 3}) } + it { is_expected.to run.with_params('some string').and_raise_error(ArgumentError, %r{'hash2yaml' parameter 'input' expects a Hash value, got String}) } example_input = { 'domain' => 'example.com', @@ -13,10 +13,9 @@ 'user' => 'root', 'pass' => 'setec-astronomy', }, - 'awesome' => true, + 'awesome' => true, } - context 'default setting' do # https://github.com/hallettj/zaml/issues/3 # https://tickets.puppetlabs.com/browse/PUP-3120 @@ -24,20 +23,20 @@ # # puppet 3.x uses ZAML which formats YAML output differently than puppet 4.x - if Puppet.version.to_f < 4.0 - output=<<-EOS ---- + output = if Puppet.version.to_f < 4.0 + <<-EOS +--- domain: example.com - mysql: - hosts: + mysql: + hosts: - "192.0.2.2" - "192.0.2.4" user: root pass: setec-astronomy awesome: true EOS - else - output=<<-EOS + else + <<-EOS --- domain: example.com mysql: @@ -48,32 +47,31 @@ pass: setec-astronomy awesome: true EOS - end + end it { is_expected.to run.with_params(example_input).and_return(output) } - end - context "custom settings" do + context 'custom settings' do settings = { 'header' => '# THIS FILE IS CONTROLLED BY PUPPET', } - if Puppet.version.to_f < 4.0 - output=<<-EOS + output = if Puppet.version.to_f < 4.0 + <<-EOS # THIS FILE IS CONTROLLED BY PUPPET ---- +--- domain: example.com - mysql: - hosts: + mysql: + hosts: - "192.0.2.2" - "192.0.2.4" user: root pass: setec-astronomy awesome: true EOS - else - output=<<-EOS + else + <<-EOS # THIS FILE IS CONTROLLED BY PUPPET --- domain: example.com @@ -85,7 +83,7 @@ pass: setec-astronomy awesome: true EOS - end + end it { is_expected.to run.with_params(example_input, settings).and_return(output) } end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1ffdf17..5a5936b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,3 +1,67 @@ +# frozen_string_literal: true + +# Specify the mocking framework - https://tickets.puppetlabs.com/browse/PDK-916 +RSpec.configure do |c| + c.mock_with :rspec +end + require 'puppetlabs_spec_helper/module_spec_helper' require 'rspec-puppet-facts' + +require 'spec_helper_local' if File.file?(File.join(File.dirname(__FILE__), 'spec_helper_local.rb')) + include RspecPuppetFacts + +# Enable hiera data for unit tests +RSpec.configure do |c| + c.hiera_config = File.expand_path(File.join(__FILE__, '../fixtures/hiera.yaml')) +end + +default_facts = { + puppetversion: Puppet.version, + facterversion: Facter.version, +} + +default_fact_files = [ + File.expand_path(File.join(File.dirname(__FILE__), 'default_facts.yml')), + File.expand_path(File.join(File.dirname(__FILE__), 'default_module_facts.yml')), +] + +default_fact_files.each do |f| + next unless File.exist?(f) && File.readable?(f) && File.size?(f) + + begin + default_facts.merge!(YAML.safe_load(File.read(f), [], [], true)) + rescue => e + RSpec.configuration.reporter.message "WARNING: Unable to load #{f}: #{e}" + end +end + +# read default_facts and merge them over what is provided by facterdb +default_facts.each do |fact, value| + add_custom_fact fact, value +end + +RSpec.configure do |c| + c.default_facts = default_facts + c.before :each do + # set to strictest setting for testing + # by default Puppet runs at warning level + Puppet.settings[:strict] = :warning + Puppet.settings[:strict_variables] = true + end + c.filter_run_excluding(bolt: true) unless ENV['GEM_BOLT'] + c.after(:suite) do + end +end + +# Ensures that a module is defined +# @param module_name Name of the module +def ensure_module_defined(module_name) + module_name.split('::').reduce(Object) do |last_module, next_module| + last_module.const_set(next_module, Module.new) unless last_module.const_defined?(next_module, false) + last_module.const_get(next_module, false) + end +end + +# 'spec_overrides' from sync.yml will appear below this line