azuki 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +71 -0
  3. data/bin/azuki +17 -0
  4. data/data/cacert.pem +3988 -0
  5. data/lib/azuki.rb +17 -0
  6. data/lib/azuki/auth.rb +339 -0
  7. data/lib/azuki/cli.rb +38 -0
  8. data/lib/azuki/client.rb +764 -0
  9. data/lib/azuki/client/azuki_postgresql.rb +141 -0
  10. data/lib/azuki/client/cisaurus.rb +26 -0
  11. data/lib/azuki/client/pgbackups.rb +113 -0
  12. data/lib/azuki/client/rendezvous.rb +108 -0
  13. data/lib/azuki/client/ssl_endpoint.rb +25 -0
  14. data/lib/azuki/command.rb +294 -0
  15. data/lib/azuki/command/account.rb +23 -0
  16. data/lib/azuki/command/accounts.rb +34 -0
  17. data/lib/azuki/command/addons.rb +305 -0
  18. data/lib/azuki/command/apps.rb +393 -0
  19. data/lib/azuki/command/auth.rb +86 -0
  20. data/lib/azuki/command/base.rb +230 -0
  21. data/lib/azuki/command/certs.rb +209 -0
  22. data/lib/azuki/command/config.rb +137 -0
  23. data/lib/azuki/command/db.rb +218 -0
  24. data/lib/azuki/command/domains.rb +85 -0
  25. data/lib/azuki/command/drains.rb +46 -0
  26. data/lib/azuki/command/fork.rb +164 -0
  27. data/lib/azuki/command/git.rb +64 -0
  28. data/lib/azuki/command/help.rb +179 -0
  29. data/lib/azuki/command/keys.rb +115 -0
  30. data/lib/azuki/command/labs.rb +147 -0
  31. data/lib/azuki/command/logs.rb +45 -0
  32. data/lib/azuki/command/maintenance.rb +61 -0
  33. data/lib/azuki/command/pg.rb +269 -0
  34. data/lib/azuki/command/pgbackups.rb +329 -0
  35. data/lib/azuki/command/plugins.rb +110 -0
  36. data/lib/azuki/command/ps.rb +232 -0
  37. data/lib/azuki/command/regions.rb +22 -0
  38. data/lib/azuki/command/releases.rb +124 -0
  39. data/lib/azuki/command/run.rb +180 -0
  40. data/lib/azuki/command/sharing.rb +89 -0
  41. data/lib/azuki/command/ssl.rb +43 -0
  42. data/lib/azuki/command/stack.rb +62 -0
  43. data/lib/azuki/command/status.rb +51 -0
  44. data/lib/azuki/command/update.rb +47 -0
  45. data/lib/azuki/command/version.rb +23 -0
  46. data/lib/azuki/deprecated.rb +5 -0
  47. data/lib/azuki/deprecated/help.rb +38 -0
  48. data/lib/azuki/distribution.rb +9 -0
  49. data/lib/azuki/excon.rb +9 -0
  50. data/lib/azuki/helpers.rb +517 -0
  51. data/lib/azuki/helpers/azuki_postgresql.rb +165 -0
  52. data/lib/azuki/helpers/log_displayer.rb +70 -0
  53. data/lib/azuki/plugin.rb +163 -0
  54. data/lib/azuki/updater.rb +171 -0
  55. data/lib/azuki/version.rb +3 -0
  56. data/lib/vendor/azuki/okjson.rb +598 -0
  57. data/spec/azuki/auth_spec.rb +256 -0
  58. data/spec/azuki/client/azuki_postgresql_spec.rb +71 -0
  59. data/spec/azuki/client/pgbackups_spec.rb +43 -0
  60. data/spec/azuki/client/rendezvous_spec.rb +62 -0
  61. data/spec/azuki/client/ssl_endpoint_spec.rb +48 -0
  62. data/spec/azuki/client_spec.rb +564 -0
  63. data/spec/azuki/command/addons_spec.rb +601 -0
  64. data/spec/azuki/command/apps_spec.rb +351 -0
  65. data/spec/azuki/command/auth_spec.rb +38 -0
  66. data/spec/azuki/command/base_spec.rb +109 -0
  67. data/spec/azuki/command/certs_spec.rb +178 -0
  68. data/spec/azuki/command/config_spec.rb +144 -0
  69. data/spec/azuki/command/db_spec.rb +110 -0
  70. data/spec/azuki/command/domains_spec.rb +87 -0
  71. data/spec/azuki/command/drains_spec.rb +34 -0
  72. data/spec/azuki/command/fork_spec.rb +56 -0
  73. data/spec/azuki/command/git_spec.rb +144 -0
  74. data/spec/azuki/command/help_spec.rb +93 -0
  75. data/spec/azuki/command/keys_spec.rb +120 -0
  76. data/spec/azuki/command/labs_spec.rb +100 -0
  77. data/spec/azuki/command/logs_spec.rb +60 -0
  78. data/spec/azuki/command/maintenance_spec.rb +51 -0
  79. data/spec/azuki/command/pg_spec.rb +236 -0
  80. data/spec/azuki/command/pgbackups_spec.rb +307 -0
  81. data/spec/azuki/command/plugins_spec.rb +104 -0
  82. data/spec/azuki/command/ps_spec.rb +195 -0
  83. data/spec/azuki/command/releases_spec.rb +130 -0
  84. data/spec/azuki/command/run_spec.rb +83 -0
  85. data/spec/azuki/command/sharing_spec.rb +59 -0
  86. data/spec/azuki/command/stack_spec.rb +46 -0
  87. data/spec/azuki/command/status_spec.rb +48 -0
  88. data/spec/azuki/command/version_spec.rb +16 -0
  89. data/spec/azuki/command_spec.rb +211 -0
  90. data/spec/azuki/helpers/azuki_postgresql_spec.rb +155 -0
  91. data/spec/azuki/helpers_spec.rb +48 -0
  92. data/spec/azuki/plugin_spec.rb +172 -0
  93. data/spec/azuki/updater_spec.rb +44 -0
  94. data/spec/helper/legacy_help.rb +16 -0
  95. data/spec/spec.opts +1 -0
  96. data/spec/spec_helper.rb +224 -0
  97. data/spec/support/display_message_matcher.rb +49 -0
  98. data/spec/support/openssl_mock_helper.rb +8 -0
  99. metadata +211 -0
@@ -0,0 +1,351 @@
1
+ require "spec_helper"
2
+ require "azuki/command/apps"
3
+
4
+ module Azuki::Command
5
+ describe Apps do
6
+
7
+ before(:each) do
8
+ stub_core
9
+ end
10
+
11
+ context("info") do
12
+
13
+ before(:each) do
14
+ api.post_app("name" => "example", "stack" => "cedar")
15
+ end
16
+
17
+ after(:each) do
18
+ api.delete_app("example")
19
+ end
20
+
21
+ it "displays impicit app info" do
22
+ stderr, stdout = execute("apps:info")
23
+ stderr.should == ""
24
+ stdout.should == <<-STDOUT
25
+ === example
26
+ Git URL: git@azukiapp.com:example.git
27
+ Owner Email: email@example.com
28
+ Stack: cedar
29
+ Web URL: http://example.azukiapp.com/
30
+ STDOUT
31
+ end
32
+
33
+ it "gets explicit app from --app" do
34
+ stderr, stdout = execute("apps:info --app example")
35
+ stderr.should == ""
36
+ stdout.should == <<-STDOUT
37
+ === example
38
+ Git URL: git@azukiapp.com:example.git
39
+ Owner Email: email@example.com
40
+ Stack: cedar
41
+ Web URL: http://example.azukiapp.com/
42
+ STDOUT
43
+ end
44
+
45
+ it "shows shell app info when --shell option is used" do
46
+ stderr, stdout = execute("apps:info --shell")
47
+ stderr.should == ""
48
+ stdout.should match Regexp.new(<<-STDOUT)
49
+ create_status=complete
50
+ created_at=\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}:\\d{2} [+-]\\d{4}
51
+ dynos=0
52
+ git_url=git@azukiapp.com:example.git
53
+ id=\\d{1,5}
54
+ name=example
55
+ owner_email=email@example.com
56
+ repo_migrate_status=complete
57
+ repo_size=
58
+ requested_stack=
59
+ slug_size=
60
+ stack=cedar
61
+ web_url=http://example.azukiapp.com/
62
+ workers=0
63
+ STDOUT
64
+ end
65
+
66
+ end
67
+
68
+ context("create") do
69
+
70
+ it "without a name" do
71
+ name = nil
72
+ with_blank_git_repository do
73
+ stderr, stdout = execute("apps:create")
74
+ name = api.get_apps.body.first["name"]
75
+ stderr.should == ""
76
+ stdout.should == <<-STDOUT
77
+ Creating #{name}... done, stack is bamboo-mri-1.9.2
78
+ http://#{name}.azukiapp.com/ | git@azukiapp.com:#{name}.git
79
+ Git remote azuki added
80
+ STDOUT
81
+ end
82
+ api.delete_app(name)
83
+ end
84
+
85
+ it "with a name" do
86
+ with_blank_git_repository do
87
+ stderr, stdout = execute("apps:create example")
88
+ stderr.should == ""
89
+ stdout.should == <<-STDOUT
90
+ Creating example... done, stack is bamboo-mri-1.9.2
91
+ http://example.azukiapp.com/ | git@azukiapp.com:example.git
92
+ Git remote azuki added
93
+ STDOUT
94
+ end
95
+ api.delete_app("example")
96
+ end
97
+
98
+ it "with -a name" do
99
+ with_blank_git_repository do
100
+ stderr, stdout = execute("apps:create -a example")
101
+ stderr.should == ""
102
+ stdout.should == <<-STDOUT
103
+ Creating example... done, stack is bamboo-mri-1.9.2
104
+ http://example.azukiapp.com/ | git@azukiapp.com:example.git
105
+ Git remote azuki added
106
+ STDOUT
107
+ end
108
+ api.delete_app("example")
109
+ end
110
+
111
+ it "with --no-remote" do
112
+ with_blank_git_repository do
113
+ stderr, stdout = execute("apps:create example --no-remote")
114
+ stderr.should == ""
115
+ stdout.should == <<-STDOUT
116
+ Creating example... done, stack is bamboo-mri-1.9.2
117
+ http://example.azukiapp.com/ | git@azukiapp.com:example.git
118
+ STDOUT
119
+ end
120
+ api.delete_app("example")
121
+ end
122
+
123
+ it "with addons" do
124
+ with_blank_git_repository do
125
+ stderr, stdout = execute("apps:create addonapp --addon custom_domains:basic,releases:basic")
126
+ stderr.should == ""
127
+ stdout.should == <<-STDOUT
128
+ Creating addonapp... done, stack is bamboo-mri-1.9.2
129
+ Adding custom_domains:basic to addonapp... done
130
+ Adding releases:basic to addonapp... done
131
+ http://addonapp.azukiapp.com/ | git@azukiapp.com:addonapp.git
132
+ Git remote azuki added
133
+ STDOUT
134
+ end
135
+ api.delete_app("addonapp")
136
+ end
137
+
138
+ it "with a buildpack" do
139
+ with_blank_git_repository do
140
+ stderr, stdout = execute("apps:create buildpackapp --buildpack http://example.org/buildpack.git")
141
+ stderr.should == ""
142
+ stdout.should == <<-STDOUT
143
+ Creating buildpackapp... done, stack is bamboo-mri-1.9.2
144
+ BUILDPACK_URL=http://example.org/buildpack.git
145
+ http://buildpackapp.azukiapp.com/ | git@azukiapp.com:buildpackapp.git
146
+ Git remote azuki added
147
+ STDOUT
148
+ end
149
+ api.delete_app("buildpackapp")
150
+ end
151
+
152
+ it "with an alternate remote name" do
153
+ with_blank_git_repository do
154
+ stderr, stdout = execute("apps:create alternate-remote --remote alternate")
155
+ stderr.should == ""
156
+ stdout.should == <<-STDOUT
157
+ Creating alternate-remote... done, stack is bamboo-mri-1.9.2
158
+ http://alternate-remote.azukiapp.com/ | git@azukiapp.com:alternate-remote.git
159
+ Git remote alternate added
160
+ STDOUT
161
+ end
162
+ api.delete_app("alternate-remote")
163
+ end
164
+
165
+ end
166
+
167
+ context("index") do
168
+
169
+ before(:each) do
170
+ api.post_app("name" => "example", "stack" => "cedar")
171
+ end
172
+
173
+ after(:each) do
174
+ api.delete_app("example")
175
+ end
176
+
177
+ it "succeeds" do
178
+ stub_core.list.returns([["example", "user"]])
179
+ stderr, stdout = execute("apps")
180
+ stderr.should == ""
181
+ stdout.should == <<-STDOUT
182
+ === Dev & Legacy Apps
183
+ example
184
+
185
+ STDOUT
186
+ end
187
+
188
+ end
189
+
190
+ context("rename") do
191
+
192
+ context("success") do
193
+
194
+ before(:each) do
195
+ api.post_app("name" => "example", "stack" => "cedar")
196
+ end
197
+
198
+ after(:each) do
199
+ api.delete_app("example2")
200
+ end
201
+
202
+ it "renames app" do
203
+ with_blank_git_repository do
204
+ stderr, stdout = execute("apps:rename example2")
205
+ stderr.should == ""
206
+ stdout.should == <<-STDOUT
207
+ Renaming example to example2... done
208
+ http://example2.azukiapp.com/ | git@azukiapp.com:example2.git
209
+ Don't forget to update your Git remotes on any local checkouts.
210
+ STDOUT
211
+ end
212
+ end
213
+
214
+ end
215
+
216
+ it "displays an error if no name is specified" do
217
+ stderr, stdout = execute("apps:rename")
218
+ stderr.should == <<-STDERR
219
+ ! Usage: azuki apps:rename NEWNAME
220
+ ! Must specify NEWNAME to rename.
221
+ STDERR
222
+ stdout.should == ""
223
+ end
224
+
225
+ end
226
+
227
+ context("destroy") do
228
+
229
+ before(:each) do
230
+ api.post_app("name" => "example", "stack" => "cedar")
231
+ end
232
+
233
+ it "succeeds with app explicitly specified with --app and user confirmation" do
234
+ stderr, stdout = execute("apps:destroy --confirm example")
235
+ stderr.should == ""
236
+ stdout.should == <<-STDOUT
237
+ Destroying example (including all add-ons)... done
238
+ STDOUT
239
+ end
240
+
241
+ context("fails") do
242
+
243
+ after(:each) do
244
+ api.delete_app("example")
245
+ end
246
+
247
+ it "fails with explicit app but no confirmation" do
248
+ stderr, stdout = execute("apps:destroy example")
249
+ stderr.should == <<-STDERR
250
+ ! Confirmation did not match example. Aborted.
251
+ STDERR
252
+ stdout.should == "
253
+ ! WARNING: Potentially Destructive Action
254
+ ! This command will destroy example (including all add-ons).
255
+ ! To proceed, type \"example\" or re-run this command with --confirm example
256
+
257
+ > "
258
+
259
+ end
260
+
261
+ it "fails without explicit app" do
262
+ stderr, stdout = execute("apps:destroy")
263
+ stderr.should == <<-STDERR
264
+ ! Usage: azuki apps:destroy --app APP
265
+ ! Must specify APP to destroy.
266
+ STDERR
267
+ stdout.should == ""
268
+ end
269
+
270
+ end
271
+
272
+ end
273
+
274
+ context "Git Integration" do
275
+
276
+ it "creates adding azuki to git remote" do
277
+ with_blank_git_repository do
278
+ stderr, stdout = execute("apps:create example")
279
+ stderr.should == ""
280
+ stdout.should == <<-STDOUT
281
+ Creating example... done, stack is bamboo-mri-1.9.2
282
+ http://example.azukiapp.com/ | git@azukiapp.com:example.git
283
+ Git remote azuki added
284
+ STDOUT
285
+ `git remote`.strip.should match(/^azuki$/)
286
+ api.delete_app("example")
287
+ end
288
+ end
289
+
290
+ it "creates adding a custom git remote" do
291
+ with_blank_git_repository do
292
+ stderr, stdout = execute("apps:create example --remote myremote")
293
+ stderr.should == ""
294
+ stdout.should == <<-STDOUT
295
+ Creating example... done, stack is bamboo-mri-1.9.2
296
+ http://example.azukiapp.com/ | git@azukiapp.com:example.git
297
+ Git remote myremote added
298
+ STDOUT
299
+ `git remote`.strip.should match(/^myremote$/)
300
+ api.delete_app("example")
301
+ end
302
+ end
303
+
304
+ it "doesn't add a git remote if it already exists" do
305
+ with_blank_git_repository do
306
+ `git remote add azuki /tmp/git_spec_#{Process.pid}`
307
+ stderr, stdout = execute("apps:create example")
308
+ stderr.should == ""
309
+ stdout.should == <<-STDOUT
310
+ Creating example... done, stack is bamboo-mri-1.9.2
311
+ http://example.azukiapp.com/ | git@azukiapp.com:example.git
312
+ STDOUT
313
+ api.delete_app("example")
314
+ end
315
+ end
316
+
317
+ it "renames updating the corresponding azuki git remote" do
318
+ with_blank_git_repository do
319
+ `git remote add github git@github.com:test/test.git`
320
+ `git remote add production git@azukiapp.com:example.git`
321
+ `git remote add staging git@azukiapp.com:example-staging.git`
322
+
323
+ api.post_app("name" => "example", "stack" => "cedar")
324
+ stderr, stdout = execute("apps:rename example2")
325
+ api.delete_app("example2")
326
+
327
+ remotes = `git remote -v`
328
+ remotes.should == <<-REMOTES
329
+ github\tgit@github.com:test/test.git (fetch)
330
+ github\tgit@github.com:test/test.git (push)
331
+ production\tgit@azukiapp.com:example2.git (fetch)
332
+ production\tgit@azukiapp.com:example2.git (push)
333
+ staging\tgit@azukiapp.com:example-staging.git (fetch)
334
+ staging\tgit@azukiapp.com:example-staging.git (push)
335
+ REMOTES
336
+ end
337
+ end
338
+
339
+ it "destroys removing any remotes pointing to the app" do
340
+ with_blank_git_repository do
341
+ `git remote add azuki git@azukiapp.com:example.git`
342
+
343
+ api.post_app("name" => "example", "stack" => "cedar")
344
+ stderr, stdout = execute("apps:destroy --confirm example")
345
+
346
+ `git remote`.strip.should_not include('azuki')
347
+ end
348
+ end
349
+ end
350
+ end
351
+ end
@@ -0,0 +1,38 @@
1
+ require "spec_helper"
2
+ require "azuki/command/auth"
3
+
4
+ describe Azuki::Command::Auth do
5
+ describe "auth" do
6
+ it "displays azuki help auth" do
7
+ stderr, stdout = execute("auth")
8
+
9
+ stderr.should == ""
10
+ stdout.should include "Additional commands"
11
+ stdout.should include "auth:login"
12
+ stdout.should include "auth:logout"
13
+ end
14
+ end
15
+
16
+ describe "auth:token" do
17
+
18
+ it "displays the user's api key" do
19
+ stderr, stdout = execute("auth:token")
20
+ stderr.should == ""
21
+ stdout.should == <<-STDOUT
22
+ apikey01
23
+ STDOUT
24
+ end
25
+ end
26
+
27
+ describe "auth:whoami" do
28
+ it "displays the user's email address" do
29
+ stderr, stdout = execute("auth:whoami")
30
+ stderr.should == ""
31
+ stdout.should == <<-STDOUT
32
+ email@example.com
33
+ STDOUT
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,109 @@
1
+ require "spec_helper"
2
+ require "azuki/command/base"
3
+
4
+ module Azuki::Command
5
+ describe Base do
6
+ before do
7
+ @base = Base.new
8
+ @base.stub!(:display)
9
+ @client = mock('azuki client', :host => 'azukiapp.com')
10
+ end
11
+
12
+ describe "confirming" do
13
+ it "confirms the app via --confirm" do
14
+ Azuki::Command.stub(:current_options).and_return(:confirm => "example")
15
+ @base.stub(:app).and_return("example")
16
+ @base.confirm_command.should be_true
17
+ end
18
+
19
+ it "does not confirms the app via --confirm on a mismatch" do
20
+ Azuki::Command.stub(:current_options).and_return(:confirm => "badapp")
21
+ @base.stub(:app).and_return("example")
22
+ lambda { @base.confirm_command}.should raise_error CommandFailed
23
+ end
24
+
25
+ it "confirms the app interactively via ask" do
26
+ @base.stub(:app).and_return("example")
27
+ @base.stub(:ask).and_return("example")
28
+ Azuki::Command.stub(:current_options).and_return({})
29
+ @base.confirm_command.should be_true
30
+ end
31
+
32
+ it "fails if the interactive confirm doesn't match" do
33
+ @base.stub(:app).and_return("example")
34
+ @base.stub(:ask).and_return("badresponse")
35
+ Azuki::Command.stub(:current_options).and_return({})
36
+ capture_stderr do
37
+ lambda { @base.confirm_command }.should raise_error(SystemExit)
38
+ end.should == <<-STDERR
39
+ ! Confirmation did not match example. Aborted.
40
+ STDERR
41
+ end
42
+ end
43
+
44
+ context "detecting the app" do
45
+ it "attempts to find the app via the --app option" do
46
+ @base.stub!(:options).and_return(:app => "example")
47
+ @base.app.should == "example"
48
+ end
49
+
50
+ it "attempts to find the app via the --confirm option" do
51
+ @base.stub!(:options).and_return(:confirm => "myconfirmapp")
52
+ @base.app.should == "myconfirmapp"
53
+ end
54
+
55
+ it "attempts to find the app via AZUKI_APP when not explicitly specified" do
56
+ ENV['AZUKI_APP'] = "myenvapp"
57
+ @base.app.should == "myenvapp"
58
+ @base.stub!(:options).and_return([])
59
+ @base.app.should == "myenvapp"
60
+ ENV.delete('AZUKI_APP')
61
+ end
62
+
63
+ it "overrides AZUKI_APP when explicitly specified" do
64
+ ENV['AZUKI_APP'] = "myenvapp"
65
+ @base.stub!(:options).and_return(:app => "example")
66
+ @base.app.should == "example"
67
+ ENV.delete('AZUKI_APP')
68
+ end
69
+
70
+ it "read remotes from git config" do
71
+ Dir.stub(:chdir)
72
+ File.should_receive(:exists?).with(".git").and_return(true)
73
+ @base.should_receive(:git).with('remote -v').and_return(<<-REMOTES)
74
+ staging\tgit@azukiapp.com:example-staging.git (fetch)
75
+ staging\tgit@azukiapp.com:example-staging.git (push)
76
+ production\tgit@azukiapp.com:example.git (fetch)
77
+ production\tgit@azukiapp.com:example.git (push)
78
+ other\tgit@other.com:other.git (fetch)
79
+ other\tgit@other.com:other.git (push)
80
+ REMOTES
81
+
82
+ @azuki = mock
83
+ @azuki.stub(:host).and_return('azukiapp.com')
84
+ @base.stub(:azuki).and_return(@azuki)
85
+
86
+ # need a better way to test internal functionality
87
+ @base.send(:git_remotes, '/home/dev/example').should == { 'staging' => 'example-staging', 'production' => 'example' }
88
+ end
89
+
90
+ it "gets the app from remotes when there's only one app" do
91
+ @base.stub!(:git_remotes).and_return({ 'azuki' => 'example' })
92
+ @base.stub!(:git).with("config azuki.remote").and_return("")
93
+ @base.app.should == 'example'
94
+ end
95
+
96
+ it "accepts a --remote argument to choose the app from the remote name" do
97
+ @base.stub!(:git_remotes).and_return({ 'staging' => 'example-staging', 'production' => 'example' })
98
+ @base.stub!(:options).and_return(:remote => "staging")
99
+ @base.app.should == 'example-staging'
100
+ end
101
+
102
+ it "raises when cannot determine which app is it" do
103
+ @base.stub!(:git_remotes).and_return({ 'staging' => 'example-staging', 'production' => 'example' })
104
+ lambda { @base.app }.should raise_error(Azuki::Command::CommandFailed)
105
+ end
106
+ end
107
+
108
+ end
109
+ end