scripted 0.0.1

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.
Files changed (73) hide show
  1. data/.gitignore +19 -0
  2. data/.rspec +3 -0
  3. data/.travis.yml +8 -0
  4. data/Gemfile +6 -0
  5. data/MIT-LICENSE +22 -0
  6. data/README.md +423 -0
  7. data/Rakefile +39 -0
  8. data/bin/scripted +67 -0
  9. data/cucumber.yml +3 -0
  10. data/examples/important.rb +31 -0
  11. data/examples/parallel.rb +30 -0
  12. data/examples/pride.rb +37 -0
  13. data/examples/websockets.png +0 -0
  14. data/examples/websockets.rb +37 -0
  15. data/examples/websockets/public/ansiparse.js +156 -0
  16. data/examples/websockets/server.rb +32 -0
  17. data/examples/websockets/server.ru +10 -0
  18. data/examples/websockets/views/_client.handlebars +47 -0
  19. data/examples/websockets/views/app.coffee +210 -0
  20. data/examples/websockets/views/index.erb +1 -0
  21. data/examples/websockets/views/layout.erb +14 -0
  22. data/examples/websockets/views/style.sass +61 -0
  23. data/features/controlling_exit_status.feature +124 -0
  24. data/features/formatters.feature +142 -0
  25. data/features/rake_integration.feature +86 -0
  26. data/features/running_commands_in_parallel.feature +27 -0
  27. data/features/running_from_command_line.feature +56 -0
  28. data/features/running_from_ruby.feature +38 -0
  29. data/features/running_groups.feature +39 -0
  30. data/features/specifying_which_commands_to_run.feature +122 -0
  31. data/features/steps/scripted_steps.rb +25 -0
  32. data/features/support/aruba.rb +5 -0
  33. data/features/support/env.rb +2 -0
  34. data/install +5 -0
  35. data/lib/scripted.rb +28 -0
  36. data/lib/scripted/command.rb +82 -0
  37. data/lib/scripted/commands/rake.rb +25 -0
  38. data/lib/scripted/commands/ruby.rb +22 -0
  39. data/lib/scripted/commands/shell.rb +28 -0
  40. data/lib/scripted/configuration.rb +103 -0
  41. data/lib/scripted/error.rb +13 -0
  42. data/lib/scripted/formatters/announcer.rb +39 -0
  43. data/lib/scripted/formatters/blank.rb +97 -0
  44. data/lib/scripted/formatters/default.rb +62 -0
  45. data/lib/scripted/formatters/human_status.rb +38 -0
  46. data/lib/scripted/formatters/stats.rb +38 -0
  47. data/lib/scripted/formatters/table.rb +99 -0
  48. data/lib/scripted/formatters/websocket.rb +137 -0
  49. data/lib/scripted/group.rb +49 -0
  50. data/lib/scripted/output/command_logger.rb +42 -0
  51. data/lib/scripted/output/logger.rb +139 -0
  52. data/lib/scripted/rake_task.rb +24 -0
  53. data/lib/scripted/runner.rb +19 -0
  54. data/lib/scripted/running/execute.rb +16 -0
  55. data/lib/scripted/running/run_command.rb +101 -0
  56. data/lib/scripted/running/run_commands.rb +98 -0
  57. data/lib/scripted/running/select_commands.rb +22 -0
  58. data/lib/scripted/version.rb +3 -0
  59. data/scripted.gemspec +35 -0
  60. data/scripted.rb +16 -0
  61. data/spec/scripted/command_spec.rb +72 -0
  62. data/spec/scripted/commands/ruby_spec.rb +10 -0
  63. data/spec/scripted/commands/shell_spec.rb +18 -0
  64. data/spec/scripted/configuration_spec.rb +50 -0
  65. data/spec/scripted/formatters/websocket_spec.rb +14 -0
  66. data/spec/scripted/group_spec.rb +49 -0
  67. data/spec/scripted/running/run_command_spec.rb +157 -0
  68. data/spec/scripted/running/run_commands_spec.rb +150 -0
  69. data/spec/scripted/running/select_commands_spec.rb +28 -0
  70. data/spec/spec_helper.rb +15 -0
  71. data/spec/support/expect_to_receive.rb +17 -0
  72. data/spec/support/io_capture.rb +50 -0
  73. metadata +340 -0
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ .rbx
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ log
19
+ .sass-cache
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --tty
3
+ --format Fivemat
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 1.9.2
5
+ - rbx-19mode
6
+ - rbx-18mode
7
+ - ree
8
+ - 1.8.7
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in scripted.gemspec
4
+ gemspec
5
+
6
+ gem 'fastercsv', :platforms => :ruby_18
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 iain
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,423 @@
1
+ # Scripted
2
+
3
+ [![Build Status](https://secure.travis-ci.org/iain/scripted.png?branch=master)](http://travis-ci.org/iain/scripted)
4
+
5
+ Scripted is a framework for organizing scripts.
6
+
7
+ Among its features are:
8
+
9
+ * A convenient DSL to determine how and when to run scripts
10
+ * Determine which scripts in parallel with each other
11
+ * Manage the exit status of your scripts
12
+ * A variaty of output formatters, including one that exports the output of the
13
+ scripts via websockets!
14
+ * Specify groups of tasks
15
+ * Integration with Rake
16
+
17
+ See a video of [scripted running with websockets](http://www.youtube.com/watch?v=GMiN0dHtFkg).
18
+
19
+ ## Reasoning
20
+
21
+ It is considered good practice to bundle all the tasks you need to do in one
22
+ script. This can be a setup script that installs your application, or a all
23
+ test scripts combined for your CI to use.
24
+
25
+ While it is very easy to make this with plain Bash scripts, I found myself
26
+ writing a lot of boiler code over and over again. I wanted to keep track of the
27
+ runtimes of each commands. Or I wanted to run certain scripts in parallel, but
28
+ still wait for them to finish.
29
+
30
+ This gem exists because I wanted to simply define which commands to run, and
31
+ not deal with all the boilerplate code every time.
32
+
33
+ ## Examples
34
+
35
+ There are a number of examples included in the project. You can find them in
36
+ the `examples` directory.
37
+
38
+ * Clone the project
39
+ * Install via `./install`
40
+ * See which examples are avaibale: `rake -T examples`
41
+ * Run an example: `rake examples:websockets`
42
+
43
+ ## Usage
44
+
45
+ You'll need to create a configuration file for scripted to run. By default this
46
+ file is called `scripted.rb`, but you can name it whatever you like.
47
+
48
+ After making the configuration, you can run it with the `scripted` executable.
49
+
50
+ Run `scripted --help` to get an overview of all the options.
51
+
52
+ ### The Basic Command DSL
53
+
54
+ You can define "commands" via the `run`-method. For instance:
55
+
56
+ ``` ruby
57
+ run "rspec"
58
+ run "cucumber"
59
+ ```
60
+
61
+ The first argument to the `run`-method is the name of the command. If you don't
62
+ specify anything else, this will be the shell command run. You can change the
63
+ command further by supplying a block.
64
+
65
+ ``` ruby
66
+ run "fast unit specs" do
67
+ `rspec spec/unit`
68
+ end
69
+
70
+ run "slow integration specs" do
71
+ `rspec spec/integration`
72
+ end
73
+ ```
74
+
75
+ You can also specify Rake tasks and Ruby commands to run:
76
+
77
+ ``` ruby
78
+ run "migrate the database" do
79
+ rake "db:migrate"
80
+ end
81
+
82
+ run "some ruby code" do
83
+ ruby { 1 + 1 }
84
+ end
85
+ ```
86
+
87
+ Keep in mind that MRI has trouble running ruby and rake tasks in parallel due
88
+ to the GIL.
89
+
90
+ ### Running scripts in parallel
91
+
92
+ You can really win some time by running certain commands in parallel. Doing
93
+ that is easy, just put them in a `parallel`-block:
94
+
95
+ ``` ruby
96
+ run "bundle install"
97
+
98
+ parallel do
99
+ run "rspec"
100
+ run "cucumber"
101
+ end
102
+
103
+ run "something else"
104
+ ```
105
+
106
+ Commands that come after the parallel block, will wait until all the commands
107
+ that run in parallel have finished.
108
+
109
+ There are only a few caveats to this. The scripts must be able to run
110
+ simultaniously. If they both access the same global data, like a database or
111
+ files on your hard disk, they will probably fail. Any output they produce
112
+ will appear at the same time, possibly making it unreadable.
113
+
114
+ You can specify multiple parallel blocks.
115
+
116
+ ### Managing exit status
117
+
118
+ By default, all commands will run, even if one failed. The exit status of the
119
+ entire scripted run will hover reflect that one script has failed.
120
+
121
+ If one of your commands is so important that other commands cannot possibly
122
+ succeed afterwards, mark it with `important!`:
123
+
124
+ ``` ruby
125
+ run "bundle install" do
126
+ important!
127
+ end
128
+
129
+ run "rspec"
130
+ ```
131
+
132
+ If a command might fail, but you don't want the global exit status to change if
133
+ it happens, mark the command with `unimportant!`
134
+
135
+ ``` ruby
136
+ run "flickering tests" do
137
+ unimportant!
138
+ end
139
+ ```
140
+
141
+ If you have some clean up to do, that always must run, even if an important
142
+ command failed, mark it with `forced!`:
143
+
144
+ ``` ruby
145
+ run "start xvfb" do
146
+ `/etc/init.d/xvfb start`
147
+ unimportant! # it might be on already
148
+ end
149
+
150
+ run "bundle install" do
151
+ important!
152
+ end
153
+
154
+ run "rspec"
155
+
156
+ run "stop xvfb" do
157
+ `/etc/init.d/xvfb stop`
158
+ forced!
159
+ end
160
+ ```
161
+
162
+ And finally, to have a command run only if other commands have failed, mark it
163
+ with `only_when_failed!`:
164
+
165
+ ``` ruby
166
+ run "mail me if build failed" do
167
+ only_when_failed!
168
+ end
169
+ ```
170
+
171
+ ### Formatters
172
+
173
+ Formatters determine what gets outputted. This can be to your screen, a file,
174
+ or a websocket. You can specify the formatters via the command line, or via
175
+ the configuration file.
176
+
177
+ Via the command line:
178
+
179
+ $ scripted --format my_formatter --out some_file.txt
180
+
181
+ Via the configuration file:
182
+
183
+ ``` ruby
184
+ formatter :my_formatter, :out => "some_file.txt"
185
+ ```
186
+
187
+ You can have multiple formatters. If you don't specify the `out` option, it
188
+ will send the output to `STDOUT`.
189
+
190
+ #### The default formatter
191
+
192
+ The formatter that is used if you don't specify anything is `default`. This
193
+ formatter will output the output of your scripts and display stacktraces. If
194
+ you specify different formatters, the default formatter will not be used. So if
195
+ you still want output to the terminal, you need to add this formatter.
196
+
197
+ $ scripted -f default -f some_other_formatter
198
+
199
+ #### Table formatter
200
+
201
+ The `table` formatter will display an ASCII table when it's done, giving an
202
+ overview of all commands.
203
+
204
+ It looks something like this:
205
+
206
+ ```
207
+ ┌─────────────────┬─────────┬─────────┐
208
+ │ Command │ Runtime │ Status │
209
+ ├─────────────────┼─────────┼─────────┤
210
+ │ rspec │ 0.661s │ success │
211
+ │ cucumber │ 18.856s │ success │
212
+ │ cucumber -p wip │ 0.558s │ success │
213
+ └─────────────────┴─────────┴─────────┘
214
+ Total runtime: 19.527s
215
+ ```
216
+
217
+ To use it:
218
+
219
+ $ scripted --format table
220
+
221
+ #### Announcer formatter
222
+
223
+ This will print a banner before each command, so you can easily see when a
224
+ command is executed.
225
+
226
+ It looks something like this:
227
+
228
+ ```
229
+ ┌────────────────────────────────────────────────┐
230
+ │ bundle update │
231
+ └────────────────────────────────────────────────┘
232
+ ```
233
+
234
+ To use it:
235
+
236
+ $ scripted --format announcer
237
+
238
+ #### Stats formatter
239
+
240
+ The `stats` formatter will print a csv file with the same contents as the
241
+ `table`-formatter. This is handy if you want to keep track of how long your
242
+ test suite takes over time, for example.
243
+
244
+ Example:
245
+
246
+ ``` csv
247
+ name,runtime,status
248
+ bundle update,5.583716,success
249
+ rspec,4.319095,success
250
+ cucumber,22.292316,failed
251
+ cucumber -p wip,0.649777,success
252
+ ```
253
+
254
+ To use it:
255
+
256
+ $ scripted --format stats --out runtime.csv
257
+
258
+ Note: make sure you backup the file afterwars, because each time it runs, it
259
+ will override the file. Also, if you're running on Ruby 1.8, you'll have to
260
+ install FasterCSV.
261
+
262
+ #### Websocket formatter
263
+
264
+ And last, but not least, the `websocket` formatter. This awesome formatter will
265
+ publish the output of your commands directly to a websocket.
266
+
267
+ This is done via [Faye](http://faye.jcoglan.com/), a simple pub/sub messaging
268
+ system. It is tricky to implement this, so be sure to check out the example
269
+ code, which includes a fully functioning Ember.js application.
270
+
271
+ $ scripted -f websocket -o http://localhost:9292/faye
272
+
273
+ Make sure you have Faye running. The example does this for you.
274
+
275
+ ![Example of the output](https://raw.github.com/iain/scripted/master/examples/websockets.png)
276
+
277
+ #### Your own formatter
278
+
279
+ You can also make your own formatter. As the name of the formatter, just
280
+ specify the class name:
281
+
282
+ $ scripted -f MyAwesome::Formatter
283
+
284
+ Have a look at the existing formatters in `lib/scripted/formatters` to see how
285
+ to make one.
286
+
287
+ ### Groups
288
+
289
+ You can specify different groups of commands by putting commands in a `group`
290
+ block:
291
+
292
+ ``` ruby
293
+ group :test do
294
+ run "rspec"
295
+ run "cucumber"
296
+ end
297
+
298
+ group :install do
299
+ run "bundle install"
300
+ rake "db:setup"
301
+ end
302
+ ```
303
+
304
+ Then you can specify one or many groups to run on the command line:
305
+
306
+ $ scripted --group install --group test
307
+
308
+ Commands that are not defined in any group are put in the `default` group.
309
+
310
+ ### Rake integration
311
+
312
+ Besides calling Rake tasks from Scripted, you can also launch scripted via
313
+ Rake.
314
+
315
+ The simplest example is:
316
+
317
+ ``` ruby
318
+ require 'scripted/rake_task'
319
+ Scripted::RakeTask.new(:scripted)
320
+ ```
321
+
322
+ Then you can run `rake scripted`
323
+
324
+ You can pass a block to specify your commands in-line if you like:
325
+
326
+ ``` ruby
327
+ require 'scripted/rake_task'
328
+ Scripted::RakeTask.new(:install) do
329
+ run "foo"
330
+ run "bar"
331
+ end
332
+ ```
333
+
334
+ You can also supply different groups to run:
335
+
336
+ ``` ruby
337
+ require 'scripted/rake_task'
338
+ Scripted::RakeTask.new(:ci, :install, :test)
339
+ ```
340
+
341
+ Running `rake ci` will run both the `install` and `test` group.
342
+
343
+ ### Ruby integration
344
+
345
+ Calling scripted from within another Ruby process is easy:
346
+
347
+ ``` ruby
348
+ require 'scripted'
349
+ Scripted.run do
350
+ run "something"
351
+ end
352
+ ```
353
+
354
+ ## Some considerations
355
+
356
+ ### Use cases
357
+
358
+ I first named this library "test_suite", and most examples show running test
359
+ suites. But Scripted isn't only for running tests. Here are some ideas:
360
+
361
+ * Installing stuff, like installing stuff you want
362
+ * Running a command perminantly and seeing the output via websockets. Like
363
+ ping, your server, or a tool that monitors your worker queues.
364
+
365
+ ### Complicated setup
366
+
367
+ The beauty if plain bash scripts is that they can be run without having
368
+ anything installed. The problem with Scripted is that it is a gem and you might
369
+ need to `gem install scripted` or `bundle install` before it will work.
370
+
371
+ I prefer to have the README of my projects say, something along the lines of:
372
+
373
+ ``` md
374
+ ## How To
375
+
376
+ * Install: `script/install`
377
+ * Upgrade: `script/upgrade`
378
+ * Deploy: `script/deploy`
379
+ ```
380
+
381
+ Nothing more. No complicated 10 step plan, just type one command and you're
382
+ good to go. You need a bash script for that.
383
+
384
+ So here is an example of how such a bash script might look like:
385
+
386
+ ``` bash
387
+ #!/usr/bin/env bash
388
+ set -e
389
+ gem which scripted >/dev/null 2>&1 || gem install scripted
390
+ scripted --group install
391
+ ```
392
+
393
+ ### Status of the gem
394
+
395
+ This gem is in alpha state. YMMV. I believe I got the basic functionality, but
396
+ not everything is as cleanly implemented as it could be. For instance, there
397
+ are undoubtedly edge cases I didn't think of and error handling can probably be
398
+ more user friendly.
399
+
400
+ I'm putting this out there to get some feedback. Please don't hesitate to
401
+ contact me if you have any questions or ideas for improvements. Mention me on
402
+ [Twitter](https://twitter.com/iain_nl), or open an issue on Github.
403
+
404
+ ### Known issues
405
+
406
+ * Works on MRI and Rubinius.
407
+ * JRuby might have problems running shell commands.
408
+ * JRuby doesn't always allow you to compile C extensions, so you cannot install
409
+ Faye. Use a different Ruby implementation or use the Node.js version.
410
+ * To get color in RSpec, use the `--tty` switch, or RSpec will not believe the
411
+ shell supports color.
412
+ * Use the `--color` switch for Cucumber.
413
+
414
+ ## Contributing
415
+
416
+ To set it up, just run `./install`.
417
+
418
+ 1. Fork it
419
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
420
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
421
+ 4. Push to the branch (`git push origin my-new-feature`)
422
+ 5. Create new Pull Request
423
+