stairs 0.6.1 → 0.7.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 33b582fd2fb33082959934152985b5fde210cb23
4
- data.tar.gz: 283a59e20d7e5eb6730553b305f1632a58723789
3
+ metadata.gz: d00a852f658b8f3191f7ae6c5f7edf56823ecc38
4
+ data.tar.gz: 424bc1126fe1cb6757b735a3b72a95032e225518
5
5
  SHA512:
6
- metadata.gz: 79a9879b665d47712c18bd84622f896f99d3ac78ae247c0a7daf841463ec6e29dac0d523847c02593780e440a249cc36285af8eb8fd364aa7499eadfb2e0f58c
7
- data.tar.gz: add58a9fd0211cc3ff9518805b6f474043848f37af26e793bbebb5c1021c2fe9a9fb1d8e3d7c3920f13005429c016b065296f672f786d95154bfe09154d18abf
6
+ metadata.gz: 4b7faabcf3e3168c77a3e3afb2d9da5d1cdb020ab71dd4f8a3a90870e4605b39ef37f496e5243e05fb26f4b7cb53a0d6af87d6ea939474892efeb64faefbf59e
7
+ data.tar.gz: 53e273c0bf8ed61bc395cae6b366e9d9e32f12f54741f021dbf3dff5d6a645ae93e7d092156a079746d46abee344fea28b87622247281b330f5cd8359283b427
data/.rubocop.yml CHANGED
@@ -8,10 +8,6 @@ LineLength:
8
8
  CaseIndentation:
9
9
  Enabled: false
10
10
 
11
- # This was offending when it shouldn't have been, like in util/file_mutation:21
12
- UselessAssignment:
13
- Enabled: false
14
-
15
11
  # Seems unnecessary?
16
12
  ReduceArguments:
17
13
  Enabled: false
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
- ## Usage
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 env vars
103
- Stairs currently supports writing environment variables for rbenv-vars, RVM, and dotenv.
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
- ### Defining setup steps
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
- ## Plugins for common setups
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(options={})
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
@@ -7,7 +7,7 @@ module Stairs
7
7
  def install!
8
8
  desc "Setup the project"
9
9
  task :newb do
10
- Stairs::Runner.new.run!
10
+ Stairs::Runner.new([:newb]).run!
11
11
  end
12
12
  end
13
13
  end
@@ -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| 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
@@ -1,3 +1,3 @@
1
1
  module Stairs
2
- VERSION = "0.6.1"
2
+ VERSION = "0.7.0"
3
3
  end
@@ -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
- subject { described_class.new(filename) }
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
- subject { anon_step.new }
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 "options" do
46
- describe "default options" do
47
- it "is required" do
48
- expect(subject.options[:required]).to be_true
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
- context "with options" do
53
- let(:options) { { something: "cool" } }
54
- subject { anon_step.new(options) }
54
+ context "with options" do
55
+ let(:options) { { something: "cool" } }
56
+ subject { anon_step.new(options) }
55
57
 
56
- it "exposes options on the instance" do
57
- expect(subject.options[:something]).to eq "cool"
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
- instance = subject # Initialize class before asserting against #new
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.6.1
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-27 00:00:00.000000000 Z
11
+ date: 2013-12-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler