webbynode 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of webbynode might be problematic. Click here for more details.

Files changed (98) hide show
  1. data/Manifest +88 -4
  2. data/PostInstall.txt +42 -9
  3. data/README.rdoc +6 -0
  4. data/Rakefile +16 -19
  5. data/assets/webbynode.png +0 -0
  6. data/bin/webbynode +3 -3
  7. data/bin/wn +7 -0
  8. data/cucumber.yml +1 -0
  9. data/devver.rake +174 -0
  10. data/features/bootstrap.feature +17 -0
  11. data/features/step_definitions/command_steps.rb +14 -0
  12. data/features/support/env.rb +22 -0
  13. data/features/support/hooks.rb +8 -0
  14. data/{test/test_webbynode.rb → features/support/io_features.rb} +0 -0
  15. data/features/support/mocha.rb +15 -0
  16. data/lib/templates/api_token +14 -0
  17. data/lib/templates/backup +15 -0
  18. data/lib/templates/gitignore +4 -0
  19. data/lib/templates/help +53 -0
  20. data/lib/webbynode/api_client.rb +121 -0
  21. data/lib/webbynode/application.rb +21 -0
  22. data/lib/webbynode/command.rb +332 -0
  23. data/lib/webbynode/commands/add_backup.rb +33 -0
  24. data/lib/webbynode/commands/add_key.rb +24 -0
  25. data/lib/webbynode/commands/alias.rb +153 -0
  26. data/lib/webbynode/commands/change_dns.rb +29 -0
  27. data/lib/webbynode/commands/config.rb +15 -0
  28. data/lib/webbynode/commands/delete.rb +25 -0
  29. data/lib/webbynode/commands/help.rb +25 -0
  30. data/lib/webbynode/commands/init.rb +77 -0
  31. data/lib/webbynode/commands/push.rb +70 -0
  32. data/lib/webbynode/commands/remote.rb +28 -0
  33. data/lib/webbynode/commands/restart.rb +25 -0
  34. data/lib/webbynode/commands/start.rb +23 -0
  35. data/lib/webbynode/commands/stop.rb +23 -0
  36. data/lib/webbynode/commands/tasks.rb +149 -0
  37. data/lib/webbynode/commands/version.rb +8 -0
  38. data/lib/webbynode/commands/webbies.rb +30 -0
  39. data/lib/webbynode/git.rb +112 -0
  40. data/lib/webbynode/io.rb +175 -0
  41. data/lib/webbynode/notify.rb +19 -0
  42. data/lib/webbynode/option.rb +84 -0
  43. data/lib/webbynode/parameter.rb +27 -0
  44. data/lib/webbynode/properties.rb +43 -0
  45. data/lib/webbynode/push_and.rb +16 -0
  46. data/lib/webbynode/remote_executor.rb +21 -0
  47. data/lib/webbynode/server.rb +39 -0
  48. data/lib/webbynode/ssh.rb +65 -0
  49. data/lib/webbynode/ssh_keys.rb +36 -0
  50. data/lib/webbynode.rb +56 -0
  51. data/spec/fixtures/aliases +0 -0
  52. data/spec/fixtures/api/credentials +3 -0
  53. data/spec/fixtures/api/dns +30 -0
  54. data/spec/fixtures/api/dns_a_record +20 -0
  55. data/spec/fixtures/api/dns_a_record_already_exists +15 -0
  56. data/spec/fixtures/api/dns_a_record_error +13 -0
  57. data/spec/fixtures/api/dns_new_zone +17 -0
  58. data/spec/fixtures/api/webbies +26 -0
  59. data/spec/fixtures/api/webbies_unauthorized +12 -0
  60. data/spec/fixtures/api/webby +6 -0
  61. data/spec/fixtures/commands/tasks/after_push +3 -0
  62. data/spec/fixtures/fixture_helpers +2 -0
  63. data/spec/fixtures/git/config/210.11.13.12 +9 -0
  64. data/spec/fixtures/git/config/67.23.79.31 +9 -0
  65. data/spec/fixtures/git/config/67.23.79.32 +9 -0
  66. data/spec/fixtures/git/config/config +9 -0
  67. data/spec/fixtures/git/status/clean +2 -0
  68. data/spec/fixtures/git/status/dirty +9 -0
  69. data/spec/fixtures/pushand +2 -0
  70. data/spec/spec_helper.rb +58 -0
  71. data/spec/webbynode/api_client_spec.rb +227 -0
  72. data/spec/webbynode/application_spec.rb +50 -0
  73. data/spec/webbynode/command_spec.rb +285 -0
  74. data/spec/webbynode/commands/add_backup_spec.rb +66 -0
  75. data/spec/webbynode/commands/add_key_spec.rb +58 -0
  76. data/spec/webbynode/commands/alias_spec.rb +213 -0
  77. data/spec/webbynode/commands/change_dns_spec.rb +51 -0
  78. data/spec/webbynode/commands/config_spec.rb +22 -0
  79. data/spec/webbynode/commands/delete_spec.rb +78 -0
  80. data/spec/webbynode/commands/help_spec.rb +43 -0
  81. data/spec/webbynode/commands/init_spec.rb +326 -0
  82. data/spec/webbynode/commands/push_spec.rb +175 -0
  83. data/spec/webbynode/commands/remote_spec.rb +76 -0
  84. data/spec/webbynode/commands/tasks_spec.rb +288 -0
  85. data/spec/webbynode/commands/version_spec.rb +18 -0
  86. data/spec/webbynode/commands/webbies_spec.rb +27 -0
  87. data/spec/webbynode/git_spec.rb +310 -0
  88. data/spec/webbynode/io_spec.rb +198 -0
  89. data/spec/webbynode/option_spec.rb +48 -0
  90. data/spec/webbynode/parameter_spec.rb +70 -0
  91. data/spec/webbynode/push_and_spec.rb +28 -0
  92. data/spec/webbynode/remote_executor_spec.rb +25 -0
  93. data/spec/webbynode/server_spec.rb +101 -0
  94. data/webbynode.gemspec +25 -16
  95. metadata +182 -14
  96. data/lib/wn.rb +0 -106
  97. data/test/test_helper.rb +0 -9
  98. data/test/test_wn.rb +0 -220
@@ -0,0 +1,285 @@
1
+ # Load Spec Helper
2
+ require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'spec_helper')
3
+
4
+ describe Webbynode::Command do
5
+ let(:re) { double("RemoteExecutor").as_null_object }
6
+ let(:git) { double("Git").as_null_object }
7
+ let(:pushand) { double("Pushand").as_null_object }
8
+ let(:server) { double("Server").as_null_object }
9
+ let(:ssh) { double("SSh").as_null_object }
10
+ let(:io) { double("Io").as_null_object }
11
+
12
+ describe "resolving commands" do
13
+ it "should allow adding aliases to child classes" do
14
+ class Zap < Webbynode::Command
15
+ add_alias "zip"
16
+ end
17
+
18
+ Webbynode::Commands.should_receive(:const_get).with("Zap")
19
+ Webbynode::Command.for("zip")
20
+ end
21
+
22
+ it "should look for a class with the name of the command" do
23
+ Webbynode::Commands.should_receive(:const_get).with("Zap")
24
+ Webbynode::Command.for("zap")
25
+ end
26
+
27
+ context "when class exists" do
28
+ it "should translate words separated by underscore into capitalized parts" do
29
+ Webbynode::Commands.should_receive(:const_get).with("RandomThoughtsIHad")
30
+ Webbynode::Command.for("random_thoughts_i_had")
31
+ end
32
+ end
33
+ end
34
+
35
+ describe "#command" do
36
+ it "should return the string representation of the command" do
37
+ AwfulCommand = Class.new(Webbynode::Command)
38
+ AwfulCommand.command.should == "awful_command"
39
+ Amazing = Class.new(Webbynode::Command)
40
+ Amazing.command.should == "amazing"
41
+ SomeStrangeStuff = Class.new(Webbynode::Command)
42
+ SomeStrangeStuff.command.should == "some_strange_stuff"
43
+ end
44
+ end
45
+
46
+ describe "#run" do
47
+ class RequireInitialize < Webbynode::Command
48
+ requires_initialization!
49
+
50
+ def execute
51
+ puts "command was executed"
52
+ end
53
+ end
54
+
55
+ context "when git is missing" do
56
+ it "should provide a friendly error" do
57
+ git.should_receive(:present?).and_return(false)
58
+
59
+ command = RequireInitialize.new
60
+ command.should_receive(:remote_executor).any_number_of_times.and_return(re)
61
+ command.should_receive(:git).any_number_of_times.and_return(git)
62
+ command.should_receive(:io).any_number_of_times.and_return(io)
63
+ command.should_receive(:pushand).any_number_of_times.and_return(pushand)
64
+ command.should_receive(:server).any_number_of_times.and_return(server)
65
+ command.run
66
+
67
+ stdout.should =~ /Hello, McFly, anybody home?/
68
+ stdout.should_not =~ /command was executed/
69
+ end
70
+ end
71
+ end
72
+
73
+ describe "array of parameters" do
74
+ class ArrayCommand < Webbynode::Command
75
+ description "Initializes the current folder as a deployable application"
76
+ parameter :params, Array, "Name or IP of the Webby to deploy to"
77
+ option :passphrase, String, "If present, passphrase will be used when creating a new SSH key", :take => :words
78
+ end
79
+
80
+ it "should return an array of parameters" do
81
+ cmd = ArrayCommand.new("a", "b", "--passphrase=abc", "c", "d")
82
+ cmd.params.first.value.should == ["a", "b", "c", "d"]
83
+ cmd.option(:passphrase).should == "abc"
84
+ end
85
+ end
86
+
87
+ describe "with no params" do
88
+ class Brief < Webbynode::Command
89
+ end
90
+
91
+ it "should refuse any param" do
92
+ cmd = Brief.new("test")
93
+ cmd.run
94
+ stdout.should =~ /command 'brief' takes no parameters/
95
+ end
96
+ end
97
+
98
+ describe "help for commands" do
99
+ class NewCommand < Webbynode::Command
100
+ description "Initializes the current folder as a deployable application"
101
+ parameter :webby, String, "Name or IP of the Webby to deploy to"
102
+ parameter :dns, String, "The DNS used for this application", :required => false
103
+
104
+ option :passphrase, String, "If present, passphrase will be used when creating a new SSH key", :take => :words
105
+ end
106
+
107
+ before(:each) do
108
+ @cmd = NewCommand.new("what!")
109
+ end
110
+
111
+ it "should provide help for parameters" do
112
+ NewCommand.help.should =~ /Usage: webbynode new_command webby \[dns\] \[options\]/
113
+ NewCommand.help.should =~ /Parameters:/
114
+ NewCommand.help.should =~ / webby Name or IP of the Webby to deploy to/
115
+ NewCommand.help.should =~ / dns The DNS used for this application, optional/
116
+ NewCommand.help.should =~ /Options:/
117
+ NewCommand.help.should =~ / --passphrase=words If present, passphrase will be used when creating a new SSH key/
118
+ end
119
+
120
+ it "should show the help if --help option is passed" do
121
+ cmd = NewCommand.new("--help")
122
+ cmd.run
123
+ stdout.should =~ /Usage: webbynode new_command webby \[dns\] \[options\]/
124
+ stdout.should =~ /Parameters:/
125
+ stdout.should =~ / webby Name or IP of the Webby to deploy to/
126
+ stdout.should =~ / dns The DNS used for this application, optional/
127
+ stdout.should =~ /Options:/
128
+ stdout.should =~ / --passphrase=words If present, passphrase will be used when creating a new SSH key/
129
+ end
130
+ end
131
+
132
+ describe "parsing options" do
133
+ it "should complain about missing params and show usage" do
134
+ Sample = Class.new(Webbynode::Command)
135
+ Sample.parameter :param1, "Teste"
136
+
137
+ cmd = Sample.new
138
+ cmd.run
139
+
140
+ stdout.should =~ /Missing 'param1' parameter. Use "webbynode help sample" for more information./
141
+ stdout.should =~ /Usage: webbynode sample param1/
142
+ end
143
+
144
+ it "should report an unknown option" do
145
+ Sample99 = Class.new(Webbynode::Command)
146
+ cmd = Sample99.new("--unknown")
147
+ lambda { cmd.run }.should_not raise_error
148
+ stdout.should =~ /Unknown option: unknown/
149
+ end
150
+
151
+ it "should parse arguments as params" do
152
+ Sample1 = Class.new(Webbynode::Command)
153
+ Sample1.parameter :param1, ""
154
+ Sample1.parameter :param2, ""
155
+
156
+ cmd = Sample1.new("param1", "param2")
157
+ cmd.params.first.value.should == "param1"
158
+ cmd.params.last.value.should == "param2"
159
+ end
160
+
161
+ it "should parse arguments starting with -- as options" do
162
+ Sample2 = Class.new(Webbynode::Command)
163
+ Sample2.option :provided, ""
164
+
165
+ cmd = Sample2.new("--provided=auto")
166
+ cmd.option(:provided).should == "auto"
167
+ end
168
+
169
+ it "should parse arguments without values as true" do
170
+ Sample3 = Class.new(Webbynode::Command)
171
+ Sample3.option :force, ""
172
+
173
+ wn = Sample3.new("--force")
174
+ wn.option(:force).should be_true
175
+ end
176
+
177
+ it "should provide option names as symbols" do
178
+ Sample4 = Class.new(Webbynode::Command)
179
+ Sample4.option :provided, ""
180
+
181
+ wn = Sample4.new("--provided=auto")
182
+ wn.option(:provided).should == "auto"
183
+ end
184
+
185
+ it "should parse quoted values" do
186
+ Sample5 = Class.new(Webbynode::Command)
187
+ Sample5.option :name, ""
188
+
189
+ wn = Sample5.new("--name=\"Felipe Coury\"")
190
+ wn.option(:name).should == "Felipe Coury"
191
+ end
192
+ end
193
+
194
+ describe "parsing mixed options and parameters" do
195
+ class Cmd < Webbynode::Command
196
+ parameter :param1, String, "param1"
197
+ parameter :param2, String, "param2"
198
+ option :provided, "option1"
199
+ option :force, "option2"
200
+ end
201
+
202
+ it "should provide option names as strings and symbols" do
203
+ wn = Cmd.new("--provided=auto", "param1", "--force", "param2")
204
+ wn.option(:provided) == "auto"
205
+ wn.option(:force).should be_true
206
+ lambda { wn.option(:another) }.should raise_error(Webbynode::Command::CommandError)
207
+ wn.param_values.should == ["param1", "param2"]
208
+ end
209
+ end
210
+
211
+ describe "handling Unauthorized API errors" do
212
+ class UnauthorizedCommand < Webbynode::Command
213
+ def execute
214
+ raise Webbynode::ApiClient::Unauthorized
215
+ end
216
+ end
217
+
218
+ it "should output a friendly message" do
219
+ cmd = UnauthorizedCommand.new
220
+ cmd.run
221
+
222
+ stdout.should =~ /Your credentials didn't match any Webbynode account./
223
+ end
224
+ end
225
+
226
+ describe "parsing array parameters" do
227
+ class ArrayCmd < Webbynode::Command
228
+ parameter :param1, String, "param1"
229
+ parameter :param2, String, "param2"
230
+ parameter :param_array, Array, "array"
231
+ option :option, String, "descr"
232
+ end
233
+
234
+ it "should parse params and all remaining as the array param" do
235
+ cmd = ArrayCmd.new("param1", "param2", "arr1", "arr2", "arr3", "arr4")
236
+ cmd.param(:param1).should == "param1"
237
+ cmd.param(:param2).should == "param2"
238
+ cmd.param(:param_array).should == ["arr1", "arr2", "arr3", "arr4"]
239
+ end
240
+
241
+ it "should ignore options" do
242
+ cmd = ArrayCmd.new("param1", "param2", "--option=tough", "arr1", "arr2", "arr3", "arr4")
243
+ cmd.option(:option).should == "tough"
244
+ cmd.param(:param1).should == "param1"
245
+ cmd.param(:param2).should == "param2"
246
+ cmd.param(:param_array).should == ["arr1", "arr2", "arr3", "arr4"]
247
+ end
248
+ end
249
+
250
+ context "with a webbynode uninitialized application" do
251
+ class NewCommand < Webbynode::Command
252
+ requires_initialization!
253
+ end
254
+
255
+ before do
256
+ command.should_receive(:remote_executor).any_number_of_times.and_return(re)
257
+ command.should_receive(:git).any_number_of_times.and_return(git)
258
+ command.should_receive(:io).any_number_of_times.and_return(io)
259
+ command.should_receive(:pushand).any_number_of_times.and_return(pushand)
260
+ command.should_receive(:server).any_number_of_times.and_return(server)
261
+ end
262
+
263
+ let(:command) { NewCommand.new("some") }
264
+
265
+ it "should not have a git repository" do
266
+ git.should_receive(:present?).and_return(false)
267
+ lambda { command.validate_initialization }.should raise_error(Webbynode::Command::CommandError,
268
+ "Ahn!? Hello, McFly, anybody home?")
269
+ end
270
+
271
+ it "should not have webbynode git remote" do
272
+ git.should_receive(:remote_webbynode?).and_return(false)
273
+ lambda { command.validate_initialization }.should raise_error(Webbynode::Command::CommandError,
274
+ "Webbynode has not been initialized for this git repository.")
275
+ end
276
+
277
+ it "should not have a pushand file" do
278
+ git.should_receive(:present?).and_return(true)
279
+ io.should_receive(:directory?).with(".webbynode").and_return(true)
280
+ pushand.should_receive(:present?).and_return(false)
281
+ lambda { command.validate_initialization }.should raise_error(Webbynode::Command::CommandError,
282
+ "Could not find .pushand file, has Webbynode been initialized for this repository?")
283
+ end
284
+ end
285
+ end
@@ -0,0 +1,66 @@
1
+ # Load Spec Helper
2
+ require File.join(File.expand_path(File.dirname(__FILE__)), '../..', 'spec_helper')
3
+
4
+ describe Webbynode::Commands::AddBackup do
5
+ def tie_dependencies(cmd)
6
+ cmd.should_receive(:io).any_number_of_times.and_return(io)
7
+ cmd.should_receive(:remote_executor).any_number_of_times.and_return(re)
8
+ cmd
9
+ end
10
+
11
+ let(:io) { double("io").as_null_object }
12
+ let(:re) { double("remote_executor").as_null_object }
13
+ let(:cmd) {
14
+ cmd = Webbynode::Commands::AddBackup.new
15
+ tie_dependencies(cmd)
16
+ }
17
+
18
+ it "should allow user to specify a retention period, in days" do
19
+ io.should_receive(:app_name).and_return("app")
20
+ io.should_receive(:general_settings).any_number_of_times.and_return({ "aws_key" => "abc", "aws_secret" => "def" })
21
+ re.should_receive(:exec).with("config_app_backup").with(%Q(config_app_backup app "abc" "def" 10), true)
22
+
23
+ cmd = tie_dependencies(Webbynode::Commands::AddBackup.new("--retain=10"))
24
+ cmd.run
25
+ end
26
+
27
+ it "should ask user's aws key and secret, if missing from ~/.weebynode" do
28
+ io.should_receive(:general_settings).any_number_of_times.and_return({})
29
+
30
+ io.should_receive(:add_general_setting).with("aws_key", "aws_key")
31
+ io.should_receive(:add_general_setting).with("aws_secret", "aws_secret")
32
+
33
+ cmd.should_receive(:ask).with("AWS secret: ").and_return("aws_secret")
34
+ cmd.should_receive(:ask).with("AWS key: ").and_return("aws_key")
35
+ cmd.run
36
+ end
37
+
38
+ it "should abort the configuration if user provides a blank AWS key" do
39
+ io.should_receive(:general_settings).any_number_of_times.and_return({})
40
+
41
+ io.should_receive(:add_general_setting).never
42
+ io.should_receive(:add_general_setting).never
43
+
44
+ cmd.should_receive(:ask).with("AWS secret: ").never
45
+ cmd.should_receive(:ask).with("AWS key: ").and_return("")
46
+ cmd.run
47
+
48
+ stdout.should =~ /Aborted./
49
+ end
50
+
51
+ it "should not ask for key/secret if already present" do
52
+ io.should_receive(:general_settings).any_number_of_times.and_return({ "aws_key" => "abc", "aws_secret" => "def" })
53
+
54
+ cmd.should_receive(:ask).with("AWS secret: ").never
55
+ cmd.should_receive(:ask).with("AWS key: ").never
56
+ cmd.run
57
+ end
58
+
59
+ it "should execute the config_app_backup utility on the server" do
60
+ io.should_receive(:app_name).and_return("app_name")
61
+ io.should_receive(:general_settings).any_number_of_times.and_return({ "aws_key" => "awskey", "aws_secret" => "awsecret" })
62
+ re.should_receive(:exec).with("config_app_backup").with(%Q(config_app_backup app_name "awskey" "awsecret"), true)
63
+
64
+ cmd.run
65
+ end
66
+ end
@@ -0,0 +1,58 @@
1
+ # Load Spec Helper
2
+ require File.join(File.expand_path(File.dirname(__FILE__)), '../..', 'spec_helper')
3
+
4
+ describe Webbynode::Commands::AddKey do
5
+ let(:server) { double("server") }
6
+
7
+ it "should have a constant pointing to the ssh key location" do
8
+ Webbynode::Commands::AddKey::LocalSshKey.should == "#{ENV['HOME']}/.ssh/id_rsa.pub"
9
+ end
10
+
11
+ it "should be aliased to addkey" do
12
+ Webbynode::Commands.should_receive(:const_get).with("AddKey")
13
+ Webbynode::Command.for("addkey")
14
+ end
15
+
16
+ context "when successful" do
17
+ it "should upload the local ssh key into the server" do
18
+ server.should_receive(:add_ssh_key).with(Webbynode::Commands::AddKey::LocalSshKey, nil)
19
+
20
+ cmd = Webbynode::Commands::AddKey.new
21
+ cmd.should_receive(:server).any_number_of_times.and_return(server)
22
+ cmd.execute
23
+ end
24
+
25
+ it "should create an ssh key with a provided passphrase" do
26
+ server.should_receive(:add_ssh_key).with(Webbynode::Commands::AddKey::LocalSshKey, "my_passphrase")
27
+
28
+ cmd = Webbynode::Commands::AddKey.new("--passphrase=my_passphrase")
29
+ cmd.should_receive(:server).any_number_of_times.and_return(server)
30
+ cmd.execute
31
+ end
32
+ end
33
+
34
+ context "when unsuccessful" do
35
+ let(:cmd) { Webbynode::Commands::AddKey.new }
36
+ let(:io) { double("Io").as_null_object }
37
+
38
+ before(:each) do
39
+ cmd.should_receive(:io).any_number_of_times.and_return(io)
40
+ end
41
+
42
+ it "should report an error if the ssh key could not be added due to invalid authentication" do
43
+ server.should_receive(:add_ssh_key).and_raise(Webbynode::InvalidAuthentication)
44
+
45
+ cmd.should_receive(:server).any_number_of_times.and_return(server)
46
+ io.should_receive(:log).with("Could not connect to webby: invalid authentication.", true)
47
+ cmd.execute
48
+ end
49
+
50
+ it "should report an error if the ssh key could not be added due to a permission error" do
51
+ server.should_receive(:add_ssh_key).and_raise(Webbynode::PermissionError)
52
+
53
+ cmd.should_receive(:server).any_number_of_times.and_return(server)
54
+ io.should_receive(:log).with("Could not create an SSH key: permission error.", true)
55
+ cmd.execute
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,213 @@
1
+ # Load Spec Helper
2
+ require File.join(File.expand_path(File.dirname(__FILE__)), '../..', 'spec_helper')
3
+
4
+ describe Webbynode::Commands::Alias do
5
+
6
+ let(:a) { Webbynode::Commands::Alias.new("add", "my_alias", "ls", "-la") }
7
+ let(:io) { double('io').as_null_object }
8
+
9
+ before(:each) do
10
+ a.should_receive(:io).any_number_of_times.and_return(io)
11
+ File.stub!(:read).with(Webbynode::Commands::Alias::FilePath).
12
+ and_return(File.join(File.dirname(__FILE__), '../../fixtures/aliases'))
13
+ end
14
+
15
+ it "should have a constant pointing at the aliases file" do
16
+ Webbynode::Commands::Alias::FilePath.should eql(".webbynode/aliases")
17
+ end
18
+
19
+ describe "params" do
20
+ it "should parse the add commands" do
21
+ a = Webbynode::Commands::Alias.new("add", "my_alias", "ls", "-la")
22
+ a.stub!(:send).with("add")
23
+ a.execute
24
+ a.action.should eql("add")
25
+ a.alias.should eql("my_alias")
26
+ a.command.should eql("ls -la")
27
+ end
28
+
29
+ it "should parse the remove commands" do
30
+ a = Webbynode::Commands::Alias.new("remove", "my_alias")
31
+ a.stub!(:send).with("remove")
32
+ a.execute
33
+ a.action.should eql("remove")
34
+ a.alias.should eql("my_alias")
35
+ a.command.should be_blank
36
+ end
37
+ end
38
+
39
+ describe "#exists?" do
40
+ it "should determine whether the specified alias already exists" do
41
+ a.exists?("my_alias").should be_false
42
+ end
43
+
44
+ it "should determine whether the specified alias already exists" do
45
+ a.session_aliases << "[my_alias] rake db:migrate"
46
+ a.exists?("my_alias").should be_true
47
+ end
48
+ end
49
+
50
+ describe "#extract_command" do
51
+ it "should extract the command from the session_aliases based on the given alias if it exists" do
52
+ a = Webbynode::Commands::Alias.new
53
+ a.stub!(:read_aliases_file)
54
+ a.session_aliases << "[my_alias] rake db:migrate"
55
+ a.extract_command('my_alias').should eql("rake db:migrate")
56
+ end
57
+
58
+ it "should return false because the requested alias does not exist" do
59
+ a = Webbynode::Commands::Alias.new
60
+ a.stub!(:read_aliases_file)
61
+ a.extract_command('my_alias').should be_false
62
+ end
63
+ end
64
+
65
+ describe "aliases file availability" do
66
+ context "when the aliases file is not present" do
67
+ it "should create it" do
68
+ io.should_receive(:file_exists?).with(Webbynode::Commands::Alias::FilePath).and_return(false)
69
+ io.should_receive(:exec).with("touch #{Webbynode::Commands::Alias::FilePath}")
70
+ a.ensure_aliases_file_exists
71
+ end
72
+ end
73
+
74
+ context "when the aliases file is present" do
75
+ it "should not create it, nor overwrite it" do
76
+ io.should_receive(:file_exists?).with(Webbynode::Commands::Alias::FilePath).and_return(true)
77
+ io.should_not_receive(:exec).with("touch #{Webbynode::Commands::Alias::FilePath}")
78
+ a.ensure_aliases_file_exists
79
+ end
80
+ end
81
+ end
82
+
83
+ describe "reading out the aliases from the file" do
84
+ it "should read out each line that has an alias" do
85
+ a.should_receive(:read_aliases_file)
86
+ a.execute
87
+ end
88
+ end
89
+
90
+ describe "aliases file interaction" do
91
+ context "when writing to the file" do
92
+ it "should invoke the add method" do
93
+ a.should_receive(:send).with('add')
94
+ a.execute
95
+ end
96
+
97
+ it "should append the new alias to the session_aliases" do
98
+ a.should_receive(:append_alias)
99
+ a.execute
100
+ end
101
+
102
+ it "should open the file in 'write mode' to write all aliases from session_aliases to it" do
103
+ io.should_receive(:open_file).with(Webbynode::Commands::Alias::FilePath, "w")
104
+ a.execute
105
+ end
106
+
107
+ it "should not add the alias to session_aliases if the command is blank" do
108
+ a = Webbynode::Commands::Alias.new("add", "my_alias")
109
+ a.should_receive(:io).any_number_of_times.and_return(io)
110
+ io.should_receive(:log).with("You must provide a remote command for the alias.", true)
111
+ a.execute
112
+ a.session_aliases.size.should eql(0)
113
+ end
114
+
115
+ it "should not add the alias if it already exists" do
116
+ a = Webbynode::Commands::Alias.new("add", "my_alias", "custom command")
117
+ a.should_receive(:io).any_number_of_times.and_return(io)
118
+ a.stub!(:write_aliases)
119
+ a.stub!(:read_aliases_file)
120
+ a.session_aliases << "[my_alias] foo"
121
+ a.session_aliases << "[mah_alias] bar"
122
+ io.should_receive(:log).with("You already have an alias named [my_alias].", true)
123
+ a.execute
124
+ a.should have(2).session_aliases
125
+ end
126
+
127
+ it "should not add the alias to session_aliases if the command is blank" do
128
+ a = Webbynode::Commands::Alias.new("add", "my_alias")
129
+ a.stub!(:write_aliases)
130
+ a.execute
131
+ a.session_aliases.size.should eql(0)
132
+ end
133
+
134
+ it "should display the current list of aliases after adding the new one" do
135
+ a.should_receive(:show_aliases)
136
+ a.execute
137
+ end
138
+ end
139
+
140
+ context "when removing from the file" do
141
+ before(:each) do
142
+ a = Webbynode::Commands::Alias.new("remove", "my_alias")
143
+ a.should_receive(:io).any_number_of_times.and_return(io)
144
+ end
145
+
146
+ it "should invoke the remove method" do
147
+ a.should_receive(:send).with('remove')
148
+ a.execute
149
+ end
150
+
151
+ it "should remove the alias if it exists" do
152
+ a.should_receive(:remove_alias)
153
+ a.execute
154
+ end
155
+
156
+ it "should remove the specified alias from the array of aliases to write" do
157
+ a.stub!(:read_aliases_file)
158
+ 3.times { |n| a.session_aliases << "[alias_#{n}] my_custom_alias_#{n}" }
159
+ a.should have(3).session_aliases
160
+ a.session_aliases << "[my_alias] what a nice alias"
161
+ a.should have(4).session_aliases
162
+ a.session_aliases.should include("[my_alias] what a nice alias")
163
+ a.execute
164
+ a.session_aliases.should_not include("[my_alias] what a nice alias")
165
+ a.should have(3).session_aliases
166
+ end
167
+
168
+ it "should write to the aliases file to apply the changes" do
169
+ a.should_receive(:write_aliases)
170
+ a.execute
171
+ end
172
+
173
+ it "should display the current list of aliases after removing the old one" do
174
+ a.should_receive(:show_aliases)
175
+ a.execute
176
+ end
177
+ end
178
+
179
+ context "reading from the file" do
180
+ before(:each) do
181
+ a = Webbynode::Commands::Alias.new("show")
182
+ a.should_receive(:io).any_number_of_times.and_return(io)
183
+ end
184
+
185
+ it "should invoke the show method" do
186
+ a.should_receive(:send).with("show")
187
+ a.execute
188
+ end
189
+
190
+ it "should show the aliases" do
191
+ a.should_receive(:show_aliases)
192
+ a.execute
193
+ end
194
+
195
+ it "should display all the aliases to the user if there are any" do
196
+ a.stub!(:read_aliases_file)
197
+ a.session_aliases << "[my_alias] rake db:migrate"
198
+ io.should_receive(:log).with("These are your current aliases..")
199
+ io.should_receive(:log).with("[my_alias] rake db:migrate")
200
+ a.session_aliases.should_receive(:any?).and_return(true)
201
+ a.execute
202
+ end
203
+
204
+ it "it should not display any aliases since there are none. Will display a friendly message instead." do
205
+ a.stub!(:read_aliases_file)
206
+ a.session_aliases.should_receive(:any?).and_return(false)
207
+ io.should_receive(:log).with("You have not yet set up any aliases.", true)
208
+ a.execute
209
+ end
210
+ end
211
+ end
212
+
213
+ end
@@ -0,0 +1,51 @@
1
+ # Load Spec Helper
2
+ require File.join(File.expand_path(File.dirname(__FILE__)), '../..', 'spec_helper')
3
+
4
+ describe Webbynode::Commands::ChangeDns do
5
+ let(:git) { double("git").as_null_object }
6
+ let(:io) { double("io").as_null_object }
7
+ let(:api) { double("api").as_null_object }
8
+ let(:cmd) { Webbynode::Commands::ChangeDns.new("the.newdns.com") }
9
+
10
+
11
+ before(:each) do
12
+ FakeWeb.clean_registry
13
+ cmd.should_receive(:io).any_number_of_times.and_return(io)
14
+ cmd.should_receive(:git).any_number_of_times.and_return(git)
15
+ cmd.should_receive(:api).any_number_of_times.and_return(api)
16
+
17
+ end
18
+
19
+ it "should change pushand" do
20
+ io.should_receive(:app_name).and_return("myapp")
21
+ io.should_receive(:create_file).with(".pushand", "#! /bin/bash\nphd $0 myapp the.newdns.com\n", true)
22
+ git.should_receive(:parse_remote_ip).and_return("1.2.3.4")
23
+ api.should_receive(:create_record).with("the.newdns.com", "1.2.3.4")
24
+
25
+ cmd.run
26
+ end
27
+
28
+ it "should give an error message if there are git changes pending" do
29
+ git.should_receive(:clean?).and_return(false)
30
+
31
+ cmd.run
32
+ stdout.should =~ /Cannot change DNS because you have pending changes. Do a git commit or add changes to .gitignore./
33
+ end
34
+
35
+ context "when committing the DNS change" do
36
+ it "should perform a commit of .pushand" do
37
+ io.should_receive(:file_exists?).with(".webbynode/settings").and_return(false)
38
+ git.should_receive(:add).with(".pushand")
39
+ git.should_receive(:commit).with("Changed DNS to \"the.newdns.com\"")
40
+ cmd.run
41
+ end
42
+
43
+ it "should perform a commit of .pushand and .webbynode/settings if the later exists" do
44
+ io.should_receive(:file_exists?).with(".webbynode/settings").and_return(true)
45
+ git.should_receive(:add).with(".pushand")
46
+ git.should_receive(:add).with(".webbynode/settings")
47
+ git.should_receive(:commit).with("Changed DNS to \"the.newdns.com\"")
48
+ cmd.run
49
+ end
50
+ end
51
+ end