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,47 @@
1
+ <div class="container">
2
+ <div class="page-header">
3
+ {{#view Scripted.ConnectionStatusView}}{{content.message}}{{/view}}
4
+ <h1>Scripted <small>live command line output via websockets</small></h1>
5
+ </div>
6
+
7
+ {{#view Scripted.RunnerView}}{{message}}{{/view}}
8
+
9
+ {{#if Scripted.CommandsController.hasCommands}}
10
+ <table class="table table-striped table-bordered">
11
+ <thead>
12
+ <tr>
13
+ <th>Command</th>
14
+ <th>Runtime (s)</th>
15
+ <th>Status</th>
16
+ </tr>
17
+ </thead>
18
+ <tbody>
19
+ {{#each Scripted.CommandsController}}
20
+ {{#view Scripted.CommandView contentBinding="this"}}
21
+ <tr>
22
+ <td>{{content.name}}</td>
23
+ <td>{{content.roundedRuntime}}</td>
24
+ <td>{{#view Scripted.CommandStatusView contentBinding="content"}}{{text}}{{/view}}</td>
25
+ </tr>
26
+ {{/view}}
27
+ {{/each}}
28
+ </tbody>
29
+ </table>
30
+
31
+ {{#each Scripted.CommandsController}}
32
+ {{#view Scripted.CommandView contentBinding="this"}}
33
+ <h3>{{content.name}} {{#view Scripted.CommandStatusView contentBinding="content"}}{{text}}{{/view}}</h3>
34
+ {{#if hasOutput}}
35
+ <div class="output">
36
+ <pre>{{output}}</pre>
37
+ </div>
38
+ {{/if}}
39
+ {{/view}}
40
+ {{/each}}
41
+ {{else}}
42
+ <div class="well">
43
+ Run <tt>bundle exec scripted --format websocket --out http://localhost:9292/faye</tt> to start.
44
+ </div>
45
+ {{/if}}
46
+
47
+ </div>
@@ -0,0 +1,210 @@
1
+ Scripted = Em.Application.create
2
+
3
+ received: (data) ->
4
+ action = @["on_#{data.action}"]
5
+ action(data) if action
6
+
7
+ on_start: (data) ->
8
+ Scripted.CommandsController.clear()
9
+ Scripted.Runner.setProperties(data.runner)
10
+ for command in data.commands
11
+ Scripted.updateCommand(command)
12
+
13
+ on_stop: (data) ->
14
+ Scripted.Runner.setProperties(data.runner)
15
+ for command in data.commands
16
+ Scripted.updateCommand(command)
17
+
18
+ on_execute: (data) ->
19
+ Scripted.updateCommand(data.command)
20
+
21
+ on_done: (data) ->
22
+ Scripted.updateCommand(data.command)
23
+
24
+ on_output: (data) ->
25
+ for output in data.output
26
+ command = Scripted.updateCommand(output.command).set('output', output.output)
27
+
28
+ updateCommand: (command) ->
29
+ Scripted.CommandsController.updateOrCreate(command)
30
+
31
+ Scripted.ConnectionStatus = Em.Object.create
32
+
33
+ status: "error"
34
+ message: "No Connection"
35
+
36
+ success: ->
37
+ if @get('hasErrored')
38
+ window.location.reload()
39
+ @set 'status', 'success'
40
+ @set 'message', 'Connected'
41
+
42
+ error: (message) ->
43
+ @set 'status', 'error'
44
+ @set 'message', "Error: #{message}"
45
+ @set 'hasErrored', true
46
+
47
+
48
+
49
+ Scripted.ConnectionStatusView = Em.View.extend
50
+
51
+ contentBinding: 'Scripted.ConnectionStatus'
52
+ tagName: 'span'
53
+ classNameBindings: ['default', 'status']
54
+
55
+ default: "pull-right label"
56
+
57
+ status: (->
58
+ switch @get('content').get('status')
59
+ when "success" then "label-success"
60
+ when "error" then "label-important"
61
+ else "label-warning"
62
+ ).property('content.status')
63
+
64
+
65
+
66
+ Scripted.CommandStatusView = Em.View.extend
67
+
68
+ tagName: 'span'
69
+ classNameBindings: ['className']
70
+
71
+ text: (->
72
+ @get('content').get('human_status')
73
+ ).property('content.human_status')
74
+
75
+ className: (->
76
+ status_code = @get('content').get('status_code')
77
+ switch status_code
78
+ when "running" then "label label-info"
79
+ when "success", "success_ran_because_other_command_failed" then "label label-success"
80
+ when "failed", "failed_ran_because_other_command_failed" then "label label-important"
81
+ when "failed_but_ignored" then "label label-warning"
82
+ when "failed_and_halted" then "label label-inverse"
83
+ else "label"
84
+ ).property('content.status_code')
85
+
86
+ Scripted.CommandView = Em.View.extend
87
+
88
+ classNameBindings: ['content.status_code']
89
+
90
+ output: (->
91
+ html = ""
92
+ output = @get('content').get('output')
93
+ nodes = ansiparse(output)
94
+ for node in nodes
95
+ html += "<span class='#{node.foreground}'>#{node.text}</span>"
96
+ new Handlebars.SafeString(html)
97
+ ).property('content.output')
98
+
99
+ hasOutput: (->
100
+ output = @get('content').get('output')
101
+ output and output != ""
102
+ ).property('content.output')
103
+
104
+ outputChanged: (->
105
+ output = this.$('.output')
106
+ scrollDown = -> output[0].scrollTop = output[0].scrollHeight + 100000
107
+ if output.length > 0
108
+ setTimeout scrollDown, 100
109
+ setTimeout scrollDown, 500
110
+ ).observes('output', 'content.status_code')
111
+
112
+ Scripted.Runner = Em.Object.create
113
+
114
+ running: false
115
+ executed: false
116
+ started_at: null
117
+
118
+ roundedRuntime: (->
119
+ value = @get('runtime')
120
+ if value
121
+ value.toFixed(3)
122
+ else
123
+ ""
124
+ ).property('runtime')
125
+
126
+ Scripted.RunnerView = Em.View.extend
127
+
128
+ contentBinding: 'Scripted.Runner'
129
+ classNameBindings: ["alert", "alertType"]
130
+
131
+ alert: (-> "alert").property()
132
+
133
+ message: (->
134
+ content = @get('content')
135
+ commandsCount = "<strong>#{Scripted.CommandsController.content.length}</strong>"
136
+ started_at = content.get('started_at')
137
+ text = if Scripted.CommandsController.get('hasCommands')
138
+ if not content.get('executed')
139
+ "Running #{commandsCount} commands"
140
+ else if content.get('failed')
141
+ "One or more commands have failed"
142
+ else
143
+ "Success! Ran #{commandsCount} commands in <strong>#{content.get('roundedRuntime')}</strong> seconds"
144
+ else
145
+ "There are <strong>no</strong> commands yet."
146
+ new Handlebars.SafeString(text)
147
+ ).property('content.started_at', 'content.failed', 'content.executed', 'content.roundedRuntime', 'Scripted.CommandsController.hasCommands')
148
+
149
+ alertType: (->
150
+ failed = @get('content').get('failed')
151
+ running = @get('content').get('running')
152
+ executed = @get('content').get('executed')
153
+ if failed
154
+ "alert-error"
155
+ else if running
156
+ "alert-info"
157
+ else if executed
158
+ "alert-success"
159
+ else
160
+ ""
161
+ ).property('content.failed', 'content.running', 'content.executed')
162
+
163
+ Scripted.Command = Em.Object.extend
164
+
165
+ id: null
166
+ name: ""
167
+ status_code: "unknown"
168
+ output: ''
169
+
170
+ roundedRuntime: (->
171
+ value = @get('runtime')
172
+ if value
173
+ value.toFixed(3)
174
+ else
175
+ ""
176
+ ).property('runtime')
177
+
178
+ Scripted.CommandsController = Em.ArrayController.create
179
+
180
+ content: []
181
+
182
+ updateOrCreate: (data) ->
183
+ command = @findCommand(data)
184
+ if command
185
+ command.setProperties(data)
186
+ else
187
+ command = Scripted.Command.create(data)
188
+ @pushObject(command)
189
+ command
190
+
191
+
192
+ findCommand: (data) ->
193
+ if @get('hasCommands')
194
+ @find((command) -> command.get('id') is data.id)
195
+ else
196
+ null
197
+
198
+ hasCommands: (->
199
+ @get('content').length > 0
200
+ ).property('lastObject')
201
+
202
+ jQuery ->
203
+ client = new Faye.Client('http://localhost:9292/faye')
204
+ subscription = client.subscribe '/scripted', (data) -> Scripted.received(data)
205
+ subscription.callback -> Scripted.ConnectionStatus.success()
206
+ subscription.errback (error) -> Scripted.ConnectionStatus.error(error.message)
207
+ client.bind 'transport:down', -> Scripted.ConnectionStatus.error("No Connection")
208
+ client.bind 'transport:up', -> Scripted.ConnectionStatus.success()
209
+
210
+ window.Scripted = Scripted
@@ -0,0 +1 @@
1
+ <%= handlebars "client" %>
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title>Websocket Client</title>
5
+ <script type="text/javascript" src="http://localhost:9292/faye/client.js"></script>
6
+ <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
7
+ <script type="text/javascript" src="http://cloud.github.com/downloads/emberjs/ember.js/ember-0.9.8.1.min.js"></script>
8
+ <script type="text/javascript" src="/ansiparse.js"></script>
9
+ <script type="text/javascript" src="/app.js"></script>
10
+ <link href="http://current.bootstrapcdn.com/bootstrap-v204/css/bootstrap-combined.min.css" rel="stylesheet">
11
+ <link href="/style.css" rel="stylesheet">
12
+ </head>
13
+ <body><%= yield %></body>
14
+ </html>
@@ -0,0 +1,61 @@
1
+ .black
2
+ color: #555555
3
+ .red
4
+ color: #FF6C60
5
+ .green
6
+ color: #99CC99
7
+ .yellow
8
+ color: #FFFFB6
9
+ .blue
10
+ color: #6699CC
11
+ .magenta
12
+ color: #FF73FD
13
+ .cyan
14
+ color: #C6C5FE
15
+ .white
16
+ color: #F6F3E8
17
+ .grey
18
+ color: #555555
19
+
20
+ h2
21
+ margin: 10px 0
22
+
23
+ pre
24
+ border: 0 none
25
+ background: black
26
+ color: #F6F3E8
27
+ font-family: "DejaVu Sans Mono", "Droid Sans Mono", "Menlo", "Monaco", "Courier New", monospace
28
+ font-size: 14px
29
+ margin: 0
30
+
31
+ .output pre
32
+ vertical-align: bottom
33
+
34
+ .output
35
+ font-size: 14px
36
+ max-height: 1000px
37
+ overflow-y: scroll
38
+ overflow-x: hidden
39
+
40
+ .success .output
41
+ transition-duration: 0.5s
42
+ -moz-transition-duration: 0.5s
43
+ -webkit-transition-duration: 0.5s
44
+ -o-transition-duration: 0.5s
45
+ max-height: 100px
46
+
47
+ h3 .label
48
+ vertical-align: 2px
49
+
50
+ .cursor
51
+ background: #F6F3E8
52
+ .prompt
53
+ color: #6699CC
54
+
55
+ tt
56
+ background-color: #DDD
57
+ padding: 3px 6px
58
+ margin: 0 5px
59
+ -webkit-border-radius: 4px
60
+ -moz-border-radius: 4px
61
+ border-radius: 4px
@@ -0,0 +1,124 @@
1
+ Feature: Controlling Exit Status
2
+
3
+ By default, Scripted will run all commands. If a command failed (e.g. if you
4
+ have failing tests) the entire run will be marked as failed. In Unix terms,
5
+ this means the exit code will be zero for successful runs and non-zero for
6
+ failed runs.
7
+
8
+ Sometimes it doesn't make sense to continue running commands if one failed,
9
+ like when an important setup command failed. If this is the case, you can
10
+ mark the command as important. If this commands fails, it will not run the
11
+ following commands.
12
+
13
+ Here RSpec won't run if the database cannot be created:
14
+
15
+ ``` ruby
16
+ run "create the database" do
17
+ rake "db:create"
18
+ important!
19
+ end
20
+
21
+ run "rspec"
22
+ ```
23
+
24
+ Sometimes you don't care if the command failed or not. The recommended
25
+ approach is to change the command itself so it does behave, but if you can't
26
+ do that, you can mark it with `unimportant!`.
27
+
28
+ ``` ruby
29
+ run "some command" do
30
+ unimportant!
31
+ end
32
+ ```
33
+
34
+ Sometimes a command can be very important to you. An example might be
35
+ shutting down daemons after a test run. You always want these commands to
36
+ run, even if your test suite failed. You can mark these with `forced!`
37
+
38
+ ``` ruby
39
+ run "stop xvfb" do
40
+ `/etc/init.d/xvfb`
41
+ forced!
42
+ end
43
+ ```
44
+
45
+ If the run did fail, you might want to do some extra work, like sending an
46
+ email. You can mark those with `only_when_failed!`.
47
+
48
+ ``` ruby
49
+ run "email" do
50
+ `mail -s Failure you@example.org`
51
+ only_when_failed!
52
+ end
53
+ ```
54
+
55
+
56
+ Scenario: Having failing commands
57
+ Given the configuration:
58
+ """
59
+ run "false"
60
+ run "echo this should still run"
61
+ """
62
+ When I run scripted
63
+ Then it should fail
64
+ And the output should contain "this should still run"
65
+
66
+ Scenario: A failing important command
67
+ Given the configuration:
68
+ """
69
+ run "false" do
70
+ important!
71
+ end
72
+ run "echo this command will not be run"
73
+ """
74
+ When I run scripted
75
+ Then it should fail
76
+ And the output should not contain "this command will not be run"
77
+
78
+ Scenario: Enforcing commands
79
+ Given the configuration:
80
+ """
81
+ run "false" do
82
+ important!
83
+ end
84
+ run "echo this command is forced" do
85
+ forced!
86
+ end
87
+ """
88
+ When I run scripted
89
+ Then it should fail
90
+ And the output should contain "this command is forced"
91
+
92
+ Scenario: A failing command that would otherwise have failed.
93
+ Given the configuration:
94
+ """
95
+ run "false" do
96
+ unimportant!
97
+ end
98
+ """
99
+ When I run scripted
100
+ Then it should pass
101
+
102
+ Scenario: Only when failed with a failing command
103
+ Given the configuration:
104
+ """
105
+ run "false"
106
+ run "echo only when failed has run" do
107
+ only_when_failed!
108
+ end
109
+ """
110
+ When I run scripted
111
+ Then it should fail
112
+ And the output should contain "only when failed has run"
113
+
114
+ Scenario: Only when failed when nothing failed
115
+ Given the configuration:
116
+ """
117
+ run "true"
118
+ run "echo only when failed has run" do
119
+ only_when_failed!
120
+ end
121
+ """
122
+ When I run scripted
123
+ Then it should pass
124
+ And the output should not contain "only when failed has run"