stairs 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +0 -4
- data/README.md +60 -5
- data/bin/stairs +11 -1
- data/lib/stairs/runner.rb +9 -1
- data/lib/stairs/script.rb +4 -3
- data/lib/stairs/step.rb +11 -4
- data/lib/stairs/tasks.rb +1 -1
- data/lib/stairs/util/file_mutation.rb +1 -1
- data/lib/stairs/version.rb +1 -1
- data/spec/lib/stairs/runner_spec.rb +14 -2
- data/spec/lib/stairs/script_spec.rb +15 -2
- data/spec/lib/stairs/step_spec.rb +68 -15
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d00a852f658b8f3191f7ae6c5f7edf56823ecc38
|
4
|
+
data.tar.gz: 424bc1126fe1cb6757b735a3b72a95032e225518
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b7faabcf3e3168c77a3e3afb2d9da5d1cdb020ab71dd4f8a3a90870e4605b39ef37f496e5243e05fb26f4b7cb53a0d6af87d6ea939474892efeb64faefbf59e
|
7
|
+
data.tar.gz: 53e273c0bf8ed61bc395cae6b366e9d9e32f12f54741f021dbf3dff5d6a645ae93e7d092156a079746d46abee344fea28b87622247281b330f5cd8359283b427
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -20,6 +20,21 @@ interactive prompts for everything else.
|
|
20
20
|
[![Build Status](https://travis-ci.org/patbenatar/stairs.png?branch=master)](https://travis-ci.org/patbenatar/stairs)
|
21
21
|
[![Code Climate](https://codeclimate.com/github/patbenatar/stairs.png)](https://codeclimate.com/github/patbenatar/stairs)
|
22
22
|
|
23
|
+
## Table of Contents
|
24
|
+
|
25
|
+
* [Setup](#setup)
|
26
|
+
* [Running Scripts](#running-scripts)
|
27
|
+
* [Command Line Utility](#advanced)
|
28
|
+
* [Defining Scripts](#defining-scripts)
|
29
|
+
* [Collecting Input](#collecting-values)
|
30
|
+
* [Asking Questions](#asking-questions)
|
31
|
+
* [Setting ENV vars](#setting-env-vars)
|
32
|
+
* [Writing to Files](#writing-files)
|
33
|
+
* [Miscellaneous](#misc-helpers)
|
34
|
+
* [Steps](#steps)
|
35
|
+
* [Groups](#groups)
|
36
|
+
* [Plugins](#plugins)
|
37
|
+
|
23
38
|
## Setup
|
24
39
|
|
25
40
|
### Rails
|
@@ -42,7 +57,7 @@ Same as above, but you'll have to manually add the Stairs Rake tasks to your
|
|
42
57
|
require "stairs/tasks"
|
43
58
|
```
|
44
59
|
|
45
|
-
##
|
60
|
+
## Running Scripts
|
46
61
|
|
47
62
|
### Basic
|
48
63
|
|
@@ -60,6 +75,7 @@ If you want more control, use the `stairs` command line utility:
|
|
60
75
|
$ stairs --help
|
61
76
|
Usage: stairs [options]
|
62
77
|
--use-defaults Use defaults when available
|
78
|
+
-g, --groups GROUPS Specify groups to run. e.g. init,reset
|
63
79
|
```
|
64
80
|
|
65
81
|
## Defining scripts
|
@@ -99,8 +115,9 @@ end
|
|
99
115
|
dinner = choice "Meat or vegetables?", ["Meat", "Vegetables"]
|
100
116
|
```
|
101
117
|
|
102
|
-
### Setting
|
103
|
-
Stairs currently supports writing environment variables for rbenv-vars, RVM, and
|
118
|
+
### Setting ENV vars
|
119
|
+
Stairs currently supports writing environment variables for rbenv-vars, RVM, and
|
120
|
+
dotenv.
|
104
121
|
|
105
122
|
```ruby
|
106
123
|
env "NAME", value
|
@@ -124,7 +141,9 @@ Display a message when setup completes
|
|
124
141
|
finish "Now that you're done, go have a drink!"
|
125
142
|
```
|
126
143
|
|
127
|
-
###
|
144
|
+
### Steps
|
145
|
+
|
146
|
+
Group related setup procedures into named steps using `setup`:
|
128
147
|
|
129
148
|
```ruby
|
130
149
|
setup :a_cool_service do
|
@@ -133,12 +152,48 @@ end
|
|
133
152
|
```
|
134
153
|
|
135
154
|
#### Using predefined steps (aka plugins)
|
155
|
+
|
136
156
|
```ruby
|
137
157
|
setup :s3
|
138
158
|
setup :facebook, required: false
|
139
159
|
```
|
140
160
|
|
141
|
-
|
161
|
+
[Available Plugins](#plugins)
|
162
|
+
|
163
|
+
### Groups
|
164
|
+
|
165
|
+
Stairs supports organizing your script into groups in a way similar to what you
|
166
|
+
may be used to with Bundler. With groups you can target specific steps to run
|
167
|
+
for different use cases (see `-g` option in the [command line utility](#advanced)).
|
168
|
+
|
169
|
+
Anything outside of a group will always be executed. Anything within a group
|
170
|
+
will only be executed when its group is run. By default, Stairs runs the `newb`
|
171
|
+
group with `$ rake newb`.
|
172
|
+
|
173
|
+
For example, you may want to run different steps on a brand new setup than you
|
174
|
+
would when resetting an existing setup:
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
group :newb do
|
178
|
+
setup :s3
|
179
|
+
end
|
180
|
+
|
181
|
+
group :newb, :reset do
|
182
|
+
setup :balanced
|
183
|
+
rake "db:setup"
|
184
|
+
end
|
185
|
+
```
|
186
|
+
|
187
|
+
And then run your reset like so:
|
188
|
+
|
189
|
+
```bash
|
190
|
+
$ stairs -g reset
|
191
|
+
```
|
192
|
+
|
193
|
+
## Plugins
|
194
|
+
|
195
|
+
Many projects share dependencies. Plugins are predefined setup steps for common
|
196
|
+
use cases.
|
142
197
|
|
143
198
|
Some steps support options. Options are specified as a hash like so:
|
144
199
|
|
data/bin/stairs
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
require "optparse"
|
4
4
|
require "stairs"
|
5
5
|
|
6
|
+
groups = nil
|
7
|
+
|
6
8
|
Stairs.configure do |config|
|
7
9
|
OptionParser.new do |options|
|
8
10
|
options.banner = "Usage: stairs [options]"
|
@@ -10,6 +12,14 @@ Stairs.configure do |config|
|
|
10
12
|
options.on("--use-defaults", "Use defaults when available") do |value|
|
11
13
|
config.use_defaults = value
|
12
14
|
end
|
15
|
+
|
16
|
+
options.on(
|
17
|
+
"-g",
|
18
|
+
"--groups GROUPS",
|
19
|
+
"Specify groups to run. e.g. init,reset"
|
20
|
+
) do |value|
|
21
|
+
groups = value.split(",").map { |g| g.to_sym } if value
|
22
|
+
end
|
13
23
|
end.parse!
|
14
24
|
end
|
15
25
|
|
@@ -17,4 +27,4 @@ end
|
|
17
27
|
rails_application = File.expand_path("./config/application.rb")
|
18
28
|
require rails_application if File.exists?(rails_application)
|
19
29
|
|
20
|
-
Stairs::Runner.new.run!
|
30
|
+
Stairs::Runner.new(groups).run!
|
data/lib/stairs/runner.rb
CHANGED
@@ -1,8 +1,16 @@
|
|
1
1
|
module Stairs
|
2
2
|
class Runner
|
3
|
+
def initialize(groups=nil)
|
4
|
+
@groups = groups
|
5
|
+
end
|
6
|
+
|
3
7
|
def run!
|
4
8
|
Stairs::InteractiveConfiguration.new.run!
|
5
|
-
Stairs::Script.new("setup.rb").run!
|
9
|
+
Stairs::Script.new("setup.rb", groups).run!
|
6
10
|
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
attr_reader :groups
|
7
15
|
end
|
8
16
|
end
|
data/lib/stairs/script.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
module Stairs
|
2
2
|
class Script
|
3
|
-
def initialize(filename)
|
3
|
+
def initialize(filename, groups)
|
4
4
|
@filename = filename
|
5
5
|
@script = File.read(@filename)
|
6
|
+
@groups = groups
|
6
7
|
end
|
7
8
|
|
8
9
|
def run!
|
@@ -13,9 +14,9 @@ module Stairs
|
|
13
14
|
private
|
14
15
|
|
15
16
|
def run
|
16
|
-
Step.new.instance_eval(script)
|
17
|
+
Step.new(groups).instance_eval(script)
|
17
18
|
end
|
18
19
|
|
19
|
-
attr_reader :script, :filename
|
20
|
+
attr_reader :script, :filename, :groups
|
20
21
|
end
|
21
22
|
end
|
data/lib/stairs/step.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
module Stairs
|
2
2
|
class Step
|
3
|
-
attr_reader :options
|
3
|
+
attr_reader :options, :groups
|
4
4
|
|
5
|
-
def initialize(
|
5
|
+
def initialize(*args)
|
6
|
+
options = args.extract_options!
|
6
7
|
@options = options.reverse_merge required: true
|
8
|
+
|
9
|
+
@groups = args.first
|
7
10
|
end
|
8
11
|
|
9
12
|
def run!
|
@@ -85,16 +88,20 @@ module Stairs
|
|
85
88
|
# of Step
|
86
89
|
def setup(step_name, options={}, &block)
|
87
90
|
if block_given?
|
88
|
-
Step.new(options).tap do |step|
|
91
|
+
Step.new(groups, options).tap do |step|
|
89
92
|
step.define_singleton_method :run, &block
|
90
93
|
step.step_title = step_name.to_s.titleize
|
91
94
|
end.run!
|
92
95
|
else
|
93
96
|
klass = "Stairs::Steps::#{step_name.to_s.camelize}".constantize
|
94
|
-
klass.new(options).run!
|
97
|
+
klass.new(groups, options).run!
|
95
98
|
end
|
96
99
|
end
|
97
100
|
|
101
|
+
def group(*names)
|
102
|
+
yield if !groups || (names & groups).any?
|
103
|
+
end
|
104
|
+
|
98
105
|
def finish(message)
|
99
106
|
puts "== All done!".green
|
100
107
|
puts message.green
|
data/lib/stairs/tasks.rb
CHANGED
@@ -28,7 +28,7 @@ module Stairs
|
|
28
28
|
def write_line(string, filename)
|
29
29
|
File.open filename, "a+" do |file|
|
30
30
|
# ensure file ends with newline before appending
|
31
|
-
last_line = file.each_line.reduce("") { |m, l|
|
31
|
+
last_line = file.each_line.reduce("") { |m, l| l }
|
32
32
|
file.puts "" unless last_line == "" || last_line =~ /(.*)\n/
|
33
33
|
|
34
34
|
file.puts string
|
data/lib/stairs/version.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Stairs::Runner do
|
4
|
+
let(:groups) { nil }
|
5
|
+
let(:subject) { described_class.new(groups) }
|
6
|
+
|
4
7
|
describe "#run!" do
|
5
8
|
let(:script_double) { double("script", run!: true) }
|
6
9
|
|
@@ -16,11 +19,20 @@ describe Stairs::Runner do
|
|
16
19
|
subject.run!
|
17
20
|
end
|
18
21
|
|
19
|
-
it "runs the setup.rb script" do
|
20
|
-
Stairs::Script.should_receive(:new).with("setup.rb").and_return(script_double)
|
22
|
+
it "runs all groups in the setup.rb script" do
|
23
|
+
Stairs::Script.should_receive(:new).with("setup.rb", groups).and_return(script_double)
|
21
24
|
script_double.should_receive(:run!)
|
22
25
|
|
23
26
|
subject.run!
|
24
27
|
end
|
28
|
+
|
29
|
+
context "with groups provided" do
|
30
|
+
let(:groups) { [:reset] }
|
31
|
+
|
32
|
+
it "passes the specified groups to the script" do
|
33
|
+
Stairs::Script.should_receive(:new).with("setup.rb", groups)
|
34
|
+
subject.run!
|
35
|
+
end
|
36
|
+
end
|
25
37
|
end
|
26
38
|
end
|
@@ -2,7 +2,9 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Stairs::Script do
|
4
4
|
let(:filename) { "setup.rb" }
|
5
|
-
|
5
|
+
let(:groups) { [:reset] }
|
6
|
+
subject { described_class.new(filename, groups) }
|
7
|
+
|
6
8
|
|
7
9
|
context "with a script present" do
|
8
10
|
before do
|
@@ -13,12 +15,23 @@ describe Stairs::Script do
|
|
13
15
|
|
14
16
|
after { File.delete(filename) }
|
15
17
|
|
18
|
+
describe "initialize" do
|
19
|
+
it "receives groups" do
|
20
|
+
expect { described_class.new(filename, groups) }.not_to raise_error
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
16
24
|
describe "#run!" do
|
17
25
|
it "outputs running message" do
|
18
26
|
output = capture_stdout { subject.run! }
|
19
27
|
expect(output).to include "= Running script setup.rb"
|
20
28
|
end
|
21
29
|
|
30
|
+
it "passes groups to the new instance of Step" do
|
31
|
+
Stairs::Step.should_receive(:new).with(groups)
|
32
|
+
subject.run!
|
33
|
+
end
|
34
|
+
|
22
35
|
it "evaluates the script in the context of an instance of Step" do
|
23
36
|
# because our test setup.rb only contains `self.class` we can check
|
24
37
|
# this way:
|
@@ -26,4 +39,4 @@ describe Stairs::Script do
|
|
26
39
|
end
|
27
40
|
end
|
28
41
|
end
|
29
|
-
end
|
42
|
+
end
|
@@ -2,7 +2,8 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Stairs::Step do
|
4
4
|
let(:anon_step) { Class.new(described_class) }
|
5
|
-
|
5
|
+
let(:groups) { nil }
|
6
|
+
subject { anon_step.new(groups) }
|
6
7
|
|
7
8
|
describe "metadata" do
|
8
9
|
describe "step_title" do
|
@@ -42,21 +43,27 @@ describe Stairs::Step do
|
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
45
|
-
describe "
|
46
|
-
describe "
|
47
|
-
|
48
|
-
|
46
|
+
describe "#initialize" do
|
47
|
+
describe "options" do
|
48
|
+
describe "default options" do
|
49
|
+
it "is required" do
|
50
|
+
expect(subject.options[:required]).to be_true
|
51
|
+
end
|
49
52
|
end
|
50
|
-
end
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
|
54
|
+
context "with options" do
|
55
|
+
let(:options) { { something: "cool" } }
|
56
|
+
subject { anon_step.new(options) }
|
55
57
|
|
56
|
-
|
57
|
-
|
58
|
+
it "exposes options on the instance" do
|
59
|
+
expect(subject.options[:something]).to eq "cool"
|
60
|
+
end
|
58
61
|
end
|
59
62
|
end
|
63
|
+
|
64
|
+
it "exposes supplied groups on the instance" do
|
65
|
+
expect(subject.groups).to eq groups
|
66
|
+
end
|
60
67
|
end
|
61
68
|
|
62
69
|
describe "#run!" do
|
@@ -314,18 +321,23 @@ describe Stairs::Step do
|
|
314
321
|
|
315
322
|
context "with a valid step_name" do
|
316
323
|
let!(:mock_step_class) { Stairs::Steps::MockStep = Class.new(Stairs::Step) }
|
324
|
+
before { mock_step_class.any_instance.stub run!: true }
|
317
325
|
|
318
326
|
it "instantiates and runs the step" do
|
319
327
|
mock_step_class.any_instance.should_receive(:run!)
|
320
328
|
subject.setup :mock_step
|
321
329
|
end
|
322
330
|
|
331
|
+
it "passes groups to the step" do
|
332
|
+
mock_step_class.should_receive(:new).with(groups, {}).and_call_original
|
333
|
+
subject.setup :mock_step
|
334
|
+
end
|
335
|
+
|
323
336
|
context "with options" do
|
324
337
|
let(:options) { { something: "cool" } }
|
325
|
-
before { mock_step_class.any_instance.stub run!: true }
|
326
338
|
|
327
339
|
it "passes options to the step" do
|
328
|
-
mock_step_class.should_receive(:new).with(options).and_call_original
|
340
|
+
mock_step_class.should_receive(:new).with(groups, options).and_call_original
|
329
341
|
subject.setup :mock_step, options
|
330
342
|
end
|
331
343
|
end
|
@@ -336,6 +348,12 @@ describe Stairs::Step do
|
|
336
348
|
subject.setup(:custom_step) { puts "I'm running in #{self.class}" }
|
337
349
|
end
|
338
350
|
|
351
|
+
# Initialize primary subject before asserting against #new for the Step
|
352
|
+
# it initializes
|
353
|
+
def initialize_primary_subject
|
354
|
+
instance = subject
|
355
|
+
end
|
356
|
+
|
339
357
|
it "sets the new step's title to a titleized version of step_name" do
|
340
358
|
output = capture_stdout { call_method }
|
341
359
|
expect(output).to include "Custom Step"
|
@@ -346,17 +364,52 @@ describe Stairs::Step do
|
|
346
364
|
expect(output).to include "I'm running in Stairs::Step"
|
347
365
|
end
|
348
366
|
|
367
|
+
it "passes groups to the step" do
|
368
|
+
initialize_primary_subject
|
369
|
+
|
370
|
+
described_class.should_receive(:new).with(groups, {}).and_call_original
|
371
|
+
call_method
|
372
|
+
end
|
373
|
+
|
349
374
|
context "with options" do
|
350
375
|
let(:options) { { something: "cool" } }
|
351
376
|
before { described_class.any_instance.stub run!: true }
|
352
377
|
|
353
378
|
it "passes options to the step" do
|
354
|
-
|
379
|
+
initialize_primary_subject
|
355
380
|
|
356
|
-
described_class.should_receive(:new).with(options).and_call_original
|
381
|
+
described_class.should_receive(:new).with(groups, options).and_call_original
|
357
382
|
subject.setup(:custom_step, options) { true }
|
358
383
|
end
|
359
384
|
end
|
360
385
|
end
|
361
386
|
end
|
387
|
+
|
388
|
+
describe "#group" do
|
389
|
+
let(:name) { :reset }
|
390
|
+
|
391
|
+
context "when the name is in the groups to run" do
|
392
|
+
let(:groups) { [:reset, :init] }
|
393
|
+
|
394
|
+
it "calls the supplied block" do
|
395
|
+
expect { |b| subject.group(name, &b) }.to yield_control
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
context "when the name is not in the groups to run" do
|
400
|
+
let(:groups) { [:init] }
|
401
|
+
|
402
|
+
it "does not call the supplied block" do
|
403
|
+
expect { |b| subject.group(name, &b) }.not_to yield_control
|
404
|
+
end
|
405
|
+
|
406
|
+
context "but no groups to run are provided" do
|
407
|
+
let(:groups) { nil }
|
408
|
+
|
409
|
+
it "calls the supplied block" do
|
410
|
+
expect { |b| subject.group(name, &b) }.to yield_control
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
362
415
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stairs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- patbenatar
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-12-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|