diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 38cacd4..f3ffb57 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,199 +1,279 @@ +# Contribution guidelines + +## Table of contents + +* [Contributing](#contributing) +* [Writing proper commits - short version](#writing-proper-commits-short-version) +* [Writing proper commits - long version](#writing-proper-commits-long-version) +* [Dependencies](#dependencies) + * [Note for OS X users](#note-for-os-x-users) +* [The test matrix](#the-test-matrix) +* [Syntax and style](#syntax-and-style) +* [Running the unit tests](#running-the-unit-tests) +* [Unit tests in docker](#unit-tests-in-docker) +* [Integration tests](#integration-tests) + This module has grown over time based on a range of contributions from people using it. If you follow these contributing guidelines your patch will likely make it into a release a little more quickly. ## Contributing Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms. [Contributor Code of Conduct](https://voxpupuli.org/coc/). -1. Fork the repo. - -1. Create a separate branch for your change. - -1. We only take pull requests with passing tests, and documentation. [travis-ci](http://travis-ci.org) - runs the tests for us. You can also execute them locally. This is explained - in a later section. - -1. Checkout [our docs](https://voxpupuli.org/docs/#reviewing-a-module-pr) we - use to review a module and the [official styleguide](https://puppet.com/docs/puppet/6.0/style_guide.html). - They provide some guidance for new code that might help you before you submit a pull request. - -1. Add a test for your change. Only refactoring and documentation - changes require no new tests. If you are adding functionality - or fixing a bug, please add a test. - -1. Squash your commits down into logical components. Make sure to rebase - against our current master. - -1. Push the branch to your fork and submit a pull request. - -Please be prepared to repeat some of these steps as our contributors review -your code. +* Fork the repo. +* Create a separate branch for your change. +* We only take pull requests with passing tests, and documentation. [travis-ci](http://travis-ci.org) runs the tests for us. You can also execute them locally. This is explained [in a later section](#the-test-matrix). +* Checkout [our docs](https://voxpupuli.org/docs/reviewing_pr/) we use to review a module and the [official styleguide](https://puppet.com/docs/puppet/6.0/style_guide.html). They provide some guidance for new code that might help you before you submit a pull request. +* Add a test for your change. Only refactoring and documentation changes require no new tests. If you are adding functionality or fixing a bug, please add a test. +* Squash your commits down into logical components. Make sure to rebase against our current master. +* Push the branch to your fork and submit a pull request. + +Please be prepared to repeat some of these steps as our contributors review your code. + +## Writing proper commits - short version + +* Make commits of logical units. +* Check for unnecessary whitespace with "git diff --check" before committing. +* Commit using Unix line endings (check the settings around "crlf" in git-config(1)). +* Do not check in commented out code or unneeded files. +* The first line of the commit message should be a short description (50 characters is the soft limit, excluding ticket number(s)), and should skip the full stop. +* Associate the issue in the message. The first line should include the issue number in the form "(#XXXX) Rest of message". +* The body should provide a meaningful commit message, which: + *uses the imperative, present tense: `change`, not `changed` or `changes`. + * includes motivation for the change, and contrasts its implementation with the previous behavior. + * Make sure that you have tests for the bug you are fixing, or feature you are adding. + * Make sure the test suites passes after your commit: + * When introducing a new feature, make sure it is properly documented in the README.md + +## Writing proper commits - long version + + 1. Make separate commits for logically separate changes. + + Please break your commits down into logically consistent units + which include new or changed tests relevant to the rest of the + change. The goal of doing this is to make the diff easier to + read for whoever is reviewing your code. In general, the easier + your diff is to read, the more likely someone will be happy to + review it and get it into the code base. + + If you are going to refactor a piece of code, please do so as a + separate commit from your feature or bug fix changes. + + We also really appreciate changes that include tests to make + sure the bug is not re-introduced, and that the feature is not + accidentally broken. + + Describe the technical detail of the change(s). If your + description starts to get too long, that is a good sign that you + probably need to split up your commit into more finely grained + pieces. + + Commits which plainly describe the things which help + reviewers check the patch and future developers understand the + code are much more likely to be merged in with a minimum of + bike-shedding or requested changes. Ideally, the commit message + would include information, and be in a form suitable for + inclusion in the release notes for the version of Puppet that + includes them. + + Please also check that you are not introducing any trailing + whitespace or other "whitespace errors". You can do this by + running "git diff --check" on your changes before you commit. + + 2. Sending your patches + + To submit your changes via a GitHub pull request, we _highly_ + recommend that you have them on a topic branch, instead of + directly on `master`. + It makes things much easier to keep track of, especially if + you decide to work on another thing before your first change + is merged in. + + GitHub has some pretty good + [general documentation](http://help.github.com/) on using + their site. They also have documentation on + [creating pull requests](http://help.github.com/send-pull-requests/). + + In general, after pushing your topic branch up to your + repository on GitHub, you can switch to the branch in the + GitHub UI and click "Pull Request" towards the top of the page + in order to open a pull request. + + + 3. Update the related GitHub issue. + + If there is a GitHub issue associated with the change you + submitted, then you should update the ticket to include the + location of your branch, along with any other commentary you + may wish to make. ## Dependencies The testing and development tools have a bunch of dependencies, all managed by [bundler](http://bundler.io/) according to the [Puppet support matrix](http://docs.puppetlabs.com/guides/platforms.html#ruby-versions). By default the tests use a baseline version of Puppet. If you have Ruby 2.x or want a specific version of Puppet, you must set an environment variable such as: ```sh export PUPPET_VERSION="~> 5.5.6" ``` You can install all needed gems for spec tests into the modules directory by running: ```sh bundle install --path .vendor/ --without development system_tests release --jobs "$(nproc)" ``` If you also want to run acceptance tests: ```sh bundle install --path .vendor/ --with system_tests --without development release --jobs "$(nproc)" ``` Our all in one solution if you don't know if you need to install or update gems: ```sh bundle install --path .vendor/ --with system_tests --without development release --jobs "$(nproc)"; bundle update; bundle clean ``` As an alternative to the `--jobs "$(nproc)` parameter, you can set an environment variable: ```sh BUNDLE_JOBS="$(nproc)" ``` ### Note for OS X users -`nproc` isn't a valid command unter OS x. As an alternative, you can do: +`nproc` isn't a valid command under OS x. As an alternative, you can do: ```sh --jobs "$(sysctl -n hw.ncpu)" ``` -## Syntax and style +## The test matrix + +### Syntax and style The test suite will run [Puppet Lint](http://puppet-lint.com/) and [Puppet Syntax](https://github.com/gds-operations/puppet-syntax) to check various syntax and style things. You can run these locally with: ```sh bundle exec rake lint bundle exec rake validate ``` It will also run some [Rubocop](http://batsov.com/rubocop/) tests against it. You can run those locally ahead of time with: ```sh bundle exec rake rubocop ``` -## Running the unit tests +### Running the unit tests The unit test suite covers most of the code, as mentioned above please add tests if you're adding new functionality. If you've not used [rspec-puppet](http://rspec-puppet.com/) before then feel free to ask about how best to test your new feature. To run the linter, the syntax checker and the unit tests: ```sh bundle exec rake test ``` To run your all the unit tests ```sh bundle exec rake spec ``` To run a specific spec test set the `SPEC` variable: ```sh bundle exec rake spec SPEC=spec/foo_spec.rb ``` -### Unit tests in docker +#### Unit tests in docker Some people don't want to run the dependencies locally or don't want to install ruby. We ship a Dockerfile that enables you to run all unit tests and linting. You only need to run: ```sh docker build . ``` Please ensure that a docker daemon is running and that your user has the permission to talk to it. You can specify a remote docker host by setting the `DOCKER_HOST` environment variable. it will copy the content of the module into the docker image. So it will not work if a Gemfile.lock exists. -## Integration tests +### Integration tests The unit tests just check the code runs, not that it does exactly what we want on a real machine. For that we're using [beaker](https://github.com/puppetlabs/beaker). This fires up a new virtual machine (using vagrant) and runs a series of simple tests against it after applying the module. You can run this with: ```sh bundle exec rake acceptance ``` This will run the tests on the module's default nodeset. You can override the nodeset used, e.g., ```sh BEAKER_set=centos-7-x64 bundle exec rake acceptance ``` There are default rake tasks for the various acceptance test modules, e.g., ```sh bundle exec rake beaker:centos-7-x64 bundle exec rake beaker:ssh:centos-7-x64 ``` If you don't want to have to recreate the virtual machine every time you can use `BEAKER_destroy=no` and `BEAKER_provision=no`. On the first run you will at least need `BEAKER_provision` set to yes (the default). The Vagrantfile for the created virtual machines will be in `.vagrant/beaker_vagrant_files`. Beaker also supports docker containers. We also use that in our automated CI pipeline at [travis-ci](http://travis-ci.org). To use that instead of Vagrant: ```sh PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=debian9-64{hypervisor=docker} BEAKER_destroy=yes bundle exec rake beaker ``` You can replace the string `debian9` with any common operating system. The following strings are known to work: * ubuntu1604 * ubuntu1804 * debian8 * debian9 * centos6 * centos7 The easiest way to debug in a docker container is to open a shell: ```sh docker exec -it -u root ${container_id_or_name} bash ``` The source of this file is in our [modulesync_config](https://github.com/voxpupuli/modulesync_config/blob/master/moduleroot/.github/CONTRIBUTING.md.erb) repository. diff --git a/.msync.yml b/.msync.yml index 23dfa32..11aed5f 100644 --- a/.msync.yml +++ b/.msync.yml @@ -1 +1 @@ -modulesync_config_version: '2.8.0' +modulesync_config_version: '2.10.0' diff --git a/.rubocop.yml b/.rubocop.yml index 099a11c..5984ccc 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,545 +1,545 @@ require: rubocop-rspec AllCops: - TargetRubyVersion: 1.9 + TargetRubyVersion: 2.1 Include: - ./**/*.rb Exclude: - files/**/* - vendor/**/* - .vendor/**/* - pkg/**/* - spec/fixtures/**/* - Gemfile - Rakefile - Guardfile - Vagrantfile Lint/ConditionPosition: Enabled: True Lint/ElseLayout: Enabled: True Lint/UnreachableCode: Enabled: True Lint/UselessComparison: Enabled: True Lint/EnsureReturn: Enabled: True Lint/HandleExceptions: Enabled: True Lint/LiteralInCondition: Enabled: True Lint/ShadowingOuterLocalVariable: Enabled: True Lint/LiteralInInterpolation: Enabled: True Style/HashSyntax: Enabled: True Style/RedundantReturn: Enabled: True Layout/EndOfLine: Enabled: False Lint/AmbiguousOperator: Enabled: True Lint/AssignmentInCondition: Enabled: True Layout/SpaceBeforeComment: Enabled: True Style/AndOr: Enabled: True Style/RedundantSelf: Enabled: True Metrics/BlockLength: Enabled: False # Method length is not necessarily an indicator of code quality Metrics/MethodLength: Enabled: False # Module length is not necessarily an indicator of code quality Metrics/ModuleLength: Enabled: False Style/WhileUntilModifier: Enabled: True Lint/AmbiguousRegexpLiteral: Enabled: True Security/Eval: Enabled: True Lint/BlockAlignment: Enabled: True Lint/DefEndAlignment: Enabled: True Lint/EndAlignment: Enabled: True Lint/DeprecatedClassMethods: Enabled: True Lint/Loop: Enabled: True Lint/ParenthesesAsGroupedExpression: Enabled: True Lint/RescueException: Enabled: True Lint/StringConversionInInterpolation: Enabled: True Lint/UnusedBlockArgument: Enabled: True Lint/UnusedMethodArgument: Enabled: True Lint/UselessAccessModifier: Enabled: True Lint/UselessAssignment: Enabled: True Lint/Void: Enabled: True Layout/AccessModifierIndentation: Enabled: True Style/AccessorMethodName: Enabled: True Style/Alias: Enabled: True Layout/AlignArray: Enabled: True Layout/AlignHash: Enabled: True Layout/AlignParameters: Enabled: True Metrics/BlockNesting: Enabled: True Style/AsciiComments: Enabled: True Style/Attr: Enabled: True Style/BracesAroundHashParameters: Enabled: True Style/CaseEquality: Enabled: True Layout/CaseIndentation: Enabled: True Style/CharacterLiteral: Enabled: True Style/ClassAndModuleCamelCase: Enabled: True Style/ClassAndModuleChildren: Enabled: False Style/ClassCheck: Enabled: True # Class length is not necessarily an indicator of code quality Metrics/ClassLength: Enabled: False Style/ClassMethods: Enabled: True Style/ClassVars: Enabled: True Style/WhenThen: Enabled: True Style/WordArray: Enabled: True Style/UnneededPercentQ: Enabled: True Layout/Tab: Enabled: True Layout/SpaceBeforeSemicolon: Enabled: True Layout/TrailingBlankLines: Enabled: True Layout/SpaceInsideBlockBraces: Enabled: True Layout/SpaceInsideBrackets: Enabled: True Layout/SpaceInsideHashLiteralBraces: Enabled: True Layout/SpaceInsideParens: Enabled: True Layout/LeadingCommentSpace: Enabled: True Layout/SpaceBeforeFirstArg: Enabled: True Layout/SpaceAfterColon: Enabled: True Layout/SpaceAfterComma: Enabled: True Layout/SpaceAfterMethodName: Enabled: True Layout/SpaceAfterNot: Enabled: True Layout/SpaceAfterSemicolon: Enabled: True Layout/SpaceAroundEqualsInParameterDefault: Enabled: True Layout/SpaceAroundOperators: Enabled: True Layout/SpaceBeforeBlockBraces: Enabled: True Layout/SpaceBeforeComma: Enabled: True Style/CollectionMethods: Enabled: True Layout/CommentIndentation: Enabled: True Style/ColonMethodCall: Enabled: True Style/CommentAnnotation: Enabled: True # 'Complexity' is very relative Metrics/CyclomaticComplexity: Enabled: False Style/ConstantName: Enabled: True Style/Documentation: Enabled: False Style/DefWithParentheses: Enabled: True Style/PreferredHashMethods: Enabled: True Layout/DotPosition: EnforcedStyle: trailing Style/DoubleNegation: Enabled: True Style/EachWithObject: Enabled: True Layout/EmptyLineBetweenDefs: Enabled: True Layout/IndentArray: Enabled: True Layout/IndentHash: Enabled: True Layout/IndentationConsistency: Enabled: True Layout/IndentationWidth: Enabled: True Layout/EmptyLines: Enabled: True Layout/EmptyLinesAroundAccessModifier: Enabled: True Style/EmptyLiteral: Enabled: True # Configuration parameters: AllowURI, URISchemes. Metrics/LineLength: Enabled: False Style/MethodCallWithoutArgsParentheses: Enabled: True Style/MethodDefParentheses: Enabled: True Style/LineEndConcatenation: Enabled: True Layout/TrailingWhitespace: Enabled: True Style/StringLiterals: Enabled: True Style/TrailingCommaInArguments: Enabled: True Style/TrailingCommaInLiteral: Enabled: True Style/GlobalVars: Enabled: True Style/GuardClause: Enabled: True Style/IfUnlessModifier: Enabled: True Style/MultilineIfThen: Enabled: True Style/NegatedIf: Enabled: True Style/NegatedWhile: Enabled: True Style/Next: Enabled: True Style/SingleLineBlockParams: Enabled: True Style/SingleLineMethods: Enabled: True Style/SpecialGlobalVars: Enabled: True Style/TrivialAccessors: Enabled: True Style/UnlessElse: Enabled: True Style/VariableInterpolation: Enabled: True Style/VariableName: Enabled: True Style/WhileUntilDo: Enabled: True Style/EvenOdd: Enabled: True Style/FileName: Enabled: True Style/For: Enabled: True Style/Lambda: Enabled: True Style/MethodName: Enabled: True Style/MultilineTernaryOperator: Enabled: True Style/NestedTernaryOperator: Enabled: True Style/NilComparison: Enabled: True Style/FormatString: Enabled: True Style/MultilineBlockChain: Enabled: True Style/Semicolon: Enabled: True Style/SignalException: Enabled: True Style/NonNilCheck: Enabled: True Style/Not: Enabled: True Style/NumericLiterals: Enabled: True Style/OneLineConditional: Enabled: True Style/OpMethod: Enabled: True Style/ParenthesesAroundCondition: Enabled: True Style/PercentLiteralDelimiters: Enabled: True Style/PerlBackrefs: Enabled: True Style/PredicateName: Enabled: True Style/RedundantException: Enabled: True Style/SelfAssignment: Enabled: True Style/Proc: Enabled: True Style/RaiseArgs: Enabled: True Style/RedundantBegin: Enabled: True Style/RescueModifier: Enabled: True # based on https://github.com/voxpupuli/modulesync_config/issues/168 Style/RegexpLiteral: EnforcedStyle: percent_r Enabled: True Lint/UnderscorePrefixedVariableName: Enabled: True Metrics/ParameterLists: Enabled: False Lint/RequireParentheses: Enabled: True Style/ModuleFunction: Enabled: True Lint/Debugger: Enabled: True Style/IfWithSemicolon: Enabled: True Style/Encoding: Enabled: True Style/BlockDelimiters: Enabled: True Layout/MultilineBlockLayout: Enabled: True # 'Complexity' is very relative Metrics/AbcSize: Enabled: False # 'Complexity' is very relative Metrics/PerceivedComplexity: Enabled: False Lint/UselessAssignment: Enabled: True Layout/ClosingParenthesisIndentation: Enabled: True # RSpec RSpec/BeforeAfterAll: Exclude: - spec/acceptance/**/* # We don't use rspec in this way RSpec/DescribeClass: Enabled: False # Example length is not necessarily an indicator of code quality RSpec/ExampleLength: Enabled: False RSpec/NamedSubject: Enabled: False # disabled for now since they cause a lot of issues # these issues aren't easy to fix RSpec/RepeatedDescription: Enabled: False RSpec/NestedGroups: Enabled: False # this is broken on ruby1.9 Layout/IndentHeredoc: Enabled: False # disable Yaml safe_load. This is needed to support ruby2.0.0 development envs Security/YAMLLoad: Enabled: false # This affects hiera interpolation, as well as some configs that we push. Style/FormatStringToken: Enabled: false # This is useful, but sometimes a little too picky about where unit tests files # are located. RSpec/FilePath: Enabled: false diff --git a/.sync.yml b/.sync.yml index 3faa6d5..408c0b3 100644 --- a/.sync.yml +++ b/.sync.yml @@ -1,16 +1,12 @@ --- .travis.yml: docker_sets: - set: centos7-64 - set: debian9-64 + - set: debian10-64 - set: fedora29-64 - set: fedora30-64 - set: ubuntu1604-64 - set: ubuntu1804-64 - extras: - - rvm: 2.5.3 - services: docker - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=debian10-64 BEAKER_HYPERVISOR=docker CHECK=beaker - bundler_args: --without development release secure: "n/CVUS2upgv5DifCm/YsjBxR/11bdTRDYi1x9QK6ILa32+6ngVV2RQaIMXXJfJKYIPT8/O21tpc9C7fOBRGhRpNbl0usfvqsZS0C9UkpEx6AqT7lcRzj6pLrNn3IuChhZ0tQjNiKp9LxVTzltxr5uTFwKKCE4o534v/DLAzkzq5EAZuBWpRS1rcVHQA3o0767Gu3601yyYkZj9ySDH5RpbSdTCcNkTzwtFhr2NEvVb+2FI0RhchDSqPBfNWHV4Hn3dKuL42MNC2zjd2FYFpC8F27OXk/erUZIOZFfpZuIWypjSimfVC95a2Nb8kfQotTvQxUI1fwiB01ibUQGGkJj+mh7Utg/byBrbijpJnWRR7TT6oQ1NbIUHVXcqE1tfpbCBZ4Ws2Hqji0QoGc0fMrkt1NVlZlgbVrb9t+ctb1QcLaEPI+1Zf2a3AZhXOKA1EGx2W5DTQSWSPv57BUtFPICZENQi/ats30h+0FwtN7rjfx8Q6BIGO2D5JODI6eJC0nLNaL5UaPA0pjGRsNlZWoUzieuKG08G/rQtj/8jLq/3eLICv1cbfvj7lDPc0thPwXdrPIC9nLSisb/wdLufpqXsFku9TeBqrRHfQWImybcv7JRAeZZeHEo+tvFvZg5MSAEiPmz8zIOJOKhuMKEXlOmALmSjEhW6Ca5r7xuQ5Qwm0=" diff --git a/.travis.yml b/.travis.yml index 4ecda04..c4859ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,99 +1,103 @@ --- -dist: xenial +dist: bionic language: ruby cache: bundler before_install: - - gem update --system - - gem update bundler + - yes | gem update --system - bundle --version script: - 'bundle exec rake $CHECK' matrix: fast_finish: true include: - rvm: 2.4.4 bundler_args: --without system_tests development release env: PUPPET_VERSION="~> 5.0" CHECK=test - rvm: 2.5.3 bundler_args: --without system_tests development release env: PUPPET_VERSION="~> 6.0" CHECK=test_with_coveralls - rvm: 2.5.3 bundler_args: --without system_tests development release env: PUPPET_VERSION="~> 6.0" CHECK=rubocop - rvm: 2.4.4 bundler_args: --without system_tests development release env: PUPPET_VERSION="~> 5.0" CHECK=build DEPLOY_TO_FORGE=yes - rvm: 2.5.3 bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=centos7-64 BEAKER_HYPERVISOR=docker CHECK=beaker + env: PUPPET_INSTALL_TYPE=agent BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=centos7-64 BEAKER_HYPERVISOR=docker CHECK=beaker services: docker - rvm: 2.5.3 bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=centos7-64 BEAKER_HYPERVISOR=docker CHECK=beaker + env: PUPPET_INSTALL_TYPE=agent BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=centos7-64 BEAKER_HYPERVISOR=docker CHECK=beaker services: docker - rvm: 2.5.3 bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=debian9-64 BEAKER_HYPERVISOR=docker CHECK=beaker + env: PUPPET_INSTALL_TYPE=agent BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=debian9-64 BEAKER_HYPERVISOR=docker CHECK=beaker services: docker - rvm: 2.5.3 bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=debian9-64 BEAKER_HYPERVISOR=docker CHECK=beaker + env: PUPPET_INSTALL_TYPE=agent BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=debian9-64 BEAKER_HYPERVISOR=docker CHECK=beaker services: docker - rvm: 2.5.3 bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=debian10-64 BEAKER_HYPERVISOR=docker CHECK=beaker + env: PUPPET_INSTALL_TYPE=agent BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=debian10-64 BEAKER_HYPERVISOR=docker CHECK=beaker services: docker - rvm: 2.5.3 bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=fedora29-64 BEAKER_HYPERVISOR=docker CHECK=beaker + env: PUPPET_INSTALL_TYPE=agent BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=debian10-64 BEAKER_HYPERVISOR=docker CHECK=beaker services: docker - rvm: 2.5.3 bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=fedora29-64 BEAKER_HYPERVISOR=docker CHECK=beaker + env: PUPPET_INSTALL_TYPE=agent BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=fedora29-64 BEAKER_HYPERVISOR=docker CHECK=beaker services: docker - rvm: 2.5.3 bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=fedora30-64 BEAKER_HYPERVISOR=docker CHECK=beaker + env: PUPPET_INSTALL_TYPE=agent BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=fedora29-64 BEAKER_HYPERVISOR=docker CHECK=beaker services: docker - rvm: 2.5.3 bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=fedora30-64 BEAKER_HYPERVISOR=docker CHECK=beaker + env: PUPPET_INSTALL_TYPE=agent BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=fedora30-64 BEAKER_HYPERVISOR=docker CHECK=beaker services: docker - rvm: 2.5.3 bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=ubuntu1604-64 BEAKER_HYPERVISOR=docker CHECK=beaker + env: PUPPET_INSTALL_TYPE=agent BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=fedora30-64 BEAKER_HYPERVISOR=docker CHECK=beaker services: docker - rvm: 2.5.3 bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=ubuntu1604-64 BEAKER_HYPERVISOR=docker CHECK=beaker + env: PUPPET_INSTALL_TYPE=agent BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=ubuntu1604-64 BEAKER_HYPERVISOR=docker CHECK=beaker services: docker - rvm: 2.5.3 bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=ubuntu1804-64 BEAKER_HYPERVISOR=docker CHECK=beaker + env: PUPPET_INSTALL_TYPE=agent BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=ubuntu1604-64 BEAKER_HYPERVISOR=docker CHECK=beaker services: docker - rvm: 2.5.3 bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=ubuntu1804-64 BEAKER_HYPERVISOR=docker CHECK=beaker + env: PUPPET_INSTALL_TYPE=agent BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=ubuntu1804-64 BEAKER_HYPERVISOR=docker CHECK=beaker + services: docker + - rvm: 2.5.3 + bundler_args: --without development release + env: PUPPET_INSTALL_TYPE=agent BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=ubuntu1804-64 BEAKER_HYPERVISOR=docker CHECK=beaker services: docker branches: only: - master - /^v\d/ notifications: email: false + webhooks: https://voxpupu.li/incoming/travis irc: on_success: always on_failure: always channels: - "chat.freenode.org#voxpupuli-notifications" deploy: provider: puppetforge user: puppet password: secure: "n/CVUS2upgv5DifCm/YsjBxR/11bdTRDYi1x9QK6ILa32+6ngVV2RQaIMXXJfJKYIPT8/O21tpc9C7fOBRGhRpNbl0usfvqsZS0C9UkpEx6AqT7lcRzj6pLrNn3IuChhZ0tQjNiKp9LxVTzltxr5uTFwKKCE4o534v/DLAzkzq5EAZuBWpRS1rcVHQA3o0767Gu3601yyYkZj9ySDH5RpbSdTCcNkTzwtFhr2NEvVb+2FI0RhchDSqPBfNWHV4Hn3dKuL42MNC2zjd2FYFpC8F27OXk/erUZIOZFfpZuIWypjSimfVC95a2Nb8kfQotTvQxUI1fwiB01ibUQGGkJj+mh7Utg/byBrbijpJnWRR7TT6oQ1NbIUHVXcqE1tfpbCBZ4Ws2Hqji0QoGc0fMrkt1NVlZlgbVrb9t+ctb1QcLaEPI+1Zf2a3AZhXOKA1EGx2W5DTQSWSPv57BUtFPICZENQi/ats30h+0FwtN7rjfx8Q6BIGO2D5JODI6eJC0nLNaL5UaPA0pjGRsNlZWoUzieuKG08G/rQtj/8jLq/3eLICv1cbfvj7lDPc0thPwXdrPIC9nLSisb/wdLufpqXsFku9TeBqrRHfQWImybcv7JRAeZZeHEo+tvFvZg5MSAEiPmz8zIOJOKhuMKEXlOmALmSjEhW6Ca5r7xuQ5Qwm0=" 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/Dockerfile b/Dockerfile index 67048bb..6fd6342 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,21 @@ FROM ruby:2.5.3 WORKDIR /opt/puppet # https://github.com/puppetlabs/puppet/blob/06ad255754a38f22fb3a22c7c4f1e2ce453d01cb/lib/puppet/provider/service/runit.rb#L39 RUN mkdir -p /etc/sv ARG PUPPET_VERSION="~> 6.0" ARG PARALLEL_TEST_PROCESSORS=4 # Cache gems COPY Gemfile . RUN bundle install --without system_tests development release --path=${BUNDLE_PATH:-vendor/bundle} COPY . . RUN bundle install -RUN bundle exec release_checks +RUN bundle exec rake release_checks # Container should not saved RUN exit 1 diff --git a/Gemfile b/Gemfile index 9571ef3..185dcf0 100644 --- a/Gemfile +++ b/Gemfile @@ -1,83 +1,88 @@ source ENV['GEM_SOURCE'] || "https://rubygems.org" def location_for(place, fake_version = nil) if place =~ /^(git[:@][^#]*)#(.*)/ [fake_version, { :git => $1, :branch => $2, :require => false }].compact elsif place =~ /^file:\/\/(.*)/ ['>= 0', { :path => File.expand_path($1), :require => false }] else [place, { :require => false }] end end group :test do gem 'puppetlabs_spec_helper', '>= 2.14.0', :require => false - gem 'rspec-puppet-facts', '>= 1.8.0', :require => false + gem 'rspec-puppet-facts', '>= 1.9.5', :require => false gem 'rspec-puppet-utils', :require => false gem 'puppet-lint-leading_zero-check', :require => false gem 'puppet-lint-trailing_comma-check', :require => false gem 'puppet-lint-version_comparison-check', :require => false gem 'puppet-lint-classes_and_types_beginning_with_digits-check', :require => false gem 'puppet-lint-unquoted_string-check', :require => false gem 'puppet-lint-variable_contains_upcase', :require => false - gem 'puppet-lint-absolute_classname-check', :require => false + gem 'puppet-lint-absolute_classname-check', '>= 2.0.0', :require => false gem 'puppet-lint-topscope-variable-check', :require => false + gem 'puppet-lint-legacy_facts-check', :require => false + gem 'puppet-lint-anchor-check', :require => false gem 'metadata-json-lint', :require => false gem 'redcarpet', :require => false gem 'rubocop', '~> 0.49.1', :require => false gem 'rubocop-rspec', '~> 1.15.0', :require => false gem 'mocha', '~> 1.4.0', :require => false gem 'coveralls', :require => false gem 'simplecov-console', :require => false gem 'parallel_tests', :require => false + # we require unreleased Fedora 30 fact sets + # https://github.com/camptocamp/facterdb/commit/1bc038fd42aac53344ac1ee9c129cbccf5b5c0aa + gem 'facterdb', :require => false, :git => 'https://github.com/camptocamp/facterdb.git', :branch => 'master' end group :development do gem 'travis', :require => false gem 'travis-lint', :require => false gem 'guard-rake', :require => false gem 'overcommit', '>= 0.39.1', :require => false end group :system_tests do gem 'winrm', :require => false if beaker_version = ENV['BEAKER_VERSION'] gem 'beaker', *location_for(beaker_version) else gem 'beaker', '>= 4.2.0', :require => false end if beaker_rspec_version = ENV['BEAKER_RSPEC_VERSION'] gem 'beaker-rspec', *location_for(beaker_rspec_version) else gem 'beaker-rspec', :require => false end gem 'serverspec', :require => false gem 'beaker-hostgenerator', '>= 1.1.22', :require => false gem 'beaker-docker', :require => false gem 'beaker-puppet', :require => false gem 'beaker-puppet_install_helper', :require => false gem 'beaker-module_install_helper', :require => false gem 'rbnacl', '>= 4', :require => false gem 'rbnacl-libsodium', :require => false gem 'bcrypt_pbkdf', :require => false end group :release do - gem 'github_changelog_generator', :require => false, :git => 'https://github.com/github-changelog-generator/github-changelog-generator' + gem 'github_changelog_generator', :require => false, :git => 'https://github.com/voxpupuli/github-changelog-generator', :branch => 'voxpupuli_essential_fixes' gem 'puppet-blacksmith', :require => false - gem 'voxpupuli-release', :require => false, :git => 'https://github.com/voxpupuli/voxpupuli-release-gem' + gem 'voxpupuli-release', :require => false gem 'puppet-strings', '>= 2.2', :require => false end if facterversion = ENV['FACTER_GEM_VERSION'] gem 'facter', facterversion.to_s, :require => false, :groups => [:test] else gem 'facter', :require => false, :groups => [:test] end ENV['PUPPET_VERSION'].nil? ? puppetversion = '~> 6.0' : puppetversion = ENV['PUPPET_VERSION'].to_s gem 'puppet', puppetversion, :require => false, :groups => [:test] # vim: syntax=ruby diff --git a/Rakefile b/Rakefile index 09701d0..c0f2d37 100644 --- a/Rakefile +++ b/Rakefile @@ -1,82 +1,85 @@ require 'puppetlabs_spec_helper/rake_tasks' # load optional tasks for releases # only available if gem group releases is installed begin require 'voxpupuli/release/rake_tasks' rescue LoadError end PuppetLint.configuration.log_format = '%{path}:%{line}:%{check}:%{KIND}:%{message}' -PuppetLint.configuration.absolute_classname_reverse = true - -exclude_paths = %w( - pkg/**/* - vendor/**/* - .vendor/**/* - spec/**/* -) -PuppetLint.configuration.ignore_paths = exclude_paths -PuppetSyntax.exclude_paths = exclude_paths desc 'Auto-correct puppet-lint offenses' task 'lint:auto_correct' do Rake::Task[:lint_fix].invoke end desc 'Run acceptance tests' RSpec::Core::RakeTask.new(:acceptance) do |t| t.pattern = 'spec/acceptance' end desc 'Run tests' task test: [:release_checks] namespace :check do desc 'Check for trailing whitespace' task :trailing_whitespace do Dir.glob('**/*.md', File::FNM_DOTMATCH).sort.each do |filename| next if filename =~ %r{^((modules|acceptance|\.?vendor|spec/fixtures|pkg)/|REFERENCE.md)} File.foreach(filename).each_with_index do |line, index| if line =~ %r{\s\n$} puts "#{filename} has trailing whitespace on line #{index + 1}" exit 1 end end end end end Rake::Task[:release_checks].enhance ['check:trailing_whitespace'] desc "Run main 'test' task and report merged results to coveralls" task test_with_coveralls: [:test] do if Dir.exist?(File.expand_path('../lib', __FILE__)) require 'coveralls/rake/task' Coveralls::RakeTask.new Rake::Task['coveralls:push'].invoke else puts 'Skipping reporting to coveralls. Module has no lib dir' end end desc 'Generate REFERENCE.md' task :reference, [:debug, :backtrace] do |t, args| patterns = '' Rake::Task['strings:generate:reference'].invoke(patterns, args[:debug], args[:backtrace]) end begin require 'github_changelog_generator/task' GitHubChangelogGenerator::RakeTask.new :changelog do |config| version = (Blacksmith::Modulefile.new).version config.future_release = "v#{version}" if version =~ /^\d+\.\d+.\d+$/ config.header = "# Changelog\n\nAll notable changes to this project will be documented in this file.\nEach new release typically also includes the latest modulesync defaults.\nThese should not affect the functionality of the module." config.exclude_labels = %w{duplicate question invalid wontfix wont-fix modulesync skip-changelog} config.user = 'voxpupuli' metadata_json = File.join(File.dirname(__FILE__), 'metadata.json') metadata = JSON.load(File.read(metadata_json)) config.project = metadata['name'] end + + # Workaround for https://github.com/github-changelog-generator/github-changelog-generator/issues/715 + require 'rbconfig' + if RbConfig::CONFIG['host_os'] =~ /linux/ + task :changelog do + puts 'Fixing line endings...' + changelog_file = File.join(__dir__, 'CHANGELOG.md') + changelog_txt = File.read(changelog_file) + new_contents = changelog_txt.gsub(%r{\r\n}, "\n") + File.open(changelog_file, "w") {|file| file.puts new_contents } + end + end + rescue LoadError end # vim: syntax=ruby diff --git a/metadata.json b/metadata.json index 8b76e61..1c1cadf 100644 --- a/metadata.json +++ b/metadata.json @@ -1,88 +1,88 @@ { "name": "puppet-letsencrypt", "version": "5.0.1-rc0", "author": "Vox Pupuli", "summary": "Manages lets-encrypt and certbot + related certs", "license": "Apache-2.0", "source": "https://github.com/voxpupuli/puppet-letsencrypt", "project_page": "https://github.com/voxpupuli/puppet-letsencrypt", "issues_url": "https://github.com/voxpupuli/puppet-letsencrypt/issues", "tags": [ "letsencrypt", "let's encrypt", "certbot", "acme" ], "operatingsystem_support": [ { "operatingsystem": "CentOS", "operatingsystemrelease": [ "7" ] }, { "operatingsystem": "RedHat", "operatingsystemrelease": [ "7" ] }, { "operatingsystem": "Fedora", "operatingsystemrelease": [ "29", "30" ] }, { "operatingsystem": "Ubuntu", "operatingsystemrelease": [ "16.04", "18.04" ] }, { "operatingsystem": "Debian", "operatingsystemrelease": [ "9", "10" ] }, { "operatingsystem": "OpenBSD", "operatingsystemrelease": [ "6.2" ] }, { "operatingsystem": "FreeBSD", "operatingsystemrelease": [ - "10", - "11" + "11", + "12" ] } ], "requirements": [ { "name": "puppet", "version_requirement": ">= 5.5.8 < 7.0.0" } ], "dependencies": [ { "name": "puppetlabs/stdlib", "version_requirement": ">= 4.13.1 < 7.0.0" }, { "name": "puppetlabs/inifile", "version_requirement": ">= 2.0.0 < 5.0.0" }, { "name": "puppetlabs/vcsrepo", "version_requirement": ">= 2.0.0 < 4.0.0" }, { "name": "stahnma/epel", "version_requirement": ">= 1.0.0 < 2.0.0" } ] } diff --git a/spec/defines/letsencrypt_certonly_spec.rb b/spec/defines/letsencrypt_certonly_spec.rb index f162103..f92be52 100644 --- a/spec/defines/letsencrypt_certonly_spec.rb +++ b/spec/defines/letsencrypt_certonly_spec.rb @@ -1,433 +1,433 @@ require 'spec_helper' describe 'letsencrypt::certonly' do on_supported_os.each do |os, facts| context "on #{os} based operating systems" do let :facts do facts end let(:pre_condition) { "class { letsencrypt: email => 'foo@example.com', package_command => 'letsencrypt' }" } # FreeBSD uses a different filesystem path pathprefix = facts[:kernel] == 'FreeBSD' ? '/usr/local' : '' context 'with a single domain' do let(:title) { 'foo.example.com' } it { is_expected.to compile.with_all_deps } it { is_expected.to contain_class('Letsencrypt::Install') } it { is_expected.to contain_class('Letsencrypt::Config') } if facts[:osfamily] == 'FreeBSD' it { is_expected.to contain_file('/usr/local/etc/letsencrypt') } it { is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini email foo@example.com') } it { is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini server https://acme-v02.api.letsencrypt.org/directory') } else it { is_expected.to contain_file('/etc/letsencrypt') } - it { is_expected.to contain_package('letsencrypt') } unless facts[:os]['release']['full'] == '14.04' + it { is_expected.to contain_package('letsencrypt') } it { is_expected.to contain_ini_setting('/etc/letsencrypt/cli.ini email foo@example.com') } it { is_expected.to contain_ini_setting('/etc/letsencrypt/cli.ini server https://acme-v02.api.letsencrypt.org/directory') } end it { is_expected.to contain_exec('initialize letsencrypt') } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com') } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_unless "/usr/local/sbin/letsencrypt-domain-validation #{pathprefix}/etc/letsencrypt/live/foo.example.com/cert.pem 'foo.example.com'" } end context 'with ensure absent' do let(:title) { 'foo.example.com' } let(:params) { { ensure: 'absent' } } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com') } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_command "letsencrypt --text --agree-tos --non-interactive delete --cert-name 'foo.example.com'" } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_onlyif "/usr/local/sbin/letsencrypt-domain-validation #{pathprefix}/etc/letsencrypt/live/foo.example.com/cert.pem 'foo.example.com'" } end context 'with multiple domains' do let(:title) { 'foo' } let(:params) { { domains: ['foo.example.com', 'bar.example.com', '*.example.com'] } } it { is_expected.to compile.with_all_deps } it { is_expected.to contain_exec('letsencrypt certonly foo').with_command "letsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo' -d 'foo.example.com' -d 'bar.example.com' -d '*.example.com'" } end context 'with custom command' do let(:title) { 'foo.example.com' } let(:params) { { letsencrypt_command: '/usr/lib/letsencrypt/letsencrypt-auto' } } it { is_expected.to compile.with_all_deps } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_command '/usr/lib/letsencrypt/letsencrypt-auto --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name \'foo.example.com\' -d \'foo.example.com\'' } end context 'with webroot plugin' do let(:title) { 'foo.example.com' } let(:params) do { plugin: 'webroot', webroot_paths: ['/var/www/foo'] } end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_command "letsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a webroot --cert-name 'foo.example.com' --webroot-path /var/www/foo -d 'foo.example.com'" } end context 'with webroot plugin and multiple domains' do let(:title) { 'foo' } let(:params) do { domains: ['foo.example.com', 'bar.example.com'], plugin: 'webroot', webroot_paths: ['/var/www/foo', '/var/www/bar'] } end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_exec('letsencrypt certonly foo').with_command "letsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a webroot --cert-name 'foo' --webroot-path /var/www/foo -d 'foo.example.com' --webroot-path /var/www/bar -d 'bar.example.com'" } end context 'with webroot plugin, one webroot, and multiple domains' do let(:title) { 'foo' } let(:params) do { domains: ['foo.example.com', 'bar.example.com'], plugin: 'webroot', webroot_paths: ['/var/www/foo'] } end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_exec('letsencrypt certonly foo').with_command "letsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a webroot --cert-name 'foo' --webroot-path /var/www/foo -d 'foo.example.com' -d 'bar.example.com'" } end context 'with webroot plugin and no webroot_paths' do let(:title) { 'foo.example.com' } let(:params) { { plugin: 'webroot' } } it { is_expected.not_to compile.with_all_deps } it { is_expected.to raise_error Puppet::Error, %r{'webroot_paths' parameter must be specified} } end context 'with dns-rfc2136 plugin' do let(:title) { 'foo.example.com' } let(:params) { { plugin: 'dns-rfc2136', letsencrypt_command: 'letsencrypt' } } let(:pre_condition) do <<-PUPPET class { 'letsencrypt': email => 'foo@example.com', config_dir => '/etc/letsencrypt', } class { 'letsencrypt::plugin::dns_rfc2136': server => '192.0.2.1', key_name => 'certbot', key_secret => 'secret', package_name => 'irrelevant', } PUPPET end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_class('letsencrypt::plugin::dns_rfc2136') } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_command "letsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a dns-rfc2136 --cert-name 'foo.example.com' -d 'foo.example.com' --dns-rfc2136-credentials /etc/letsencrypt/dns-rfc2136.ini --dns-rfc2136-propagation-seconds 10" } end context 'with custom plugin' do let(:title) { 'foo.example.com' } let(:params) { { plugin: 'apache' } } it { is_expected.to compile.with_all_deps } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_command "letsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a apache --cert-name 'foo.example.com' -d 'foo.example.com'" } end context 'with custom plugin and manage_cron' do let(:title) { 'foo.example.com' } let(:params) do { plugin: 'apache', manage_cron: true } end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_command('"/var/lib/puppet/letsencrypt/renew-foo.example.com.sh"').with_ensure('present') } it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a apache --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with hook' do context 'pre' do let(:title) { 'foo.example.com' } let(:params) { { config_dir: '/etc/letsencrypt', pre_hook_commands: ['FooBar'] } } it do is_expected.to compile.with_all_deps is_expected.to contain_letsencrypt__hook('foo.example.com-pre').with_hook_file('/etc/letsencrypt/renewal-hooks-puppet/foo.example.com-pre.sh') end end context 'pre with wildcard domain' do let(:title) { '*.example.com' } let(:params) { { config_dir: '/etc/letsencrypt', pre_hook_commands: ['FooBar'] } } it do is_expected.to compile.with_all_deps is_expected.to contain_letsencrypt__hook('*.example.com-pre').with_hook_file('/etc/letsencrypt/renewal-hooks-puppet/example.com-pre.sh') end end context 'post' do let(:title) { 'foo.example.com' } let(:params) { { config_dir: '/etc/letsencrypt', post_hook_commands: ['FooBar'] } } it do is_expected.to compile.with_all_deps is_expected.to contain_letsencrypt__hook('foo.example.com-post').with_hook_file('/etc/letsencrypt/renewal-hooks-puppet/foo.example.com-post.sh') end end context 'deploy' do let(:title) { 'foo.example.com' } let(:params) { { config_dir: '/etc/letsencrypt', deploy_hook_commands: ['FooBar'] } } it do is_expected.to compile.with_all_deps is_expected.to contain_letsencrypt__hook('foo.example.com-deploy').with_hook_file('/etc/letsencrypt/renewal-hooks-puppet/foo.example.com-deploy.sh') end end end # context 'with hook' context 'with manage_cron and defined cron_hour (integer)' do let(:title) { 'foo.example.com' } let(:params) do { cron_hour: 13, manage_cron: true } end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_hour(13).with_ensure('present') } it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with manage_cron and out of range defined cron_hour (integer)' do let(:title) { 'foo.example.com' } let(:params) do { cron_hour: 24, manage_cron: true } end it { is_expected.not_to compile.with_all_deps } it { is_expected.to raise_error Puppet::Error } end context 'with manage_cron and defined cron_hour (string)' do let(:title) { 'foo.example.com' } let(:params) do { cron_hour: '00', manage_cron: true } end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_hour('00').with_ensure('present') } it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with manage_cron and defined cron_hour (array)' do let(:title) { 'foo.example.com' } let(:params) do { cron_hour: [1, 13], manage_cron: true } end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_hour([1, 13]).with_ensure('present') } it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with manage_cron and defined cron_minute (integer)' do let(:title) { 'foo.example.com' } let(:params) do { cron_minute: 15, manage_cron: true } end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_minute(15).with_ensure('present') } it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with manage_cron and out of range defined cron_hour (integer)' do let(:title) { 'foo.example.com' } let(:params) do { cron_hour: 66, manage_cron: true } end it { is_expected.not_to compile.with_all_deps } it { is_expected.to raise_error Puppet::Error } end context 'with manage_cron and defined cron_minute (string)' do let(:title) { 'foo.example.com' } let(:params) do { cron_minute: '15', manage_cron: true } end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_minute('15').with_ensure('present') } it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with manage_cron and defined cron_minute (array)' do let(:title) { 'foo.example.com' } let(:params) do { cron_minute: [0, 30], manage_cron: true } end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_minute([0, 30]).with_ensure('present') } it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with manage_cron and ensure absent' do let(:title) { 'foo.example.com' } let(:params) do { ensure: 'absent', manage_cron: true } end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_ensure('absent') } it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('absent') } end context 'with custom puppet_vardir path and manage_cron' do let :facts do super().merge(puppet_vardir: '/tmp/custom_vardir') end let(:title) { 'foo.example.com' } let(:params) do { plugin: 'apache', manage_cron: true } end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_file('/tmp/custom_vardir/letsencrypt').with_ensure('directory') } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_command '"/tmp/custom_vardir/letsencrypt/renew-foo.example.com.sh"' } it { is_expected.to contain_file('/tmp/custom_vardir/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a apache --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with custom plugin and manage cron and cron_success_command' do let(:title) { 'foo.example.com' } let(:params) do { plugin: 'apache', manage_cron: true, cron_before_command: 'echo before', cron_success_command: 'echo success' } end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_command '"/var/lib/puppet/letsencrypt/renew-foo.example.com.sh"' } it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\n(echo before) && letsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a apache --cert-name 'foo.example.com' -d 'foo.example.com' && (echo success)\n") } end context 'without plugin' do let(:title) { 'foo.example.com' } let(:params) { { custom_plugin: true } } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_command "letsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 --cert-name 'foo.example.com' -d 'foo.example.com'" } end context 'with invalid plugin' do let(:title) { 'foo.example.com' } let(:params) { { plugin: 'bad' } } it { is_expected.not_to compile.with_all_deps } it { is_expected.to raise_error Puppet::Error } end context 'when specifying additional arguments' do let(:title) { 'foo.example.com' } let(:params) { { additional_args: ['--foo bar', '--baz quux'] } } it { is_expected.to compile.with_all_deps } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_command "letsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com' --foo bar --baz quux" } end describe 'when specifying custom environment variables' do let(:title) { 'foo.example.com' } let(:params) { { environment: ['FOO=bar', 'FIZZ=buzz'] } } it { is_expected.to compile.with_all_deps } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_environment(['VENV_PATH=/opt/letsencrypt/.venv', 'FOO=bar', 'FIZZ=buzz']) } end context 'with custom environment variables and manage_cron' do let(:title) { 'foo.example.com' } let(:params) { { environment: ['FOO=bar', 'FIZZ=buzz'], manage_cron: true } } it { is_expected.to compile.with_all_deps } it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_content "#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nexport FOO=bar\nexport FIZZ=buzz\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com'\n" } end context 'with manage cron and suppress_cron_output' do\ let(:title) { 'foo.example.com' } let(:params) do { manage_cron: true, suppress_cron_output: true } end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_command('"/var/lib/puppet/letsencrypt/renew-foo.example.com.sh"').with_ensure('present') } it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com' > /dev/null 2>&1\n") } end context 'with manage cron and custom day of month' do let(:title) { 'foo.example.com' } let(:params) do { manage_cron: true, cron_monthday: [1, 15] } end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with(monthday: [1, 15]).with_ensure('present') } it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with custom config_dir' do let(:title) { 'foo.example.com' } let(:pre_condition) { "class { letsencrypt: email => 'foo@example.com', config_dir => '/foo/bar/baz', package_command => 'letsencrypt'}" } it { is_expected.to compile.with_all_deps } it { is_expected.to contain_file('/foo/bar/baz').with_ensure('directory') } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_unless '/usr/local/sbin/letsencrypt-domain-validation /foo/bar/baz/live/foo.example.com/cert.pem \'foo.example.com\'' } end context 'on FreeBSD', if: facts[:os]['name'] == 'FreeBSD' do let(:title) { 'foo.example.com' } let(:pre_condition) { "class { letsencrypt: email => 'foo@example.com'}" } it { is_expected.to compile.with_all_deps } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_command %r{^certbot} } it { is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini email foo@example.com') } it { is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini server https://acme-v02.api.letsencrypt.org/directory') } it { is_expected.to contain_file('/usr/local/etc/letsencrypt').with_ensure('directory') } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_unless '/usr/local/sbin/letsencrypt-domain-validation /usr/local/etc/letsencrypt/live/foo.example.com/cert.pem \'foo.example.com\'' } end end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f16fb15..e40ba44 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,44 +1,65 @@ # This file is managed via modulesync # https://github.com/voxpupuli/modulesync # https://github.com/voxpupuli/modulesync_config RSpec.configure do |c| c.mock_with :rspec end require 'puppetlabs_spec_helper/module_spec_helper' require 'rspec-puppet-facts' require 'bundler' include RspecPuppetFacts +if ENV['DEBUG'] + Puppet::Util::Log.level = :debug + Puppet::Util::Log.newdestination(:console) +end + if File.exist?(File.join(__dir__, 'default_module_facts.yml')) facts = YAML.load(File.read(File.join(__dir__, 'default_module_facts.yml'))) if facts facts.each do |name, value| add_custom_fact name.to_sym, value end end end if Dir.exist?(File.expand_path('../../lib', __FILE__)) require 'coveralls' require 'simplecov' require 'simplecov-console' SimpleCov.formatters = [ SimpleCov::Formatter::HTMLFormatter, SimpleCov::Formatter::Console ] SimpleCov.start do track_files 'lib/**/*.rb' add_filter '/spec' add_filter '/vendor' add_filter '/.vendor' add_filter Bundler.configured_bundle_path.path end end RSpec.configure do |c| + # getting the correct facter version is tricky. We use facterdb as a source to mock facts + # see https://github.com/camptocamp/facterdb + # people might provide a specific facter version. In that case we use it. + # Otherwise we need to match the correct facter version to the used puppet version. + # as of 2019-10-31, puppet 5 ships facter 3.11 and puppet 6 ships facter 3.14 + # https://puppet.com/docs/puppet/5.5/about_agent.html + # + # The environment variable `PUPPET_VERSION` is available in our travis environment, but we cannot rely on it + # if somebody runs the tests locally. For that case we should fallback the the puppet gem version + c.default_facter_version = if ENV['FACTERDB_FACTS_VERSION'] + ENV['FACTERDB_FACTS_VERSION'] + else + puppet_version = ENV['PUPPET_VERSION'] ? ENV['PUPPET_VERSION'] : Gem.loaded_specs['puppet'].version.to_s + Gem::Dependency.new('', puppet_version).match?('', '5') ? '3.11.0' : '3.14.0' + end + # Coverage generation c.after(:suite) do RSpec::Puppet::Coverage.report! end end