producer-core 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.travis.yml +5 -1
- data/Guardfile +2 -0
- data/README.md +386 -0
- data/Rakefile +8 -5
- data/features/cli/debug.feature +9 -7
- data/features/cli/error_reporting.feature +18 -6
- data/features/cli/usage.feature +1 -0
- data/features/steps/output_steps.rb +8 -0
- data/features/steps/recipe_steps.rb +18 -0
- data/features/support/env.rb +17 -4
- data/lib/producer/core/error_formatter.rb +5 -4
- data/lib/producer/core/version.rb +1 -1
- data/producer-core.gemspec +1 -1
- data/spec/producer/core/error_formatter_spec.rb +40 -13
- metadata +8 -29
- data/features/support/env_aruba_timeout.rb +0 -3
- data/features/support/env_cucumber_doc_string.rb +0 -23
- data/features/support/env_fake_home.rb +0 -3
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7369766247b31d978939ca38cea6e1ffda8e7e72
|
4
|
+
data.tar.gz: f0440319fe4a6c3e3dcf0352ac01a1dd39ed6a9f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3cf37a2d16b4e6bb4d42d0204ffc3f3a52016fc52358a625bc0eb86b13209241f75a6f171d29044414ff48dba4f339f6fff454d52b5d9ace33a4027f29d55117
|
7
|
+
data.tar.gz: 267659f33b453c84df3c0f9188ecb7f82ec08162bcc119afdf1b8da3776cc57d1b8014c846524b41202cb3ecbf3785ed66493e03f86987dc0cc46fd4845dd745
|
data/.travis.yml
CHANGED
data/Guardfile
CHANGED
data/README.md
ADDED
@@ -0,0 +1,386 @@
|
|
1
|
+
producer
|
2
|
+
========
|
3
|
+
|
4
|
+
Software provisioning and configuration management tool, providing a
|
5
|
+
DSL to write "recipes".
|
6
|
+
|
7
|
+
[![Version ][badge-version-img]][badge-version-uri]
|
8
|
+
[![Build status ][badge-build-img]][badge-build-uri]
|
9
|
+
[![Code Climate ][badge-cclimate-img]][badge-cclimate-uri]
|
10
|
+
|
11
|
+
|
12
|
+
Getting started
|
13
|
+
---------------
|
14
|
+
|
15
|
+
### Installation (requires ruby ~> 2.1 and rubygems)
|
16
|
+
|
17
|
+
$ gem install producer-core
|
18
|
+
|
19
|
+
|
20
|
+
### Simple recipe
|
21
|
+
|
22
|
+
Recipes are composed by tasks and a task includes actions. Here we
|
23
|
+
use the `echo` action, which output the given string to standard
|
24
|
+
output. All the power of the Ruby language is available.
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
hello_message = 'hello world!'
|
28
|
+
|
29
|
+
task :hello_world do
|
30
|
+
echo hello_message
|
31
|
+
echo hello_message.upcase
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
$ producer simple_recipe.rb
|
36
|
+
hello world!
|
37
|
+
HELLO WORLD!
|
38
|
+
|
39
|
+
|
40
|
+
### Shell command execution on remote host
|
41
|
+
|
42
|
+
The `sh` action will execute a shell command given as a string on
|
43
|
+
the targeted remote host. The remote host can be specified with the
|
44
|
+
CLI option `-t`.
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
task :show_zsh_pkg do
|
48
|
+
sh 'pkg info | grep zsh'
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
$ producer -t localhost show_zsh_pkg.rb
|
53
|
+
zsh-5.0.7 The Z shell
|
54
|
+
|
55
|
+
When execution fails, recipe processing is stopped and the action
|
56
|
+
which triggered the failed execution is the last one to be applied.
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
task :sh_fail do
|
60
|
+
sh 'false'
|
61
|
+
echo 'end of recipe'
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
$ producer -t localhost sh_fail.rb
|
66
|
+
RemoteCommandExecutionError: false
|
67
|
+
$
|
68
|
+
|
69
|
+
Only the first action is applied.
|
70
|
+
|
71
|
+
|
72
|
+
### Task conditions
|
73
|
+
|
74
|
+
A task can be bound to a condition: when the condition fails actions
|
75
|
+
are skipped, otherwise actions are applied as usual.
|
76
|
+
|
77
|
+
This condition can be a simple ruby expression :
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
task :condition_pass do
|
81
|
+
condition { true }
|
82
|
+
echo 'will output'
|
83
|
+
end
|
84
|
+
|
85
|
+
task :condition_fail do
|
86
|
+
condition { false }
|
87
|
+
echo 'will NOT output'
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
#### Built-in tests
|
92
|
+
|
93
|
+
Specific test keywords are also available in the condition block
|
94
|
+
context, `producer-core` ships with a few common tests,
|
95
|
+
`producer-stdlib` provides more, and custom tests can be defined.
|
96
|
+
|
97
|
+
Here we use the `sh` condition keyword which will pass when the
|
98
|
+
execution of the given shell command succeed, and fail when the
|
99
|
+
execution fails.
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
task :condition_sh_pass do
|
103
|
+
condition { sh 'true' }
|
104
|
+
echo 'will output'
|
105
|
+
end
|
106
|
+
|
107
|
+
task :condition_sh_fail do
|
108
|
+
condition { sh 'false' }
|
109
|
+
cho 'will NOT output'
|
110
|
+
end
|
111
|
+
```
|
112
|
+
|
113
|
+
|
114
|
+
### Nested tasks
|
115
|
+
|
116
|
+
Complex tasks can be split into nested subtasks. Conditions have
|
117
|
+
the same effect on tasks they have on actions, when the condition
|
118
|
+
fails, subtasks of the current task are skipped.
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
task :main_task do
|
122
|
+
condition { true }
|
123
|
+
task(:foo_subtask) { echo 'do foo' }
|
124
|
+
task(:bar_subtask) { echo 'do bar' }
|
125
|
+
task(:baz_subtask) do
|
126
|
+
condition { false }
|
127
|
+
task(:baz_subtask_subtask) { echo 'do baz' }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
```
|
131
|
+
$ producer nested_tasks.rb
|
132
|
+
do foo
|
133
|
+
do bar
|
134
|
+
|
135
|
+
|
136
|
+
Usage
|
137
|
+
-----
|
138
|
+
|
139
|
+
Usage: producer [options] [recipes]
|
140
|
+
|
141
|
+
options:
|
142
|
+
-v, --verbose enable verbose mode
|
143
|
+
-d, --debug enable debug mode
|
144
|
+
-n, --dry-run enable dry run mode
|
145
|
+
-t, --target HOST target host
|
146
|
+
|
147
|
+
|
148
|
+
Actions
|
149
|
+
-------
|
150
|
+
|
151
|
+
See:
|
152
|
+
https://github.com/tjouan/producer-core/tree/master/features/actions
|
153
|
+
|
154
|
+
|
155
|
+
Tests
|
156
|
+
-----
|
157
|
+
|
158
|
+
See:
|
159
|
+
https://github.com/tjouan/producer-core/tree/master/features/tests
|
160
|
+
|
161
|
+
|
162
|
+
Templates
|
163
|
+
---------
|
164
|
+
|
165
|
+
The following example can setup jails on a FreeBSD host.
|
166
|
+
|
167
|
+
In `templates/freebsd/jail.conf.erb`:
|
168
|
+
|
169
|
+
```erb
|
170
|
+
exec.start = "/bin/sh /etc/rc";
|
171
|
+
exec.stop = "/bin/sh /etc/rc.shutdown";
|
172
|
+
exec.clean;
|
173
|
+
mount.devfs;
|
174
|
+
allow.chflags;
|
175
|
+
|
176
|
+
path = "/var/jails/$name";
|
177
|
+
|
178
|
+
<% @jails.each do |jail| -%>
|
179
|
+
<%= jail[:name] %> {
|
180
|
+
interface "<%= @if %>";
|
181
|
+
ip4.addr = <%= jail[:addr4] %>;
|
182
|
+
}
|
183
|
+
<% end -%>
|
184
|
+
```
|
185
|
+
|
186
|
+
Simple usage:
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
INTERFACE = 're0'.freeze
|
190
|
+
JAILS = [{
|
191
|
+
name: 'freebsd-10r1',
|
192
|
+
src: true,
|
193
|
+
addr4: '10.0.0.1'
|
194
|
+
}].freeze
|
195
|
+
|
196
|
+
task :jails_conf do
|
197
|
+
conf = template 'freebsd/jail.conf', if: INTERFACE, jails: JAILS
|
198
|
+
file_write_once '/etc/jail.conf', conf
|
199
|
+
end
|
200
|
+
```
|
201
|
+
|
202
|
+
|
203
|
+
Macros
|
204
|
+
------
|
205
|
+
|
206
|
+
FIXME
|
207
|
+
|
208
|
+
|
209
|
+
Test macros
|
210
|
+
-----------
|
211
|
+
|
212
|
+
FIXME
|
213
|
+
|
214
|
+
|
215
|
+
Macro composition
|
216
|
+
-----------------
|
217
|
+
|
218
|
+
FIXME
|
219
|
+
|
220
|
+
|
221
|
+
Background
|
222
|
+
----------
|
223
|
+
|
224
|
+
producer started as a collection of heterogeneous scripts (Ruby,
|
225
|
+
POSIX shell, Perl…) in the late '90s. I wanted to experiment with the
|
226
|
+
design and usage of Domain Specific Languages in Ruby, and refactor
|
227
|
+
all my scripts as "recipes" in a common language.
|
228
|
+
|
229
|
+
|
230
|
+
Sample recipe
|
231
|
+
-------------
|
232
|
+
|
233
|
+
Based on the previous template example (FreeBSD jails.conf
|
234
|
+
template):
|
235
|
+
|
236
|
+
```ruby
|
237
|
+
require 'producer/stdlib'
|
238
|
+
|
239
|
+
JAILS_ROOT = '/var/jails'.freeze
|
240
|
+
ZROOT = 'tank/jails'.freeze
|
241
|
+
INTERFACE = 're0'.freeze
|
242
|
+
SETS = {
|
243
|
+
base: '2b028a894d25711ad496762622a52d74b1e32ee04693ad1cf056e3ddcdc23975',
|
244
|
+
src: 'f919287a5ef51d4f133f27c99c54f2e8054f408d3dd53bc60f4e233cc75ec03d'
|
245
|
+
}.freeze
|
246
|
+
JAILS = [
|
247
|
+
{
|
248
|
+
name: 'freebsd-10r1',
|
249
|
+
src: true,
|
250
|
+
addr4: '10.0.0.1'
|
251
|
+
},
|
252
|
+
{
|
253
|
+
name: 'freebsd-10r1-gcc',
|
254
|
+
src: true,
|
255
|
+
addr4: '10.0.0.2'
|
256
|
+
}
|
257
|
+
].freeze
|
258
|
+
|
259
|
+
task :freebsd_archives_fetch do
|
260
|
+
SETS.keys.each { |set| condition { no_file? "/tmp/#{set}.txz"} }
|
261
|
+
|
262
|
+
SETS.each do |set, sum|
|
263
|
+
sh <<-eoh
|
264
|
+
cd /tmp && \
|
265
|
+
fetch ftp://ftp.freebsd.org:/pub/FreeBSD/releases/amd64/10.1-RELEASE/#{set}.txz && \
|
266
|
+
sha256 -c #{sum} #{set}.txz
|
267
|
+
eoh
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
task :jails_fs_create do
|
272
|
+
condition { no_sh "zfs list #{ZROOT}" }
|
273
|
+
sh "zfs create -o mountpoint=#{JAILS_ROOT} -o compress=lz4 #{ZROOT}"
|
274
|
+
end
|
275
|
+
|
276
|
+
JAILS.each do |jail|
|
277
|
+
root = "#{JAILS_ROOT}/#{jail[:name]}"
|
278
|
+
fs = "#{ZROOT}/#{jail[:name]}"
|
279
|
+
|
280
|
+
task :jail_initialize do
|
281
|
+
condition { no_sh "zfs list #{fs}@install" }
|
282
|
+
|
283
|
+
task :jail_fs_create do
|
284
|
+
condition { no_sh "zfs list #{fs}" }
|
285
|
+
|
286
|
+
sh "zfs create #{fs}"
|
287
|
+
|
288
|
+
SETS.keys.each do |set|
|
289
|
+
next if set == 'src' && !jail[:src]
|
290
|
+
sh "tar -JxC #{root}/ -f /tmp/#{set}.txz"
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
task :rc_conf do
|
295
|
+
file_write_once "#{root}/etc/rc.conf", <<-eoh
|
296
|
+
hostname=#{jail[:name]}
|
297
|
+
# ...
|
298
|
+
eoh
|
299
|
+
end
|
300
|
+
|
301
|
+
task :root_passwd do
|
302
|
+
sh "chroot #{root} pw user mod root -w random"
|
303
|
+
end
|
304
|
+
|
305
|
+
task :mail_aliases do
|
306
|
+
condition { no_file? "#{root}/etc/mail/aliases.db" }
|
307
|
+
|
308
|
+
sh "chroot #{root} make -C /etc/mail aliases"
|
309
|
+
end
|
310
|
+
|
311
|
+
freebsd_update_patch_interactive "#{root}/usr/sbin/freebsd-update"
|
312
|
+
|
313
|
+
task :jail_snapshot_install do
|
314
|
+
sh "zfs snapshot #{fs}@install"
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
task :jail_update do
|
319
|
+
condition { no_sh "zfs list #{fs}@update" }
|
320
|
+
|
321
|
+
sh "chroot #{root} freebsd-update fetch install"
|
322
|
+
sh "zfs snapshot #{fs}@update"
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
task :jails_conf do
|
327
|
+
conf = template 'freebsd/jail.conf', if: INTERFACE, jails: JAILS
|
328
|
+
file_write_once '/etc/jail.conf', conf
|
329
|
+
end
|
330
|
+
```
|
331
|
+
|
332
|
+
|
333
|
+
Similar or related code and tools
|
334
|
+
---------------------------------
|
335
|
+
|
336
|
+
### Ruby DSL
|
337
|
+
|
338
|
+
* https://github.com/sprinkle-tool/sprinkle
|
339
|
+
* http://www.capistranorb.com/
|
340
|
+
* http://babushka.me/ (with BDD features, no network support?)
|
341
|
+
|
342
|
+
### Ruby DSL, shell script transpilation
|
343
|
+
|
344
|
+
* http://nadarei.co/mina/ (Rake based DSL, requires and uses bash)
|
345
|
+
|
346
|
+
### Ruby-like DSL
|
347
|
+
|
348
|
+
* http://puppetlabs.com/ (Ruby supported on >= 2.6.x)
|
349
|
+
|
350
|
+
### Agents, daemons
|
351
|
+
|
352
|
+
* https://github.com/saltstack/salt (Python, YAML)
|
353
|
+
* http://www.cobblerd.org/ (Python, many features)
|
354
|
+
* https://www.getchef.com/chef/
|
355
|
+
|
356
|
+
### SSH
|
357
|
+
|
358
|
+
* https://github.com/ansible/ansible (Python, YAML)
|
359
|
+
* http://docs.fabfile.org/ (Python)
|
360
|
+
* https://github.com/sebastien/cuisine (Python DSL, uses Fabric)
|
361
|
+
* https://github.com/kenn/sunzi (Ruby, provisioning, shell based)
|
362
|
+
* http://solutious.com/projects/rudy/ (Ruby, provisioning)
|
363
|
+
|
364
|
+
### Ruby SSH related code
|
365
|
+
|
366
|
+
* https://github.com/leehambley/sshkit
|
367
|
+
* https://github.com/gammons/screwcap
|
368
|
+
* https://github.com/delano/rye/
|
369
|
+
* https://github.com/jheiss/sshwrap
|
370
|
+
|
371
|
+
### BDD
|
372
|
+
|
373
|
+
* https://github.com/hedgehog/cuken (Cucumber)
|
374
|
+
* http://serverspec.org/ (RSpec, Net::SSH)
|
375
|
+
* https://github.com/auxesis/cucumber-nagios (Cucumber, Net::SSH,
|
376
|
+
Webrat)
|
377
|
+
* http://larsyencken.github.io/marelle/ (Prolog, babushka inspired)
|
378
|
+
|
379
|
+
|
380
|
+
|
381
|
+
[badge-version-img]: https://img.shields.io/gem/v/producer-core.svg
|
382
|
+
[badge-version-uri]: https://rubygems.org/gems/producer-core
|
383
|
+
[badge-build-img]: https://img.shields.io/travis/tjouan/producer-core/master.svg
|
384
|
+
[badge-build-uri]: https://travis-ci.org/tjouan/producer-core
|
385
|
+
[badge-cclimate-img]: https://img.shields.io/codeclimate/github/tjouan/producer-core.svg
|
386
|
+
[badge-cclimate-uri]: https://codeclimate.com/github/tjouan/producer-core
|
data/Rakefile
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
require 'cucumber/rake/task'
|
2
2
|
require 'rspec/core/rake_task'
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
task default: %i[features spec]
|
5
|
+
|
6
|
+
Cucumber::Rake::Task.new(:features)
|
7
|
+
|
8
|
+
Cucumber::Rake::Task.new(:features_no_sshd) do |t|
|
9
|
+
t.instance_eval { @desc << ' excluding @sshd'}
|
6
10
|
t.cucumber_opts = '--tags ~@sshd'
|
7
11
|
end
|
8
12
|
|
9
|
-
desc 'Run all specs'
|
10
13
|
RSpec::Core::RakeTask.new(:spec)
|
11
14
|
|
12
|
-
|
13
|
-
task
|
15
|
+
desc 'Run CI test suite'
|
16
|
+
task ci: %i[features_no_sshd spec]
|
data/features/cli/debug.feature
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
Feature: CLI debug option
|
2
2
|
|
3
|
-
|
4
|
-
Given a recipe with
|
5
|
-
"""
|
6
|
-
task(:trigger_error) { fail 'some error' }
|
7
|
-
"""
|
8
|
-
|
9
|
-
Scenario: reports recipe errors
|
3
|
+
Scenario: reports recipe errors with their cause
|
4
|
+
Given a recipe with an error
|
10
5
|
When I execute the recipe with option -d
|
11
6
|
Then the output must match /\ARuntimeError:.*\n\ncause:\nRuntimeError:/
|
7
|
+
|
8
|
+
Scenario: does not exclude anything from backtrace
|
9
|
+
Given a recipe using a remote
|
10
|
+
When I execute the recipe on unknown remote target with option -d
|
11
|
+
Then the output must contain "producer-core"
|
12
|
+
And the output must contain "net-ssh"
|
13
|
+
And the output must contain ruby lib directory
|
@@ -1,20 +1,32 @@
|
|
1
1
|
Feature: CLI error reporting
|
2
2
|
|
3
|
-
Background:
|
4
|
-
Given a recipe with:
|
5
|
-
"""
|
6
|
-
task(:trigger_error) { fail 'some error' }
|
7
|
-
"""
|
8
|
-
|
9
3
|
Scenario: reports recipe errors
|
4
|
+
Given a recipe with an error
|
10
5
|
When I execute the recipe
|
11
6
|
Then the exit status must be 70
|
12
7
|
And the output must match /\ARuntimeError: some error\n/
|
13
8
|
|
14
9
|
Scenario: reports errors with a backtrace
|
10
|
+
Given a recipe with an error
|
15
11
|
When I execute the recipe
|
16
12
|
Then the output must match /^\s+recipe\.rb:\d+:in /
|
17
13
|
|
18
14
|
Scenario: prepends recipe file path in the backtrace
|
15
|
+
Given a recipe with an error
|
19
16
|
When I execute the recipe
|
20
17
|
Then the output must match /^\s+recipe\.rb \(recipe\)\n\s+recipe\.rb:/
|
18
|
+
|
19
|
+
Scenario: excludes producer from backtrace
|
20
|
+
Given a recipe using a remote
|
21
|
+
When I execute the recipe on unknown remote target
|
22
|
+
Then the output must not contain "producer-core"
|
23
|
+
|
24
|
+
Scenario: excludes net-ssh from backtrace
|
25
|
+
Given a recipe using a remote
|
26
|
+
When I execute the recipe on unknown remote target
|
27
|
+
Then the output must not contain "net-ssh"
|
28
|
+
|
29
|
+
Scenario: excludes ruby standard library from backtrace
|
30
|
+
Given a recipe using a remote
|
31
|
+
When I execute the recipe on unknown remote target
|
32
|
+
Then the output must not contain ruby lib directory
|
data/features/cli/usage.feature
CHANGED
@@ -25,3 +25,11 @@ end
|
|
25
25
|
Then /^the error output must contain exactly "([^"]+)"$/ do |content|
|
26
26
|
assert_exact_output content, all_stderr
|
27
27
|
end
|
28
|
+
|
29
|
+
Then /^the output must contain ruby lib directory$/ do
|
30
|
+
assert_partial_output RbConfig::CONFIG['rubylibdir'], all_output
|
31
|
+
end
|
32
|
+
|
33
|
+
Then /^the output must not contain ruby lib directory$/ do
|
34
|
+
assert_no_partial_output RbConfig::CONFIG['rubylibdir'], all_output
|
35
|
+
end
|
@@ -2,6 +2,14 @@ Given /^a recipe with:$/ do |recipe_body|
|
|
2
2
|
write_file 'recipe.rb', recipe_body
|
3
3
|
end
|
4
4
|
|
5
|
+
Given /^a recipe with an error$/ do
|
6
|
+
write_file 'recipe.rb', "task(:trigger_error) { fail 'some error' }\n"
|
7
|
+
end
|
8
|
+
|
9
|
+
Given /^a recipe using a remote$/ do
|
10
|
+
write_file 'recipe.rb', "task(:some_task) { sh 'echo hello' }\n"
|
11
|
+
end
|
12
|
+
|
5
13
|
Given /^a recipe named "([^"]+)" with:$/ do |recipe_path, recipe_body|
|
6
14
|
write_file recipe_path, recipe_body
|
7
15
|
end
|
@@ -14,6 +22,16 @@ When /^I execute the recipe on remote target$/ do
|
|
14
22
|
run_simple 'producer recipe.rb -t some_host.test', false
|
15
23
|
end
|
16
24
|
|
25
|
+
When /^I execute the recipe on unknown remote target$/ do
|
26
|
+
run_simple 'producer recipe.rb -t #unknown_host.test', false
|
27
|
+
assert_matching_output '\ASocketError', all_output
|
28
|
+
end
|
29
|
+
|
30
|
+
When /^I execute the recipe on unknown remote target with option (-.+)$/ do |option|
|
31
|
+
run_simple "producer recipe.rb #{option} -t #unknown_host.test", false
|
32
|
+
assert_matching_output '\ASocketError', all_output
|
33
|
+
end
|
34
|
+
|
17
35
|
When /^I successfully execute the recipe$/ do
|
18
36
|
step 'I execute the recipe'
|
19
37
|
assert_exit_status 0
|
data/features/support/env.rb
CHANGED
@@ -2,7 +2,6 @@ require 'aruba/cucumber'
|
|
2
2
|
require 'aruba/in_process'
|
3
3
|
require 'producer/core'
|
4
4
|
|
5
|
-
|
6
5
|
class ArubaProgramWrapper
|
7
6
|
def initialize(argv, stdin = $stdin, stdout = $stdout, stderr = $stderr,
|
8
7
|
kernel = Kernel)
|
@@ -18,16 +17,18 @@ class ArubaProgramWrapper
|
|
18
17
|
@argv.dup, stdin: @stdin, stdout: @stdout, stderr: @stderr
|
19
18
|
)
|
20
19
|
rescue SystemExit => e
|
21
|
-
@kernel.exit
|
20
|
+
@kernel.exit e.status
|
22
21
|
end
|
23
22
|
end
|
24
23
|
|
25
24
|
|
25
|
+
# Raise aruba default timeout so test suite can run on a slow machine.
|
26
26
|
Before do
|
27
|
-
@
|
27
|
+
@aruba_timeout_seconds = 8
|
28
28
|
end
|
29
|
-
require 'cucumber/sshd/cucumber'
|
30
29
|
|
30
|
+
# Use aruba "in process" optimization only for scenarios not tagged @exec.
|
31
|
+
# We need a real process in a few cases: real program name, interactive usage…
|
31
32
|
Before('@exec') do
|
32
33
|
Aruba.process = Aruba::SpawnProcess
|
33
34
|
end
|
@@ -36,3 +37,15 @@ Before('~@exec') do
|
|
36
37
|
Aruba::InProcess.main_class = ArubaProgramWrapper
|
37
38
|
Aruba.process = Aruba::InProcess
|
38
39
|
end
|
40
|
+
|
41
|
+
# Fake home directory for @fake_home tagged scenarios.
|
42
|
+
Before('@fake_home') do
|
43
|
+
ENV['HOME'] = File.expand_path(current_dir)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Enable cucumber-sshd "fast" mode (persists sshd across scenarios), and
|
47
|
+
# register hooks for @sshd tagged scenarios.
|
48
|
+
Before do
|
49
|
+
@_sshd_fast = true
|
50
|
+
end
|
51
|
+
require 'cucumber/sshd/cucumber'
|
@@ -2,9 +2,10 @@ module Producer
|
|
2
2
|
module Core
|
3
3
|
class ErrorFormatter
|
4
4
|
FILTERS = [
|
5
|
-
/\/producer-\w
|
6
|
-
|
7
|
-
/\/net
|
5
|
+
/\/producer-\w+/,
|
6
|
+
Regexp.new(RbConfig::CONFIG['rubylibdir']),
|
7
|
+
/\/net-ssh/,
|
8
|
+
/\/net-sftp/
|
8
9
|
].freeze
|
9
10
|
|
10
11
|
def initialize(debug: false, force_cause: [])
|
@@ -17,7 +18,7 @@ module Producer
|
|
17
18
|
end
|
18
19
|
|
19
20
|
def format(exception)
|
20
|
-
lines = format_exception exception
|
21
|
+
lines = format_exception exception, filter: !debug?
|
21
22
|
|
22
23
|
if debug? && exception.cause
|
23
24
|
lines << ''
|
data/producer-core.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.add_dependency 'net-sftp', '~> 2.1'
|
22
22
|
|
23
23
|
s.add_development_dependency 'rspec', '~> 3.1'
|
24
|
-
s.add_development_dependency 'cucumber', '~>
|
24
|
+
s.add_development_dependency 'cucumber', '~> 2.0'
|
25
25
|
s.add_development_dependency 'aruba', '~> 0.5'
|
26
26
|
s.add_development_dependency 'cucumber-sshd', '~> 0.1'
|
27
27
|
s.add_development_dependency 'rake', '~> 10.1'
|
@@ -23,10 +23,14 @@ module Producer
|
|
23
23
|
end
|
24
24
|
|
25
25
|
describe '#format' do
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
let(:rubylibdir) { RbConfig::CONFIG['rubylibdir'] }
|
27
|
+
let(:bt) { %W[backtrace /producer-core /net-ssh #{rubylibdir}] }
|
28
|
+
let(:exception) { RuntimeError.new('some exception').tap { |o| o.set_backtrace bt } }
|
29
|
+
|
30
|
+
def exception_with_cause
|
31
|
+
begin fail 'exception cause' rescue fail 'some exception' end
|
32
|
+
rescue => e
|
33
|
+
e.tap { |o| o.set_backtrace bt }
|
30
34
|
end
|
31
35
|
|
32
36
|
it 'formats the message' do
|
@@ -35,21 +39,44 @@ module Producer
|
|
35
39
|
end
|
36
40
|
|
37
41
|
it 'indents the backtrace' do
|
38
|
-
expect(formatter.format exception).to match /^\s+
|
42
|
+
expect(formatter.format exception).to match /^\s+backtrace$/
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'excludes producer code from the backtrace' do
|
46
|
+
expect(formatter.format exception).not_to include 'producer-core'
|
39
47
|
end
|
40
48
|
|
41
|
-
|
42
|
-
|
49
|
+
it 'excludes net-ssh from the backtrace' do
|
50
|
+
expect(formatter.format exception).not_to include 'net-ssh'
|
51
|
+
end
|
43
52
|
|
44
|
-
|
45
|
-
|
53
|
+
it 'excludes ruby lib directory from the backtrace' do
|
54
|
+
expect(formatter.format exception).not_to include rubylibdir
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when exception has a cause' do
|
58
|
+
it 'does not include the cause' do
|
59
|
+
expect(formatter.format exception_with_cause)
|
60
|
+
.not_to include 'exception cause'
|
46
61
|
end
|
62
|
+
end
|
47
63
|
|
48
|
-
|
49
|
-
|
64
|
+
context 'when debug is enabled' do
|
65
|
+
let(:debug) { true }
|
66
|
+
|
67
|
+
it 'does not filter the backtrace' do
|
68
|
+
expect(formatter.format exception).to include 'producer-core'
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when exception has a cause' do
|
72
|
+
it 'includes the exception cause' do
|
73
|
+
expect(formatter.format exception_with_cause)
|
74
|
+
.to include 'exception cause'
|
75
|
+
end
|
50
76
|
|
51
|
-
it '
|
52
|
-
expect(formatter.format
|
77
|
+
it 'formats the cause' do
|
78
|
+
expect(formatter.format exception_with_cause)
|
79
|
+
.to match /^cause:\nRuntimeError: exception cause/
|
53
80
|
end
|
54
81
|
end
|
55
82
|
end
|
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: producer-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
5
|
-
prerelease:
|
4
|
+
version: 0.4.5
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Thibault Jouan
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2015-
|
11
|
+
date: 2015-04-03 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: net-ssh
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: net-sftp
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - "~>"
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - "~>"
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -46,7 +41,6 @@ dependencies:
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: rspec
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - "~>"
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,6 @@ dependencies:
|
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - "~>"
|
60
53
|
- !ruby/object:Gem::Version
|
@@ -62,23 +55,20 @@ dependencies:
|
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: cucumber
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
59
|
- - "~>"
|
68
60
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
61
|
+
version: '2.0'
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
66
|
- - "~>"
|
76
67
|
- !ruby/object:Gem::Version
|
77
|
-
version: '
|
68
|
+
version: '2.0'
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: aruba
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
73
|
- - "~>"
|
84
74
|
- !ruby/object:Gem::Version
|
@@ -86,7 +76,6 @@ dependencies:
|
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
80
|
- - "~>"
|
92
81
|
- !ruby/object:Gem::Version
|
@@ -94,7 +83,6 @@ dependencies:
|
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: cucumber-sshd
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
87
|
- - "~>"
|
100
88
|
- !ruby/object:Gem::Version
|
@@ -102,7 +90,6 @@ dependencies:
|
|
102
90
|
type: :development
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
94
|
- - "~>"
|
108
95
|
- !ruby/object:Gem::Version
|
@@ -110,7 +97,6 @@ dependencies:
|
|
110
97
|
- !ruby/object:Gem::Dependency
|
111
98
|
name: rake
|
112
99
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
100
|
requirements:
|
115
101
|
- - "~>"
|
116
102
|
- !ruby/object:Gem::Version
|
@@ -118,7 +104,6 @@ dependencies:
|
|
118
104
|
type: :development
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
107
|
requirements:
|
123
108
|
- - "~>"
|
124
109
|
- !ruby/object:Gem::Version
|
@@ -136,6 +121,7 @@ files:
|
|
136
121
|
- Gemfile
|
137
122
|
- Guardfile
|
138
123
|
- LICENSE
|
124
|
+
- README.md
|
139
125
|
- Rakefile
|
140
126
|
- bin/producer
|
141
127
|
- config/cucumber.yaml
|
@@ -168,9 +154,6 @@ files:
|
|
168
154
|
- features/steps/remote_steps.rb
|
169
155
|
- features/steps/ssh_steps.rb
|
170
156
|
- features/support/env.rb
|
171
|
-
- features/support/env_aruba_timeout.rb
|
172
|
-
- features/support/env_cucumber_doc_string.rb
|
173
|
-
- features/support/env_fake_home.rb
|
174
157
|
- features/task/ask.feature
|
175
158
|
- features/task/condition.feature
|
176
159
|
- features/task/nested_tasks.feature
|
@@ -274,27 +257,26 @@ files:
|
|
274
257
|
- spec/support/test_env_helpers.rb
|
275
258
|
homepage: https://rubygems.org/gems/producer-core
|
276
259
|
licenses: []
|
260
|
+
metadata: {}
|
277
261
|
post_install_message:
|
278
262
|
rdoc_options: []
|
279
263
|
require_paths:
|
280
264
|
- lib
|
281
265
|
required_ruby_version: !ruby/object:Gem::Requirement
|
282
|
-
none: false
|
283
266
|
requirements:
|
284
267
|
- - ">="
|
285
268
|
- !ruby/object:Gem::Version
|
286
269
|
version: '0'
|
287
270
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
288
|
-
none: false
|
289
271
|
requirements:
|
290
272
|
- - ">="
|
291
273
|
- !ruby/object:Gem::Version
|
292
274
|
version: '0'
|
293
275
|
requirements: []
|
294
276
|
rubyforge_project:
|
295
|
-
rubygems_version:
|
277
|
+
rubygems_version: 2.4.5
|
296
278
|
signing_key:
|
297
|
-
specification_version:
|
279
|
+
specification_version: 4
|
298
280
|
summary: Provisioning tool
|
299
281
|
test_files:
|
300
282
|
- features/actions/echo.feature
|
@@ -326,9 +308,6 @@ test_files:
|
|
326
308
|
- features/steps/remote_steps.rb
|
327
309
|
- features/steps/ssh_steps.rb
|
328
310
|
- features/support/env.rb
|
329
|
-
- features/support/env_aruba_timeout.rb
|
330
|
-
- features/support/env_cucumber_doc_string.rb
|
331
|
-
- features/support/env_fake_home.rb
|
332
311
|
- features/task/ask.feature
|
333
312
|
- features/task/condition.feature
|
334
313
|
- features/task/nested_tasks.feature
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'cucumber/formatter/pretty'
|
2
|
-
|
3
|
-
module Cucumber
|
4
|
-
module Ast
|
5
|
-
class DocString
|
6
|
-
alias :old_initialize :initialize
|
7
|
-
|
8
|
-
def initialize(string, content_type)
|
9
|
-
old_initialize(string + "\n", content_type)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
module Formatter
|
15
|
-
class Pretty
|
16
|
-
alias :old_doc_string :doc_string
|
17
|
-
|
18
|
-
def doc_string(string)
|
19
|
-
old_doc_string(string.chomp)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|