vagrant-bolt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +124 -0
  5. data/.travis.yml +28 -0
  6. data/.yardopts +1 -0
  7. data/Gemfile +37 -0
  8. data/LICENSE +12 -0
  9. data/Puppetfile +7 -0
  10. data/README.md +431 -0
  11. data/Rakefile +19 -0
  12. data/Vagrantfile +47 -0
  13. data/acceptance/artifacts/.keep +0 -0
  14. data/acceptance/components/bolt_spec.rb +98 -0
  15. data/acceptance/skeletons/advanced/Vagrantfile +26 -0
  16. data/acceptance/skeletons/base/Vagrantfile +11 -0
  17. data/acceptance/skeletons/base/modules/facts/CHANGELOG.md +26 -0
  18. data/acceptance/skeletons/base/modules/facts/CONTRIBUTING.md +279 -0
  19. data/acceptance/skeletons/base/modules/facts/Gemfile +98 -0
  20. data/acceptance/skeletons/base/modules/facts/LICENSE +201 -0
  21. data/acceptance/skeletons/base/modules/facts/README.md +45 -0
  22. data/acceptance/skeletons/base/modules/facts/Rakefile +8 -0
  23. data/acceptance/skeletons/base/modules/facts/checksums.json +42 -0
  24. data/acceptance/skeletons/base/modules/facts/lib/puppet/functions/facts/group_by.rb +14 -0
  25. data/acceptance/skeletons/base/modules/facts/metadata.json +62 -0
  26. data/acceptance/skeletons/base/modules/facts/plans/info.pp +16 -0
  27. data/acceptance/skeletons/base/modules/facts/plans/init.pp +13 -0
  28. data/acceptance/skeletons/base/modules/facts/tasks/bash.json +5 -0
  29. data/acceptance/skeletons/base/modules/facts/tasks/bash.sh +93 -0
  30. data/acceptance/skeletons/base/modules/facts/tasks/init.json +10 -0
  31. data/acceptance/skeletons/base/modules/facts/tasks/powershell.json +4 -0
  32. data/acceptance/skeletons/base/modules/facts/tasks/powershell.ps1 +56 -0
  33. data/acceptance/skeletons/base/modules/facts/tasks/ruby.json +4 -0
  34. data/acceptance/skeletons/base/modules/facts/tasks/ruby.rb +40 -0
  35. data/acceptance/skeletons/provisioner/Vagrantfile +19 -0
  36. data/acceptance/skeletons/trigger/Vagrantfile +22 -0
  37. data/acceptance/vagrant-spec.config.rb +22 -0
  38. data/lib/vagrant-bolt.rb +57 -0
  39. data/lib/vagrant-bolt/command.rb +65 -0
  40. data/lib/vagrant-bolt/config.rb +6 -0
  41. data/lib/vagrant-bolt/config/bolt.rb +135 -0
  42. data/lib/vagrant-bolt/config/global.rb +172 -0
  43. data/lib/vagrant-bolt/config_builder.rb +11 -0
  44. data/lib/vagrant-bolt/config_builder/config.rb +150 -0
  45. data/lib/vagrant-bolt/config_builder/monkey_patches.rb +71 -0
  46. data/lib/vagrant-bolt/config_builder/provisioner.rb +106 -0
  47. data/lib/vagrant-bolt/config_builder/triggers.rb +29 -0
  48. data/lib/vagrant-bolt/plugin.rb +39 -0
  49. data/lib/vagrant-bolt/provisioner.rb +18 -0
  50. data/lib/vagrant-bolt/runner.rb +88 -0
  51. data/lib/vagrant-bolt/util/bolt.rb +139 -0
  52. data/lib/vagrant-bolt/util/config.rb +43 -0
  53. data/lib/vagrant-bolt/util/machine.rb +73 -0
  54. data/lib/vagrant-bolt/version.rb +5 -0
  55. data/spec/spec_helper.rb +12 -0
  56. data/spec/unit/config/bolt_spec.rb +150 -0
  57. data/spec/unit/config/global_spec.rb +95 -0
  58. data/spec/unit/provisioner/bolt_spec.rb +39 -0
  59. data/spec/unit/runner/runner_spec.rb +122 -0
  60. data/spec/unit/util/bolt_spec.rb +148 -0
  61. data/spec/unit/util/config_spec.rb +53 -0
  62. data/spec/unit/vagrant_spec.rb +9 -0
  63. data/tasks/acceptance.rake +45 -0
  64. data/tasks/spec.rake +5 -0
  65. data/templates/locales/en.yml +24 -0
  66. data/vagrant-bolt.gemspec +24 -0
  67. metadata +109 -0
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'rspec/core/rake_task'
6
+ require 'rubocop/rake_task'
7
+
8
+ Dir.chdir(File.expand_path(__dir__))
9
+
10
+ RuboCop::RakeTask.new(:rubocop) do |t|
11
+ t.options = ['--display-cop-names']
12
+ end
13
+
14
+ task_dir = File.expand_path("tasks", __dir__)
15
+ Dir["#{task_dir}/**/*.rake"].each do |task_file|
16
+ load task_file
17
+ end
18
+
19
+ task default: [:rubocop, :spec]
@@ -0,0 +1,47 @@
1
+ require 'vagrant-bolt'
2
+ Vagrant.configure("2") do |config|
3
+ config.vm.box = "alpine/alpine64"
4
+ config.bolt.run_as = 'root'
5
+
6
+ # Using a global bolt trigger for a plan
7
+ # This will fire on all machines after :up
8
+ config.trigger.after :up do |trigger|
9
+ trigger.name = "Bolt \"facts::bash\" after :up"
10
+ trigger.ruby do |env, machine|
11
+ VagrantBolt.plan("facts", env, machine)
12
+ end
13
+ end
14
+
15
+ ## Server
16
+ config.vm.define 'server' do |node|
17
+ # Machine level bolt configs
18
+ node.bolt.run_as = 'vagrant'
19
+ # Trigger bolt using a trigger
20
+ node.trigger.after :provision do |trigger|
21
+ trigger.name = "Bolt \"facts::bash\" after provision"
22
+ trigger.ruby do |env, machine|
23
+ # Sending additional config for the task
24
+ VagrantBolt.task("facts::bash", env, machine, host_key_check: false, verbose: true)
25
+ end
26
+ end
27
+ end
28
+
29
+ ## Server2
30
+ config.vm.define 'server2' do |node|
31
+ # Using the Bolt provisioner instead of a trigger
32
+ node.vm.provision :bolt do |bolt|
33
+ bolt.command = :task
34
+ bolt.name = "service::linux"
35
+ bolt.params = { name: "chronyd", action: "restart" }
36
+ bolt.nodes = 'ALL'
37
+ bolt.run_as = "root"
38
+ end
39
+ # Using a command before the machine is destroyed
40
+ node.trigger.before :destroy do |trigger|
41
+ trigger.name = "Bolt \"hostname\" after up"
42
+ trigger.ruby do |env, machine|
43
+ VagrantBolt.command("hostname", env, machine)
44
+ end
45
+ end
46
+ end
47
+ end
File without changes
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples 'provider/virtualbox' do |provider, options|
4
+ include_context "acceptance"
5
+ let(:extra_env) { options[:env_vars] }
6
+
7
+ before do
8
+ environment.skeleton('base')
9
+ assert_execute('vagrant', 'box', 'add', 'box', options[:box])
10
+ end
11
+
12
+ after do
13
+ execute('vagrant', 'destroy', '-f', log: false)
14
+ end
15
+
16
+ describe 'bolt provisioner' do
17
+ before(:each) do
18
+ environment.skeleton('provisioner')
19
+ @result = assert_execute('vagrant', 'up', "--provider=#{provider}")
20
+ end
21
+
22
+ it 'runs a task, plan, and command' do
23
+ expect(@result.exit_code).to eq(0)
24
+ expect(@result.stdout).to match(%r{Bolt: Running bolt command locally: \/[^\ ]+bolt task run 'facts'})
25
+ expect(@result.stdout).to match(%r{Bolt: Running bolt command locally: \/[^\ ]+bolt plan run 'facts'})
26
+ expect(@result.stdout).to match(%r{Bolt: Running bolt command locally: \/[^\ ]+bolt command run})
27
+ expect(@result.stdout.scan(%r{Successful on 1 node}).size).to eq(3)
28
+ end
29
+ end
30
+
31
+ describe 'bolt trigger' do
32
+ before(:each) do
33
+ environment.skeleton('trigger')
34
+ @result = assert_execute('vagrant', 'up', "--provider=#{provider}")
35
+ end
36
+
37
+ it 'runs a task, plan, and command' do
38
+ expect(@result.exit_code).to eq(0)
39
+ expect(@result.stdout).to match(%r{Bolt: Running bolt command locally: \/[^\ ]+bolt task run 'facts'})
40
+ expect(@result.stdout).to match(%r{Bolt: Running bolt command locally: \/[^\ ]+bolt plan run 'facts'})
41
+ expect(@result.stdout).to match(%r{Bolt: Running bolt command locally: \/[^\ ]+bolt command run})
42
+ expect(@result.stdout.scan(%r{Successful on 1 node}).size).to eq(3)
43
+ end
44
+ end
45
+
46
+ describe 'bolt command' do
47
+ before(:each) do
48
+ @result = assert_execute('vagrant', 'up', "--provider=#{provider}")
49
+ end
50
+
51
+ it 'runs a task, plan, and command' do
52
+ expect(@result.exit_code).to eq(0)
53
+ result = assert_execute('vagrant', 'bolt', 'task', 'run', 'facts', '-n', 'server')
54
+ expect(result.exit_code).to eq(0)
55
+ expect(result.stdout).to match(%r{Bolt: Running bolt command locally: '\/[^\ ]+bolt' 'task' 'run' 'facts'})
56
+ expect(result.stdout.scan(%r{Successful on 1 node}).size).to eq(1)
57
+ result = assert_execute('vagrant', 'bolt', 'plan', 'run', 'facts', '-n', 'server')
58
+ expect(result.exit_code).to eq(0)
59
+ expect(result.stdout).to match(%r{Bolt: Running bolt command locally: '\/[^\ ]+bolt' 'plan' 'run' 'facts'})
60
+ expect(result.stdout.scan(%r{Successful on 1 node}).size).to eq(1)
61
+ result = assert_execute('vagrant', 'bolt', 'command', 'run', 'hostname', '-n', 'server')
62
+ expect(result.exit_code).to eq(0)
63
+ expect(result.stdout).to match(%r{Bolt: Running bolt command locally: '\/[^\ ]+bolt' 'command' 'run'})
64
+ expect(result.stdout.scan(%r{Successful on 1 node}).size).to eq(1)
65
+ end
66
+ end
67
+
68
+ describe 'bolt advanced use cases' do
69
+ before(:each) do
70
+ environment.skeleton('advanced')
71
+ @result = assert_execute('vagrant', 'up', "--provider=#{provider}")
72
+ end
73
+
74
+ # This is a mashup of many tests combined. In an effort to cut down the time, this tests many items.
75
+ it 'runs bolt' do
76
+ # Ensure the machines came online
77
+ expect(@result.exit_code).to eq(0)
78
+ ## Allnodetest
79
+ # Check for root level triggers
80
+ result = assert_execute('vagrant', 'provision')
81
+ expect(result.exit_code).to eq(0)
82
+ # Ensure that the trigger is run on both nodes
83
+ expect(result.stdout.scan(%r{server[12]:\s+allnodetest}).size).to eq(4)
84
+ # Ensure that 'nodes = all' includes both nodes
85
+ expect(result.stdout).to match(%r{Bolt: Running bolt command locally: \/[^\ ]+bolt command run[^\n]+allnodetest[^\n]+server[12],server[12]})
86
+ # Ensure that the root level `run_as` is used
87
+ expect(result.stdout).to match(%r{Bolt: Running bolt command locally: \/[^\ ]+bolt command run[^\n]+allnodetest[^\n]+--run-as 'root'})
88
+ ## Configtest
89
+ # Ensure excludes overrides nodes
90
+ expect(result.stdout).to match(%r{Bolt: Running bolt command locally: \/[^\ ]+bolt command run[^\n]+configtest[^\n]+server2})
91
+ # Ensure verbose and debug flags are correctly handled
92
+ expect(result.stdout).to match(%r{Bolt: Running bolt command locally: \/[^\ ]+bolt command run[^\n]+configtest[^\n]+--verbose})
93
+ expect(result.stdout).not_to match(%r{Bolt: Running bolt command locally: \/[^\ ]+bolt command run[^\n]+configtest[^\n]+--debug})
94
+ # Ensure run_as override
95
+ expect(result.stdout).to match(%r{Bolt: Running bolt command locally: \/[^\ ]+bolt command run[^\n]+configtest[^\n]+--run-as 'vagrant'})
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,26 @@
1
+ require 'vagrant-spec/which'
2
+ Vagrant.configure('2') do |config|
3
+ config.bolt.bolt_exe = Vagrant::Spec::Which.which('bolt')
4
+ config.bolt.run_as = 'root'
5
+ config.vm.box = 'box'
6
+ # Run a trigger on all nodes after provision
7
+ config.trigger.after :provision do |trigger|
8
+ trigger.ruby do |env, machine|
9
+ VagrantBolt.command('/bin/echo "allnodetest"', env, machine, nodes: 'all')
10
+ end
11
+ end
12
+ config.vm.define 'server1' do |node|
13
+ # Provision a node testing the config options
14
+ node.vm.provision :bolt do |bolt|
15
+ bolt.command = :command
16
+ bolt.name = '/bin/echo "configtest"'
17
+ bolt.nodes = ['server1', 'server2']
18
+ bolt.excludes = ['server1']
19
+ bolt.verbose = true
20
+ bolt.debug = false
21
+ bolt.run_as = "vagrant"
22
+ end
23
+ end
24
+ config.vm.define 'server2' do |node|
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ require 'vagrant-spec/which'
2
+ Vagrant.configure('2') do |config|
3
+ config.bolt.bolt_exe = Vagrant::Spec::Which.which('bolt')
4
+ config.vm.box = 'box'
5
+ config.vm.define 'server' do |node|
6
+ node.vm.provision :bolt do |bolt|
7
+ bolt.command = :task
8
+ bolt.name = "facts"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ # Change Log
2
+
3
+ ## 0.3.1
4
+ ### Fixed
5
+ - Allow setting Puppet gem version via `PUPPET_GEM_VERSION` so we can use Puppet 5 to ship the module.
6
+
7
+ ## 0.3.0
8
+ ### Fixed
9
+ - Task metadata specifies environment input to work around BOLT-691.
10
+
11
+ ### Changed
12
+ - Stop hiding failures gathering facts in the `facts` plan.
13
+
14
+ ### Removed
15
+ - `facts::retrieve` as redundant with the `facts` task when cross-platform
16
+ tasks are supported.
17
+
18
+ ## 0.2.0
19
+ ### Added
20
+ - Legacy facts added to results.
21
+ - Improve ability of bash and ruby task to find facter executable path.
22
+
23
+ ## 0.1.2
24
+
25
+ ### Changed
26
+ - Move facts to external module (from bolt).
@@ -0,0 +1,279 @@
1
+ # Contributing to Puppet modules
2
+
3
+ So you want to contribute to a Puppet module: Great! Below are some instructions to get you started doing
4
+ that very thing while setting expectations around code quality as well as a few tips for making the
5
+ process as easy as possible.
6
+
7
+ ### Table of Contents
8
+
9
+ 1. [Getting Started](#getting-started)
10
+ 1. [Commit Checklist](#commit-checklist)
11
+ 1. [Submission](#submission)
12
+ 1. [More about commits](#more-about-commits)
13
+ 1. [Testing](#testing)
14
+ - [Running Tests](#running-tests)
15
+ - [Writing Tests](#writing-tests)
16
+ 1. [Get Help](#get-help)
17
+
18
+ ## Getting Started
19
+
20
+ - Fork the module repository on GitHub and clone to your workspace
21
+
22
+ - Make your changes!
23
+
24
+ ## Commit Checklist
25
+
26
+ ### The Basics
27
+
28
+ - [x] my commit is a single logical unit of work
29
+
30
+ - [x] I have checked for unnecessary whitespace with "git diff --check"
31
+
32
+ - [x] my commit does not include commented out code or unneeded files
33
+
34
+ ### The Content
35
+
36
+ - [x] my commit includes tests for the bug I fixed or feature I added
37
+
38
+ - [x] my commit includes appropriate documentation changes if it is introducing a new feature or changing existing functionality
39
+
40
+ - [x] my code passes existing test suites
41
+
42
+ ### The Commit Message
43
+
44
+ - [x] the first line of my commit message includes:
45
+
46
+ - [x] an issue number (if applicable), e.g. "(MODULES-xxxx) This is the first line"
47
+
48
+ - [x] a short description (50 characters is the soft limit, excluding ticket number(s))
49
+
50
+ - [x] the body of my commit message:
51
+
52
+ - [x] is meaningful
53
+
54
+ - [x] uses the imperative, present tense: "change", not "changed" or "changes"
55
+
56
+ - [x] includes motivation for the change, and contrasts its implementation with the previous behavior
57
+
58
+ ## Submission
59
+
60
+ ### Pre-requisites
61
+
62
+ - Make sure you have a [GitHub account](https://github.com/join)
63
+
64
+ - [Create a ticket](https://tickets.puppet.com/secure/CreateIssue!default.jspa), or [watch the ticket](https://tickets.puppet.com/browse/) you are patching for.
65
+
66
+ ### Push and PR
67
+
68
+ - Push your changes to your fork
69
+
70
+ - [Open a Pull Request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) against the repository in the puppetlabs organization
71
+
72
+ ## More about commits
73
+
74
+ 1. Make separate commits for logically separate changes.
75
+
76
+ Please break your commits down into logically consistent units
77
+ which include new or changed tests relevant to the rest of the
78
+ change. The goal of doing this is to make the diff easier to
79
+ read for whoever is reviewing your code. In general, the easier
80
+ your diff is to read, the more likely someone will be happy to
81
+ review it and get it into the code base.
82
+
83
+ If you are going to refactor a piece of code, please do so as a
84
+ separate commit from your feature or bug fix changes.
85
+
86
+ We also really appreciate changes that include tests to make
87
+ sure the bug is not re-introduced, and that the feature is not
88
+ accidentally broken.
89
+
90
+ Describe the technical detail of the change(s). If your
91
+ description starts to get too long, that is a good sign that you
92
+ probably need to split up your commit into more finely grained
93
+ pieces.
94
+
95
+ Commits which plainly describe the things which help
96
+ reviewers check the patch and future developers understand the
97
+ code are much more likely to be merged in with a minimum of
98
+ bike-shedding or requested changes. Ideally, the commit message
99
+ would include information, and be in a form suitable for
100
+ inclusion in the release notes for the version of Puppet that
101
+ includes them.
102
+
103
+ Please also check that you are not introducing any trailing
104
+ whitespace or other "whitespace errors". You can do this by
105
+ running "git diff --check" on your changes before you commit.
106
+
107
+ 2. Sending your patches
108
+
109
+ To submit your changes via a GitHub pull request, we _highly_
110
+ recommend that you have them on a topic branch, instead of
111
+ directly on "master".
112
+ It makes things much easier to keep track of, especially if
113
+ you decide to work on another thing before your first change
114
+ is merged in.
115
+
116
+ GitHub has some pretty good
117
+ [general documentation](http://help.github.com/) on using
118
+ their site. They also have documentation on
119
+ [creating pull requests](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).
120
+
121
+ In general, after pushing your topic branch up to your
122
+ repository on GitHub, you can switch to the branch in the
123
+ GitHub UI and click "Pull Request" towards the top of the page
124
+ in order to open a pull request.
125
+
126
+ 3. Update the related JIRA issue.
127
+
128
+ If there is a JIRA issue associated with the change you
129
+ submitted, then you should update the ticket to include the
130
+ location of your branch, along with any other commentary you
131
+ may wish to make.
132
+
133
+ # Testing
134
+
135
+ ## Getting Started
136
+
137
+ Our Puppet modules provide [`Gemfile`](./Gemfile)s, which can tell a Ruby package manager such as [bundler](http://bundler.io/) what Ruby packages,
138
+ or Gems, are required to build, develop, and test this software.
139
+
140
+ Please make sure you have [bundler installed](http://bundler.io/#getting-started) on your system, and then use it to
141
+ install all dependencies needed for this project in the project root by running
142
+
143
+ ```shell
144
+ % bundle install --path .bundle/gems
145
+ Fetching gem metadata from https://rubygems.org/........
146
+ Fetching gem metadata from https://rubygems.org/..
147
+ Using rake (10.1.0)
148
+ Using builder (3.2.2)
149
+ -- 8><-- many more --><8 --
150
+ Using rspec-system-puppet (2.2.0)
151
+ Using serverspec (0.6.3)
152
+ Using rspec-system-serverspec (1.0.0)
153
+ Using bundler (1.3.5)
154
+ Your bundle is complete!
155
+ Use `bundle show [gemname]` to see where a bundled gem is installed.
156
+ ```
157
+
158
+ NOTE: some systems may require you to run this command with sudo.
159
+
160
+ If you already have those gems installed, make sure they are up-to-date:
161
+
162
+ ```shell
163
+ % bundle update
164
+ ```
165
+
166
+ ## Running Tests
167
+
168
+ With all dependencies in place and up-to-date, run the tests:
169
+
170
+ ### Unit Tests
171
+
172
+ ```shell
173
+ % bundle exec rake spec
174
+ ```
175
+
176
+ This executes all the [rspec tests](http://rspec-puppet.com/) in the directories defined [here](https://github.com/puppetlabs/puppetlabs_spec_helper/blob/699d9fbca1d2489bff1736bb254bb7b7edb32c74/lib/puppetlabs_spec_helper/rake_tasks.rb#L17) and so on.
177
+ rspec tests may have the same kind of dependencies as the module they are testing. Although the module defines these dependencies in its [metadata.json](./metadata.json),
178
+ rspec tests define them in [.fixtures.yml](./fixtures.yml).
179
+
180
+ ### Acceptance Tests
181
+
182
+ Some Puppet modules also come with acceptance tests, which use [beaker][]. These tests spin up a virtual machine under
183
+ [VirtualBox](https://www.virtualbox.org/), controlled with [Vagrant](http://www.vagrantup.com/), to simulate scripted test
184
+ scenarios. In order to run these, you need both Virtualbox and Vagrant installed on your system.
185
+
186
+ Run the tests by issuing the following command
187
+
188
+ ```shell
189
+ % bundle exec rake spec_clean
190
+ % bundle exec rspec spec/acceptance
191
+ ```
192
+
193
+ This will now download a pre-fabricated image configured in the [default node-set](./spec/acceptance/nodesets/default.yml),
194
+ install Puppet, copy this module, and install its dependencies per [spec/spec_helper_acceptance.rb](./spec/spec_helper_acceptance.rb)
195
+ and then run all the tests under [spec/acceptance](./spec/acceptance).
196
+
197
+ A specific node set can be selected by setting the `BEAKER_set` environment variable
198
+
199
+ ```shell
200
+ % export BEAKER_set=spec/acceptance/nodesets/centos-7-x64
201
+ ```
202
+
203
+ If using a VM pooler node set, a password must be set via `BEAKER_password`.
204
+
205
+ ## Writing Tests
206
+
207
+ ### Unit Tests
208
+
209
+ When writing unit tests for Puppet, [rspec-puppet][] is your best friend. It provides tons of helper methods for testing your manifests against a
210
+ catalog (e.g. contain_file, contain_package, with_params, etc). It would be ridiculous to try and top rspec-puppet's [documentation][rspec-puppet_docs]
211
+ but here's a tiny sample:
212
+
213
+ Sample manifest:
214
+
215
+ ```puppet
216
+ file { "a test file":
217
+ ensure => present,
218
+ path => "/etc/sample",
219
+ }
220
+ ```
221
+
222
+ Sample test:
223
+
224
+ ```ruby
225
+ it 'does a thing' do
226
+ expect(subject).to contain_file("a test file").with({:path => "/etc/sample"})
227
+ end
228
+ ```
229
+
230
+ ### Acceptance Tests
231
+
232
+ Writing acceptance tests for Puppet involves [beaker][] and its cousin [beaker-rspec][]. A common pattern for acceptance tests is to create a test manifest, apply it
233
+ twice to check for idempotency or errors, then run expectations.
234
+
235
+ ```ruby
236
+ it 'does an end-to-end thing' do
237
+ pp = <<-EOF
238
+ file { 'a test file':
239
+ ensure => present,
240
+ path => "/etc/sample",
241
+ content => "test string",
242
+ }
243
+
244
+ apply_manifest(pp, :catch_failures => true)
245
+ apply_manifest(pp, :catch_changes => true)
246
+
247
+ end
248
+
249
+ describe file("/etc/sample") do
250
+ it { is_expected.to contain "test string" }
251
+ end
252
+
253
+ ```
254
+
255
+ # If you have commit access to the repository
256
+
257
+ Even if you have commit access to the repository, you still need to go through the process above, and have someone else review and merge
258
+ in your changes. The rule is that **all changes must be reviewed by a project developer that did not write the code to ensure that
259
+ all changes go through a code review process.**
260
+
261
+ The record of someone performing the merge is the record that they performed the code review. Again, this should be someone other than the author of the topic branch.
262
+
263
+ # Get Help
264
+
265
+ ### On the web
266
+ * [Puppet help messageboard](http://puppet.com/community/get-help)
267
+ * [Writing tests](https://docs.puppet.com/guides/module_guides/bgtm.html#step-three-module-testing)
268
+ * [General GitHub documentation](http://help.github.com/)
269
+ * [GitHub pull request documentation](http://help.github.com/send-pull-requests/)
270
+
271
+ ### On chat
272
+ * Slack (slack.puppet.com) #forge-modules, #puppet-dev, #windows, #voxpupuli
273
+ * IRC (freenode) #puppet-dev, #voxpupuli
274
+
275
+
276
+ [rspec-puppet]: http://rspec-puppet.com/
277
+ [rspec-puppet_docs]: http://rspec-puppet.com/documentation/
278
+ [beaker]: https://github.com/puppetlabs/beaker
279
+ [beaker-rspec]: https://github.com/puppetlabs/beaker-rspec