scripted 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+