stairs 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5757c8d2dd7a6f123729557b5ccf99f292f75a9f
4
- data.tar.gz: 1a208a280bc33d113efc36aadc00e07213931887
3
+ metadata.gz: cb094a690ad438125715b25683b2d11f176432ed
4
+ data.tar.gz: d3eb3604d83427287293ecac50daf8ed6a5ea841
5
5
  SHA512:
6
- metadata.gz: 52a26152b30d4289ac3e73b49dd33ade9ccf9270df0e6b2802f230966a223b3df34902d6cfe07efd9b9962d6b1d33c7aec51fbc13fa89874ea14c204ed5f3ddd
7
- data.tar.gz: 0f39e7ab93a8335c98c7a4e1cc186882c6ba49c8c92ad5698c97aac57eeb9bc75e9c622196e97af35cf864a5428eb387873c8392e25f8f313f97c020aca86978
6
+ metadata.gz: 54186ff0a046b2dcbe68fb116a6915ffb7cc350105c0e633e62ff05d37460f705a2c08334c542195ddc1a7b1cfdfb14613aaf60e18f2839f5a7d66d3b381f07c
7
+ data.tar.gz: 6c5e729f8a7e3b8df3c5f5b0fe9c20264c9b95e688ba43e435f747cafade1426084cb81029ea59f3b3f3ad570154c43c68b3ac990589bf9d00b4c4e3e343cac4
data/.rubocop.yml CHANGED
@@ -32,6 +32,10 @@ SpecialGlobalVars:
32
32
  CollectionMethods:
33
33
  Enabled: false
34
34
 
35
+ # Cuz we don't use any fancy characters anyway
36
+ Encoding:
37
+ Enabled: false
38
+
35
39
  # I just don't care so much about clean specs.. Like short methods and short lines
36
40
  AllCops:
37
41
  Excludes:
data/Guardfile CHANGED
@@ -5,6 +5,6 @@ guard "rspec" do
5
5
  end
6
6
 
7
7
  guard :rubocop do
8
- watch(%r{.+\.rb$})
8
+ watch(%r{^lib/(.+)\.rb$})
9
9
  watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
10
10
  end
data/README.md CHANGED
@@ -43,8 +43,7 @@ $ rake newb
43
43
 
44
44
  ## Defining scripts
45
45
 
46
- A script composes many steps that setup a project. __Note:__ optional steps are
47
- not yet implemented.
46
+ A script composes many steps that setup a project.
48
47
 
49
48
  ```ruby
50
49
  bundle
@@ -55,7 +54,7 @@ setup :s3
55
54
  setup :zencoder, required: false
56
55
 
57
56
  setup :misc do
58
- env "CHECK_IT", provide "Cool check it value"
57
+ env "CHECK_IT", provide("Cool check it value")
59
58
  end
60
59
 
61
60
  rake "db:setup"
@@ -65,38 +64,30 @@ finish "Just run rails s and sidekiq to get rolling!"
65
64
 
66
65
  ### Example CLI
67
66
 
68
- Given the above script, the CLI might look like this. __Note:__ some of this
69
- is desired future functionality (bundle/db tasks, spacing, last words).
67
+ Given the above script, the CLI might look like this.
70
68
 
71
69
  ```
72
70
  $ rake newb
73
71
  Looks like you're using rbenv to manage environment variables. Is this correct? (Y/N): Y
74
-
75
72
  = Running script setup.rb
76
-
77
73
  == Running bundle
78
74
  ...
79
75
  == Completed bundle
80
-
81
76
  == Running S3
82
77
  AWS access key: 39u39d9u291
83
78
  AWS secret: 19jd920i10is0i01i0s01ks0kfknkje
84
79
  Do you have an existing bucket? (Y/N): Y
85
80
  Bucket name (leave blank for app-dev): my-cool-bucket
86
81
  == Completed S3
87
-
88
82
  == Starting Zencoder
89
83
  This step is optional, would you like to perform it? (Y/N): N
90
84
  == Completed Zencoder
91
-
92
85
  == Starting Misc
93
86
  Cool check it value: w00t
94
87
  == Completed Misc
95
-
96
88
  == Running db:setup
97
89
  ...
98
90
  == Completed db:setup
99
-
100
91
  == All done!
101
92
  Run rails s and sidekiq to get rolling!
102
93
  ```
@@ -106,7 +97,7 @@ Run rails s and sidekiq to get rolling!
106
97
  ### Collecting values
107
98
  ```ruby
108
99
  value = provide "Something"
109
- value = provide "Another", required: false # Not fully implemented
100
+ value = provide "Another", required: false
110
101
  provide "More", default: "a-default"
111
102
  ```
112
103
 
@@ -158,6 +149,7 @@ end
158
149
  #### Using predefined steps (aka plugins)
159
150
  ```ruby
160
151
  setup :s3
152
+ setup :facebook, required: false
161
153
  ```
162
154
 
163
155
  ## Plugins for common setups
@@ -175,9 +167,9 @@ setup :s3
175
167
 
176
168
  ### Defining custom plugins
177
169
 
178
- Steps inherit from `Stairs::Step`, have a title, description, and
179
- implement the `run` method. See those included and in the various
180
- extension gems for examples.
170
+ Steps inherit from `Stairs::Step` and live in `Stairs::Steps`, have a title,
171
+ description, and implement the `run` method. See those included and in the
172
+ various extension gems for examples.
181
173
 
182
174
  ## Contributing
183
175
 
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
1
  require "bundler/gem_tasks"
2
-
3
2
  require "rspec/core/rake_task"
3
+ require "rubocop/rake_task"
4
4
 
5
5
  RSpec::Core::RakeTask.new(:spec)
6
- task default: :spec
6
+ Rubocop::RakeTask.new
7
+
8
+ task default: [:spec, :rubocop]
@@ -12,6 +12,10 @@ module Stairs
12
12
  ".env",
13
13
  )
14
14
  end
15
+
16
+ def unset(name)
17
+ Util::FileMutation.remove Regexp.new("^#{name}=(.*)\n"), ".env"
18
+ end
15
19
  end
16
20
  end
17
21
  end
@@ -13,6 +13,10 @@ module Stairs
13
13
  ".rbenv-vars",
14
14
  )
15
15
  end
16
+
17
+ def unset(name)
18
+ Util::FileMutation.remove Regexp.new("^#{name}=(.*)\n"), ".rbenv-vars"
19
+ end
16
20
  end
17
21
  end
18
22
  end
@@ -13,6 +13,10 @@ module Stairs
13
13
  ".rvmrc",
14
14
  )
15
15
  end
16
+
17
+ def unset(name)
18
+ Util::FileMutation.remove Regexp.new("^export #{name}=(.*)\n"), ".rvmrc"
19
+ end
16
20
  end
17
21
  end
18
22
  end
data/lib/stairs/step.rb CHANGED
@@ -1,8 +1,14 @@
1
1
  module Stairs
2
2
  class Step
3
+ attr_reader :options
4
+
5
+ def initialize(options={})
6
+ @options = options.reverse_merge required: true
7
+ end
8
+
3
9
  def run!
4
10
  stairs_info "== Running #{step_title}"
5
- run
11
+ run if run_step?
6
12
  stairs_info "== Completed #{step_title}"
7
13
  end
8
14
 
@@ -58,7 +64,12 @@ module Stairs
58
64
  # Set or update env var
59
65
  def env(name, value)
60
66
  ENV[name] = value
61
- Stairs.configuration.env_adapter.set name, value
67
+
68
+ if value
69
+ Stairs.configuration.env_adapter.set name, value
70
+ else
71
+ Stairs.configuration.env_adapter.unset name
72
+ end
62
73
  end
63
74
 
64
75
  # Replace contents of file
@@ -74,15 +85,15 @@ module Stairs
74
85
  # Embed a step where step_name is a symbol that can be resolved to a class
75
86
  # in Stairs::Steps or a block is provided to be executed in an instance
76
87
  # of Step
77
- def setup(step_name, &block)
88
+ def setup(step_name, options={}, &block)
78
89
  if block_given?
79
- Step.new.tap do |step|
90
+ Step.new(options).tap do |step|
80
91
  step.define_singleton_method :run, &block
81
92
  step.step_title = step_name.to_s.titleize
82
93
  end.run!
83
94
  else
84
95
  klass = "Stairs::Steps::#{step_name.to_s.camelize}".constantize
85
- klass.new.run!
96
+ klass.new(options).run!
86
97
  end
87
98
  end
88
99
 
@@ -97,6 +108,11 @@ module Stairs
97
108
 
98
109
  private
99
110
 
111
+ def run_step?
112
+ return true if options[:required]
113
+ choice "This step is optional, would you like to perform it?"
114
+ end
115
+
100
116
  class Choice
101
117
  # TODO: shouldn't care about case?
102
118
  def initialize(question, choices=%w[Y N], &block)
@@ -5,7 +5,7 @@ module Stairs
5
5
  def replace_or_append(pattern, string, filename)
6
6
  if File.exists? filename
7
7
  contents = File.read filename
8
- if contents.index pattern
8
+ if contents =~ pattern
9
9
  contents.sub! pattern, string
10
10
  write contents, filename
11
11
  return
@@ -15,11 +15,21 @@ module Stairs
15
15
  write_line string, filename
16
16
  end
17
17
 
18
+ def remove(pattern, filename)
19
+ return unless File.exists? filename
20
+
21
+ contents = File.read filename
22
+ if contents =~ pattern
23
+ contents.slice!(pattern)
24
+ write contents, filename
25
+ end
26
+ end
27
+
18
28
  def write_line(string, filename)
19
29
  File.open filename, "a+" do |file|
20
30
  # ensure file ends with newline before appending
21
31
  last_line = file.each_line.reduce("") { |m, l| m = l }
22
- file.puts "" unless last_line.index /(.*)\n/
32
+ file.puts "" unless last_line == "" || last_line =~ /(.*)\n/
23
33
 
24
34
  file.puts string
25
35
  end
@@ -1,3 +1,3 @@
1
1
  module Stairs
2
- VERSION = "0.4.0"
2
+ VERSION = "0.4.1"
3
3
  end
@@ -35,4 +35,14 @@ describe Stairs::EnvAdapters::Dotenv do
35
35
  subject.set(name, value)
36
36
  end
37
37
  end
38
- end
38
+
39
+ describe "#unset" do
40
+ it "delegates to the well tested FileMutation util" do
41
+ Stairs::Util::FileMutation.should_receive(:remove).with(
42
+ Regexp.new("^SOMETHING=(.*)\n"),
43
+ ".env",
44
+ )
45
+ subject.unset "SOMETHING"
46
+ end
47
+ end
48
+ end
@@ -37,4 +37,14 @@ describe Stairs::EnvAdapters::Rbenv do
37
37
  subject.set(name, value)
38
38
  end
39
39
  end
40
- end
40
+
41
+ describe "#unset" do
42
+ it "delegates to the well tested FileMutation util" do
43
+ Stairs::Util::FileMutation.should_receive(:remove).with(
44
+ Regexp.new("^SOMETHING=(.*)\n"),
45
+ ".rbenv-vars",
46
+ )
47
+ subject.unset "SOMETHING"
48
+ end
49
+ end
50
+ end
@@ -37,4 +37,14 @@ describe Stairs::EnvAdapters::RVM do
37
37
  subject.set(name, value)
38
38
  end
39
39
  end
40
- end
40
+
41
+ describe "#unset" do
42
+ it "delegates to the well tested FileMutation util" do
43
+ Stairs::Util::FileMutation.should_receive(:remove).with(
44
+ Regexp.new("^export SOMETHING=(.*)\n"),
45
+ ".rvmrc",
46
+ )
47
+ subject.unset "SOMETHING"
48
+ end
49
+ end
50
+ end
@@ -42,6 +42,23 @@ describe Stairs::Step do
42
42
  end
43
43
  end
44
44
 
45
+ describe "options" do
46
+ describe "default options" do
47
+ it "is required" do
48
+ expect(subject.options[:required]).to be_true
49
+ end
50
+ end
51
+
52
+ context "with options" do
53
+ let(:options) { { something: "cool" } }
54
+ subject { anon_step.new(options) }
55
+
56
+ it "exposes options on the instance" do
57
+ expect(subject.options[:something]).to eq "cool"
58
+ end
59
+ end
60
+ end
61
+
45
62
  describe "#run!" do
46
63
  before { subject.stub run: true }
47
64
  before { anon_step.title "Step Name" }
@@ -60,6 +77,30 @@ describe Stairs::Step do
60
77
  output = capture_stdout { subject.run! }
61
78
  expect(output).to include "== Completed Step Name"
62
79
  end
80
+
81
+ context "when the step is not required" do
82
+ subject { anon_step.new required: false }
83
+ before { subject.stub run: true }
84
+
85
+ it "prompts the user to decide if we should run the step" do
86
+ output = follow_prompts("Y") { subject.run! }
87
+ expect(output).to include "This step is optional, would you like to perform it? (Y/N): "
88
+ end
89
+
90
+ context "user says yes" do
91
+ it "runs the step" do
92
+ subject.should_receive :run
93
+ follow_prompts("Y") { subject.run! }
94
+ end
95
+ end
96
+
97
+ context "user says no" do
98
+ it "doesn't run the step" do
99
+ subject.should_not_receive :run
100
+ follow_prompts("N") { subject.run! }
101
+ end
102
+ end
103
+ end
63
104
  end
64
105
 
65
106
  describe "#provide" do
@@ -214,7 +255,7 @@ describe Stairs::Step do
214
255
  let(:adapter) { double("adapter", set: true) }
215
256
  before { Stairs.configuration.env_adapter = adapter }
216
257
 
217
- it "delegates to the adapter" do
258
+ it "delegates to the adapter's set" do
218
259
  adapter.should_receive(:set).with("NAME", "value")
219
260
  subject.env "NAME", "value"
220
261
  end
@@ -223,6 +264,13 @@ describe Stairs::Step do
223
264
  ENV.should_receive(:[]=).with("NAME", "value")
224
265
  subject.env "NAME", "value"
225
266
  end
267
+
268
+ context "with no value" do
269
+ it "delegates to the adapter's unset" do
270
+ adapter.should_receive(:unset).with("NAME")
271
+ subject.env "NAME", nil
272
+ end
273
+ end
226
274
  end
227
275
 
228
276
  describe "#write" do
@@ -272,6 +320,16 @@ describe Stairs::Step do
272
320
  mock_step_class.any_instance.should_receive(:run!)
273
321
  subject.setup :mock_step
274
322
  end
323
+
324
+ context "with options" do
325
+ let(:options) { { something: "cool" } }
326
+ before { mock_step_class.any_instance.stub run!: true }
327
+
328
+ it "passes options to the step" do
329
+ mock_step_class.should_receive(:new).with(options).and_call_original
330
+ subject.setup :mock_step, options
331
+ end
332
+ end
275
333
  end
276
334
 
277
335
  context "with a block" do
@@ -288,6 +346,18 @@ describe Stairs::Step do
288
346
  output = capture_stdout { call_method }
289
347
  expect(output).to include "I'm running in Stairs::Step"
290
348
  end
349
+
350
+ context "with options" do
351
+ let(:options) { { something: "cool" } }
352
+ before { described_class.any_instance.stub run!: true }
353
+
354
+ it "passes options to the step" do
355
+ instance = subject # Initialize class before asserting against #new
356
+
357
+ described_class.should_receive(:new).with(options).and_call_original
358
+ subject.setup(:custom_step, options) { true }
359
+ end
360
+ end
291
361
  end
292
362
  end
293
- end
363
+ end
@@ -35,6 +35,41 @@ describe Stairs::Util::FileMutation do
35
35
  end
36
36
  end
37
37
 
38
+ describe ".remove" do
39
+ before do
40
+ File.open(filename, "w") do |file|
41
+ file.write "VAR_1=hey\nVAR_2=hello\nVAR_3=hi\n"
42
+ end
43
+ end
44
+
45
+ context "when the pattern exists in file" do
46
+ it "removes the match from the file" do
47
+ subject.remove /^VAR_2=(.*)\n/, filename
48
+ expect(File.read(filename)).to eq "VAR_1=hey\nVAR_3=hi\n"
49
+ end
50
+
51
+ context "and is the last line without a trailing newline" do
52
+ before do
53
+ File.open(filename, "w+") do |file|
54
+ file.write "VAR_1=hey\nVAR_2=hello\nVAR_3=hi"
55
+ end
56
+
57
+ it "still matches and removes it" do
58
+ subject.remove /^VAR_3=(.*)\n/, filename
59
+ expect(File.read(filename)).to eq "VAR_1=hey\nVAR_2=hello\n"
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ context "when the pattern does not exist in file" do
66
+ it "leaves the file untouched" do
67
+ subject.remove /^VAR_2=(.*)\n/, filename
68
+ expect(File.read(filename)).to eq "VAR_1=hey\nVAR_3=hi\n"
69
+ end
70
+ end
71
+ end
72
+
38
73
  describe ".write_line" do
39
74
  before do
40
75
  File.open(filename, "w") do |file|
@@ -51,9 +86,7 @@ describe Stairs::Util::FileMutation do
51
86
 
52
87
  context "when there is no newline at the bottom" do
53
88
  before do
54
- File.delete(filename) if File.exists?(filename)
55
-
56
- File.open(filename, "w") do |file|
89
+ File.open(filename, "w+") do |file|
57
90
  file.write("line1\nline2")
58
91
  end
59
92
  end
@@ -63,6 +96,19 @@ describe Stairs::Util::FileMutation do
63
96
  expect(File.read(filename)).to eq "line1\nline2\nline3\n"
64
97
  end
65
98
  end
99
+
100
+ context "when the file is empty" do
101
+ before do
102
+ File.open filename, "w+" do |file|
103
+ file.write ""
104
+ end
105
+ end
106
+
107
+ it "writes to the first line of the line" do
108
+ described_class.write_line "line1", filename
109
+ expect(File.read(filename)).to eq "line1\n"
110
+ end
111
+ end
66
112
  end
67
113
 
68
114
  describe ".write" do
@@ -95,4 +141,4 @@ describe Stairs::Util::FileMutation do
95
141
  end
96
142
  end
97
143
  end
98
- end
144
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stairs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - patbenatar