stairs 0.4.0 → 0.4.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.
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