shelly 0.0.30 → 0.0.31

Sign up to get free protection for your applications and to get access to all the features.
data/lib/shelly/app.rb CHANGED
@@ -50,16 +50,24 @@ module Shelly
50
50
  File.open(cloudfile_path, "a+") { |f| f << content }
51
51
  end
52
52
 
53
- def logs
54
- shelly.cloud_logs(self.code_name)
53
+ def deploy_logs
54
+ shelly.deploy_logs(code_name)
55
+ end
56
+
57
+ def deploy_log(log)
58
+ shelly.deploy_log(code_name, log)
59
+ end
60
+
61
+ def application_logs
62
+ shelly.application_logs(self.code_name)
55
63
  end
56
64
 
57
65
  def start
58
- shelly.start_cloud(self.code_name)
66
+ shelly.start_cloud(code_name)
59
67
  end
60
68
 
61
69
  def stop
62
- shelly.stop_cloud(self.code_name)
70
+ shelly.stop_cloud(code_name)
63
71
  end
64
72
 
65
73
  def cloudfile_path
@@ -71,11 +79,23 @@ module Shelly
71
79
  end
72
80
 
73
81
  def ips
74
- shelly.app_ips(self.code_name)
82
+ shelly.app_ips(code_name)
75
83
  end
76
84
 
77
85
  def users
78
- shelly.app_users(self.code_name)
86
+ shelly.app_users(code_name)
87
+ end
88
+
89
+ def configs
90
+ @configs ||= shelly.app_configs(code_name)
91
+ end
92
+
93
+ def user_configs
94
+ configs.find_all { |config| config["created_by_user"] }
95
+ end
96
+
97
+ def shelly_generated_configs
98
+ configs.find_all { |config| config["created_by_user"] == false }
79
99
  end
80
100
 
81
101
  def open_billing_page
@@ -0,0 +1,47 @@
1
+ require "shelly/cli/command"
2
+
3
+ module Shelly
4
+ module CLI
5
+ class Config < Command
6
+ include Thor::Actions
7
+ include Helpers
8
+
9
+ desc "list", "List configuration files"
10
+ def list
11
+ logged_in?
12
+ say_error "No Cloudfile found" unless Cloudfile.present?
13
+ cloudfile = Cloudfile.new
14
+ cloudfile.clouds.each do |cloud|
15
+ @app = App.new(cloud)
16
+ begin
17
+ configs = @app.configs
18
+ unless configs.empty?
19
+ say "Configuration files for #{cloud}", :green
20
+ user_configs = @app.user_configs
21
+ unless user_configs.empty?
22
+ say "Custom configuration files:"
23
+ user_configs.each { |config| say " * #{config["path"]}" }
24
+ else
25
+ say "You have no custom configuration files."
26
+ end
27
+ shelly_configs = @app.shelly_generated_configs
28
+ unless shelly_configs.empty?
29
+ say "Following files are created by Shelly Cloud:"
30
+ shelly_configs.each { |config| say " * #{config["path"]}" }
31
+ end
32
+ else
33
+ say "Cloud #{cloud} has no configuration files"
34
+ end
35
+ rescue Client::APIError => e
36
+ if e.unauthorized?
37
+ say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
38
+ else
39
+ say_error e.message
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -11,8 +11,8 @@ module Shelly
11
11
  def list(cloud = nil)
12
12
  logged_in?
13
13
  say_error "No Cloudfile found" unless Cloudfile.present?
14
- multiple_clouds(cloud, "deploy list", "Select cloud to view deploy logs using:")
15
- logs = @app.logs
14
+ multiple_clouds(cloud, "deploys list", "Select cloud to view deploy logs using:")
15
+ logs = @app.deploy_logs
16
16
  unless logs.empty?
17
17
  say "Available deploy logs", :green
18
18
  logs.each do |log|
@@ -29,6 +29,47 @@ module Shelly
29
29
  end
30
30
  end
31
31
 
32
+ desc "show LOG", "Show specific deploy log"
33
+ def show(log = nil, cloud = nil)
34
+ say_error "No Cloudfile found" unless Cloudfile.present?
35
+ specify_log(log)
36
+ multiple_clouds(cloud, "deploys show #{log}", "Select log and cloud to view deploy logs using:")
37
+ content = @app.deploy_log(log)
38
+ say "Log for deploy done on #{content["created_at"]}", :green
39
+ if content["bundle_install"]
40
+ say("Starting bundle install", :green); say(content["bundle_install"])
41
+ end
42
+ if content["whenever"]
43
+ say("Starting whenever", :green); say(content["whenever"])
44
+ end
45
+ if content["callbacks"]
46
+ say("Starting callbacks", :green); say(content["callbacks"])
47
+ end
48
+ if content["delayed_job"]
49
+ say("Starting delayed job", :green); say(content["delayed_job"])
50
+ end
51
+ if content["thin_restart"]
52
+ say("Starting thin", :green); say(content["thin_restart"])
53
+ end
54
+ rescue Client::APIError => e
55
+ if e.unauthorized?
56
+ say_error "You have no access to '#{@app.code_name}' cloud defined in Cloudfile"
57
+ elsif e.message == "Log not found"
58
+ say_error "Log not found, list all deploy logs using:", :with_exit => false
59
+ say " shelly deploys list #{cloud}"
60
+ exit 1
61
+ end
62
+ end
63
+
64
+ no_tasks do
65
+ def specify_log(log)
66
+ unless log
67
+ say_error "Specify log by passing date value or to see last log use:", :with_exit => false
68
+ say " shelly deploys show last"
69
+ exit 1
70
+ end
71
+ end
72
+ end
32
73
  end
33
74
  end
34
75
  end
@@ -1,6 +1,7 @@
1
1
  require "shelly/cli/command"
2
2
  require "shelly/cli/user"
3
3
  require "shelly/cli/deploys"
4
+ require "shelly/cli/config"
4
5
 
5
6
  module Shelly
6
7
  module CLI
@@ -9,6 +10,7 @@ module Shelly
9
10
  include Helpers
10
11
  register(User, "user", "user <command>", "Manages users using this cloud")
11
12
  register(Deploys, "deploys", "deploys <command>", "View cloud deploy logs")
13
+ register(Config, "config", "config <command>", "Manages cloud configuration files")
12
14
  check_unknown_options!
13
15
 
14
16
  map %w(-v --version) => :version
@@ -234,6 +236,28 @@ module Shelly
234
236
  say_error e.message
235
237
  end
236
238
 
239
+ desc "logs", "Show latest application logs from each instance"
240
+ method_option :cloud, :type => :string, :aliases => "-c",
241
+ :desc => "Specify which cloud to show logs for"
242
+ def logs
243
+ cloud = options[:cloud]
244
+ logged_in?
245
+ say_error "No Cloudfile found" unless Cloudfile.present?
246
+ multiple_clouds(cloud, "logs --cloud", "Select which to show logs for using:")
247
+ begin
248
+ logs = @app.application_logs
249
+ say "Cloud #{@app.code_name}:", :green
250
+ logs.each_with_index do |log, i|
251
+ say "Instance #{i+1}:"
252
+ print_wrapped log, :ident => 2
253
+ end
254
+ rescue Client::APIError => e
255
+ if e.unauthorized?
256
+ say_error "You have no access to cloud '#{cloud || @app.code_name}'"
257
+ end
258
+ end
259
+ end
260
+
237
261
  # FIXME: move to helpers
238
262
  no_tasks do
239
263
  def check_options(options)
data/lib/shelly/client.rb CHANGED
@@ -58,6 +58,10 @@ module Shelly
58
58
  get("/token")
59
59
  end
60
60
 
61
+ def app_configs(cloud)
62
+ get("/apps/#{cloud}/configs")
63
+ end
64
+
61
65
  def send_invitation(cloud, email)
62
66
  post("/apps/#{cloud}/collaborations", :email => email)
63
67
  end
@@ -86,10 +90,18 @@ module Shelly
86
90
  get("/apps")
87
91
  end
88
92
 
89
- def cloud_logs(cloud)
93
+ def deploy_logs(cloud)
90
94
  get("/apps/#{cloud}/deploys")
91
95
  end
92
96
 
97
+ def deploy_log(cloud, log)
98
+ get("/apps/#{cloud}/deploys/#{log}")
99
+ end
100
+
101
+ def application_logs(cloud)
102
+ get("/apps/#{cloud}/logs")
103
+ end
104
+
93
105
  def ssh_key_available?(ssh_key)
94
106
  get("/users/new", :ssh_key => ssh_key)
95
107
  end
@@ -27,6 +27,7 @@ module Shelly
27
27
  end
28
28
  end
29
29
 
30
+ # FIXME: this should return instances of App
30
31
  def clouds
31
32
  @content.keys.sort
32
33
  end
@@ -1,3 +1,3 @@
1
1
  module Shelly
2
- VERSION = "0.0.30"
2
+ VERSION = "0.0.31"
3
3
  end
@@ -48,6 +48,23 @@ describe Shelly::App do
48
48
  end
49
49
  end
50
50
 
51
+ describe "#configs" do
52
+ it "should get configs from client" do
53
+ @client.should_receive(:app_configs).with("foo-staging")
54
+ @app.configs
55
+ end
56
+
57
+ it "should return only user config files" do
58
+ @client.should_receive(:app_configs).with("foo-staging").and_return([])
59
+ @app.user_configs
60
+ end
61
+
62
+ it "should return only shelly genereted config files" do
63
+ @client.should_receive(:app_configs).with("foo-staging").and_return([])
64
+ @app.shelly_generated_configs
65
+ end
66
+ end
67
+
51
68
  describe "#generate_cloudfile" do
52
69
  it "should return generated cloudfile" do
53
70
  user = mock(:email => "bob@example.com")
@@ -128,10 +145,25 @@ config
128
145
  end
129
146
  end
130
147
 
131
- describe "#logs" do
132
- it "should list logs" do
133
- @client.should_receive(:cloud_logs).with("foo-staging")
134
- @app.logs
148
+ describe "#deploy_logs" do
149
+ it "should list deploy_logs" do
150
+ @client.should_receive(:deploy_logs).with("foo-staging")
151
+ @app.deploy_logs
152
+ end
153
+ end
154
+
155
+ describe "#application_logs" do
156
+ it "should list application_logs" do
157
+ @client.should_receive(:application_logs).with("foo-staging").
158
+ and_return({"logs" => ["log1", "log2"]})
159
+ @app.application_logs
160
+ end
161
+ end
162
+
163
+ describe "#deploy_log" do
164
+ it "should show log" do
165
+ @client.should_receive(:deploy_log).with("foo-staging", "2011-11-29-11-50-16")
166
+ @app.deploy_log("2011-11-29-11-50-16")
135
167
  end
136
168
  end
137
169
 
@@ -0,0 +1,55 @@
1
+ require "spec_helper"
2
+ require "shelly/cli/config"
3
+
4
+ describe Shelly::CLI::Config do
5
+
6
+ before do
7
+ FileUtils.stub(:chmod)
8
+ @config = Shelly::CLI::Config.new
9
+ @client = mock
10
+ Shelly::Client.stub(:new).and_return(@client)
11
+ $stdout.stub(:puts)
12
+ $stdout.stub(:print)
13
+ end
14
+
15
+ describe "#list" do
16
+ before do
17
+ FileUtils.mkdir_p("/projects/foo")
18
+ Dir.chdir("/projects/foo")
19
+ File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\nfoo-production:\n") }
20
+ @client.stub(:token).and_return("abc")
21
+ end
22
+
23
+ it "should exit with message if there is no Cloudfile" do
24
+ File.delete("Cloudfile")
25
+ $stdout.should_receive(:puts).with(red "No Cloudfile found")
26
+ lambda {
27
+ @config.list
28
+ }.should raise_error(SystemExit)
29
+ end
30
+
31
+ it "should exit if user doesn't have access to cloud in Cloudfile" do
32
+ response = {"message" => "Cloud foo-staging not found"}
33
+ exception = Shelly::Client::APIError.new(response.to_json)
34
+ @client.stub(:app_configs).and_raise(exception)
35
+ $stdout.should_receive(:puts).with(red "You have no access to 'foo-production' cloud defined in Cloudfile")
36
+ lambda { @config.list }.should raise_error(SystemExit)
37
+ end
38
+
39
+ it "should list available configuration files for clouds" do
40
+ @client.should_receive(:app_configs).with("foo-staging").and_return([{"created_by_user" => true, "path" => "config/settings.yml"}])
41
+ @client.should_receive(:app_configs).with("foo-production").and_return([{"created_by_user" => false, "path" => "config/app.yml"}])
42
+ $stdout.should_receive(:puts).with(green "Configuration files for foo-production")
43
+ $stdout.should_receive(:puts).with("You have no custom configuration files.")
44
+ $stdout.should_receive(:puts).with("Following files are created by Shelly Cloud:")
45
+ $stdout.should_receive(:puts).with(" * config/app.yml")
46
+ $stdout.should_receive(:puts).with(green "Configuration files for foo-staging")
47
+ $stdout.should_receive(:puts).with("Custom configuration files:")
48
+ $stdout.should_receive(:puts).with(" * config/settings.yml")
49
+
50
+ @config.list
51
+ end
52
+
53
+ end
54
+
55
+ end
@@ -30,7 +30,7 @@ describe Shelly::CLI::Deploys do
30
30
  it "should exit if user doesn't have access to cloud in Cloudfile" do
31
31
  response = {"message" => "Cloud foo-staging not found"}
32
32
  exception = Shelly::Client::APIError.new(response.to_json)
33
- @client.stub(:cloud_logs).and_raise(exception)
33
+ @client.stub(:deploy_logs).and_raise(exception)
34
34
  $stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
35
35
  lambda { @deploys.list }.should raise_error(SystemExit)
36
36
  end
@@ -42,7 +42,7 @@ describe Shelly::CLI::Deploys do
42
42
 
43
43
  it "should show information to select specific cloud and exit" do
44
44
  $stdout.should_receive(:puts).with("You have multiple clouds in Cloudfile. Select cloud to view deploy logs using:")
45
- $stdout.should_receive(:puts).with(" shelly deploy list foo-production")
45
+ $stdout.should_receive(:puts).with(" shelly deploys list foo-production")
46
46
  $stdout.should_receive(:puts).with("Available clouds:")
47
47
  $stdout.should_receive(:puts).with(" * foo-production")
48
48
  $stdout.should_receive(:puts).with(" * foo-staging")
@@ -50,7 +50,7 @@ describe Shelly::CLI::Deploys do
50
50
  end
51
51
 
52
52
  it "should take cloud from command line for which to show logs" do
53
- @client.should_receive(:cloud_logs).with("foo-staging").and_return([{"failed" => false, "created_at" => "2011-12-12-14-14-59"}])
53
+ @client.should_receive(:deploy_logs).with("foo-staging").and_return([{"failed" => false, "created_at" => "2011-12-12-14-14-59"}])
54
54
  $stdout.should_receive(:puts).with(green "Available deploy logs")
55
55
  $stdout.should_receive(:puts).with(" * 2011-12-12-14-14-59")
56
56
  @deploys.list("foo-staging")
@@ -59,15 +59,88 @@ describe Shelly::CLI::Deploys do
59
59
 
60
60
  context "single cloud" do
61
61
  it "should display available logs" do
62
- @client.should_receive(:cloud_logs).with("foo-staging").and_return([{"failed" => false, "created_at" => "2011-12-12-14-14-59"}, {"failed" => true, "created_at" => "2011-12-12-15-14-59"}])
62
+ @client.should_receive(:deploy_logs).with("foo-staging").and_return([{"failed" => false, "created_at" => "2011-12-12-14-14-59"}, {"failed" => true, "created_at" => "2011-12-12-15-14-59"}])
63
63
  $stdout.should_receive(:puts).with(green "Available deploy logs")
64
64
  $stdout.should_receive(:puts).with(" * 2011-12-12-14-14-59")
65
65
  $stdout.should_receive(:puts).with(" * 2011-12-12-15-14-59 (failed)")
66
66
  @deploys.list
67
67
  end
68
+ end
69
+ end
70
+
71
+ describe "#show" do
72
+ before do
73
+ FileUtils.mkdir_p("/projects/foo")
74
+ Dir.chdir("/projects/foo")
75
+ File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\n") }
76
+ @client.stub(:token).and_return("abc")
77
+ end
78
+
79
+ it "should exit with message if there is no Cloudfile" do
80
+ File.delete("Cloudfile")
81
+ $stdout.should_receive(:puts).with("\e[31mNo Cloudfile found\e[0m")
82
+ lambda {
83
+ @deploys.show
84
+ }.should raise_error(SystemExit)
85
+ end
86
+
87
+ it "should exit if user doesn't have access to cloud in Cloudfile" do
88
+ response = {"message" => "Cloud foo-staging not found"}
89
+ exception = Shelly::Client::APIError.new(response.to_json)
90
+ @client.stub(:deploy_log).and_raise(exception)
91
+ $stdout.should_receive(:puts).with(red "You have no access to 'foo-staging' cloud defined in Cloudfile")
92
+ lambda { @deploys.show("last") }.should raise_error(SystemExit)
93
+ end
94
+
95
+ context "multiple clouds" do
96
+ before do
97
+ File.open("Cloudfile", 'w') {|f| f.write("foo-staging:\nfoo-production:\n") }
98
+ end
99
+
100
+ it "should show information to select specific cloud and exit" do
101
+ $stdout.should_receive(:puts).with("You have multiple clouds in Cloudfile. Select log and cloud to view deploy logs using:")
102
+ $stdout.should_receive(:puts).with(" shelly deploys show last foo-production")
103
+ $stdout.should_receive(:puts).with("Available clouds:")
104
+ $stdout.should_receive(:puts).with(" * foo-production")
105
+ $stdout.should_receive(:puts).with(" * foo-staging")
106
+ lambda { @deploys.show("last") }.should raise_error(SystemExit)
107
+ end
108
+
109
+ it "should render the logs" do
110
+ @client.should_receive(:deploy_log).with("foo-staging", "last").and_return(response)
111
+ expected_output
112
+ @deploys.show("last", "foo-staging")
113
+ end
114
+ end
115
+
116
+ context "single cloud" do
117
+ it "should render logs without passing cloud" do
118
+ @client.should_receive(:deploy_log).with("foo-staging", "last").and_return(response)
119
+ expected_output
120
+ @deploys.show("last")
121
+ end
122
+ end
123
+
124
+ def expected_output
125
+ $stdout.should_receive(:puts).with(green "Log for deploy done on 2011-12-12 at 14:14:59")
126
+ $stdout.should_receive(:puts).with(green "Starting bundle install")
127
+ $stdout.should_receive(:puts).with("Installing gems")
128
+ $stdout.should_receive(:puts).with(green "Starting whenever")
129
+ $stdout.should_receive(:puts).with("Looking up schedule.rb")
130
+ $stdout.should_receive(:puts).with(green "Starting callbacks")
131
+ $stdout.should_receive(:puts).with("rake db:migrate")
132
+ $stdout.should_receive(:puts).with(green "Starting delayed job")
133
+ $stdout.should_receive(:puts).with("delayed jobs")
134
+ $stdout.should_receive(:puts).with(green "Starting thin")
135
+ $stdout.should_receive(:puts).with("thins up and running")
136
+ end
68
137
 
138
+ def response
139
+ {"created_at" => "2011-12-12 at 14:14:59", "bundle_install" => "Installing gems",
140
+ "whenever" => "Looking up schedule.rb", "thin_restart" => "thins up and running",
141
+ "delayed_job" => "delayed jobs", "callbacks" => "rake db:migrate"}
69
142
  end
70
143
 
71
144
  end
72
145
 
73
- end
146
+ end
@@ -24,12 +24,14 @@ describe Shelly::CLI::Main do
24
24
  expected = <<-OUT
25
25
  Tasks:
26
26
  shelly add # Adds new cloud to Shelly Cloud
27
+ shelly config <command> # Manages cloud configuration files
27
28
  shelly delete CODE-NAME # Delete cloud from Shelly Cloud
28
29
  shelly deploys <command> # View cloud deploy logs
29
30
  shelly help [TASK] # Describe available tasks or one specific task
30
31
  shelly ip # Lists clouds IP's
31
32
  shelly list # Lists all your clouds
32
33
  shelly login [EMAIL] # Logs user in to Shelly Cloud
34
+ shelly logs # Show latest application logs from each instance
33
35
  shelly register [EMAIL] # Registers new user account on Shelly Cloud
34
36
  shelly start [CODE-NAME] # Starts specific cloud
35
37
  shelly stop [CODE-NAME] # Stops specific cloud
@@ -42,6 +44,21 @@ OUT
42
44
  out = IO.popen("bin/shelly").read.strip
43
45
  out.should == expected.strip
44
46
  end
47
+
48
+ it "should display options in help for logs" do
49
+ expected = <<-OUT
50
+ Usage:
51
+ shelly logs
52
+
53
+ Options:
54
+ -c, [--cloud=CLOUD] # Specify which cloud to show logs for
55
+ [--debug] # Show debug information
56
+
57
+ Show latest application logs from each instance
58
+ OUT
59
+ out = IO.popen("bin/shelly help logs").read.strip
60
+ out.should == expected.strip
61
+ end
45
62
  end
46
63
 
47
64
  describe "#register" do
@@ -775,4 +792,95 @@ OUT
775
792
  end
776
793
  end
777
794
  end
795
+
796
+ describe "#logs" do
797
+ before do
798
+ @user = Shelly::User.new
799
+ @client.stub(:token).and_return("abc")
800
+ FileUtils.mkdir_p("/projects/foo")
801
+ Dir.chdir("/projects/foo")
802
+ File.open("Cloudfile", 'w') {|f| f.write("foo-production:\n") }
803
+ Shelly::User.stub(:new).and_return(@user)
804
+ @client.stub(:apps).and_return([{"code_name" => "foo-production"},
805
+ {"code_name" => "foo-staging"}])
806
+ @app = Shelly::App.new
807
+ Shelly::App.stub(:new).and_return(@app)
808
+ end
809
+
810
+ it "should exit if there is no Cloudfile" do
811
+ File.delete("Cloudfile")
812
+ $stdout.should_receive(:puts).with("\e[31mNo Cloudfile found\e[0m")
813
+ lambda {
814
+ @main.logs
815
+ }.should raise_error(SystemExit)
816
+ end
817
+
818
+ it "should exit if user doesn't have access to clouds in Cloudfile" do
819
+ response = {"message" => "Cloud foo-production not found"}
820
+ exception = Shelly::Client::APIError.new(response.to_json)
821
+ @client.stub(:application_logs).and_raise(exception)
822
+ $stdout.should_receive(:puts).
823
+ with(red "You have no access to cloud 'foo-production'")
824
+ lambda { @main.logs }.should raise_error(SystemExit)
825
+ end
826
+
827
+ it "should exit if user is not logged in" do
828
+ response = {"message" => "Unauthorized"}
829
+ exception = Shelly::Client::APIError.new(response.to_json)
830
+ @client.stub(:token).and_raise(exception)
831
+ $stdout.should_receive(:puts).
832
+ with(red "You are not logged in. To log in use:")
833
+ $stdout.should_receive(:puts).with(" shelly login")
834
+ lambda { @main.logs }.should raise_error(SystemExit)
835
+ end
836
+
837
+ context "single cloud in Cloudfile" do
838
+ it "should show logs for the cloud" do
839
+ @client.stub(:application_logs).and_return(["log1"])
840
+ $stdout.should_receive(:puts).with(green "Cloud foo-production:")
841
+ $stdout.should_receive(:puts).with("Instance 1:")
842
+ $stdout.should_receive(:puts).with(" log1")
843
+ @main.logs
844
+ end
845
+ end
846
+
847
+ context "multiple clouds in Cloudfile" do
848
+ before do
849
+ File.open("Cloudfile", 'w') {|f|
850
+ f.write("foo-staging:\nfoo-production:\n") }
851
+ end
852
+
853
+ it "should show information to print logs for specific cloud and exit" do
854
+ $stdout.should_receive(:puts).
855
+ with("You have multiple clouds in Cloudfile. Select which to show logs for using:")
856
+ $stdout.should_receive(:puts).with(" shelly logs --cloud foo-production")
857
+ $stdout.should_receive(:puts).with("Available clouds:")
858
+ $stdout.should_receive(:puts).with(" * foo-production")
859
+ $stdout.should_receive(:puts).with(" * foo-staging")
860
+ lambda { @main.logs }.should raise_error(SystemExit)
861
+ end
862
+
863
+ it "should fetch from command line which cloud to start" do
864
+ @client.should_receive(:application_logs).with("foo-staging").
865
+ and_return(["log1"])
866
+ $stdout.should_receive(:puts).with(green "Cloud foo-staging:")
867
+ $stdout.should_receive(:puts).with("Instance 1:")
868
+ $stdout.should_receive(:puts).with(" log1")
869
+ @main.options = {:cloud => "foo-staging"}
870
+ @main.logs
871
+ end
872
+ end
873
+
874
+ context "multiple instances" do
875
+ it "should show logs from each instance" do
876
+ @client.stub(:application_logs).and_return(["log1", "log2"])
877
+ $stdout.should_receive(:puts).with(green "Cloud foo-production:")
878
+ $stdout.should_receive(:puts).with("Instance 1:")
879
+ $stdout.should_receive(:puts).with(" log1")
880
+ $stdout.should_receive(:puts).with("Instance 2:")
881
+ $stdout.should_receive(:puts).with(" log2")
882
+ @main.logs
883
+ end
884
+ end
885
+ end
778
886
  end
@@ -100,17 +100,43 @@ describe Shelly::Client do
100
100
  end
101
101
  end
102
102
 
103
- describe "#cloud_logs" do
103
+ describe "#deploy_logs" do
104
104
  it "should send get request" do
105
105
  time = Time.now
106
106
  FakeWeb.register_uri(:get, @url + "/apps/staging-foo/deploys", :body => [{:failed => false, :created_at => time},
107
107
  {:failed => true, :created_at => time+1}].to_json)
108
- response = @client.cloud_logs("staging-foo")
108
+ response = @client.deploy_logs("staging-foo")
109
109
  response.should == [{"failed"=>false, "created_at"=>time.to_s},
110
110
  {"failed"=>true, "created_at"=>(time+1).to_s}]
111
111
  end
112
112
  end
113
113
 
114
+ describe "#deploy_log" do
115
+ it "should send get request with cloud and log" do
116
+ FakeWeb.register_uri(:get, @url + "/apps/staging-foo/deploys/2011-11-29-11-50-16", :body => {:content => "Log"}.to_json)
117
+ response = @client.deploy_log("staging-foo", "2011-11-29-11-50-16")
118
+ response.should == {"content" => "Log"}
119
+ end
120
+ end
121
+
122
+ describe "#app_configs" do
123
+ it "should send get request" do
124
+ FakeWeb.register_uri(:get, @url + "/apps/staging-foo/configs", :body => [{:created_by_user => true, :path => "config/app.yml"}].to_json)
125
+ response = @client.app_configs("staging-foo")
126
+ response.should == [{"created_by_user" => true, "path" => "config/app.yml"}]
127
+ end
128
+ end
129
+
130
+ describe "#application_logs" do
131
+ it "should send get request" do
132
+ time = Time.now
133
+ FakeWeb.register_uri(:get, @url + "/apps/staging-foo/logs",
134
+ :body => {:logs => ["application_log_1", "application_log_2"]}.to_json)
135
+ response = @client.application_logs("staging-foo")
136
+ response.should == {"logs" => ["application_log_1", "application_log_2"]}
137
+ end
138
+ end
139
+
114
140
  describe "#create_app" do
115
141
  it "should send post with app's attributes" do
116
142
  @client.should_receive(:post).with("/apps", :app => {:code_name => "foo", :ruby_version => "1.9.2"})
metadata CHANGED
@@ -1,156 +1,202 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: shelly
3
- version: !ruby/object:Gem::Version
4
- version: 0.0.30
3
+ version: !ruby/object:Gem::Version
4
+ hash: 33
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 31
10
+ version: 0.0.31
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Shelly Cloud team
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2011-12-19 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
17
+
18
+ date: 2011-12-19 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
15
21
  name: rspec
16
- requirement: &70153945354720 !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
17
24
  none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
22
32
  type: :development
23
- prerelease: false
24
- version_requirements: *70153945354720
25
- - !ruby/object:Gem::Dependency
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
26
35
  name: rake
27
- requirement: &70153945354300 !ruby/object:Gem::Requirement
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
28
38
  none: false
29
- requirements:
30
- - - ! '>='
31
- - !ruby/object:Gem::Version
32
- version: '0'
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
33
46
  type: :development
34
- prerelease: false
35
- version_requirements: *70153945354300
36
- - !ruby/object:Gem::Dependency
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
37
49
  name: guard
38
- requirement: &70153945353880 !ruby/object:Gem::Requirement
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
39
52
  none: false
40
- requirements:
41
- - - ! '>='
42
- - !ruby/object:Gem::Version
43
- version: '0'
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
44
60
  type: :development
45
- prerelease: false
46
- version_requirements: *70153945353880
47
- - !ruby/object:Gem::Dependency
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
48
63
  name: guard-rspec
49
- requirement: &70153945353460 !ruby/object:Gem::Requirement
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
50
66
  none: false
51
- requirements:
52
- - - ! '>='
53
- - !ruby/object:Gem::Version
54
- version: '0'
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
55
74
  type: :development
56
- prerelease: false
57
- version_requirements: *70153945353460
58
- - !ruby/object:Gem::Dependency
75
+ version_requirements: *id004
76
+ - !ruby/object:Gem::Dependency
59
77
  name: growl_notify
60
- requirement: &70153945353000 !ruby/object:Gem::Requirement
78
+ prerelease: false
79
+ requirement: &id005 !ruby/object:Gem::Requirement
61
80
  none: false
62
- requirements:
63
- - - ! '>='
64
- - !ruby/object:Gem::Version
65
- version: '0'
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ hash: 3
85
+ segments:
86
+ - 0
87
+ version: "0"
66
88
  type: :development
67
- prerelease: false
68
- version_requirements: *70153945353000
69
- - !ruby/object:Gem::Dependency
89
+ version_requirements: *id005
90
+ - !ruby/object:Gem::Dependency
70
91
  name: rb-fsevent
71
- requirement: &70153945352580 !ruby/object:Gem::Requirement
92
+ prerelease: false
93
+ requirement: &id006 !ruby/object:Gem::Requirement
72
94
  none: false
73
- requirements:
74
- - - ! '>='
75
- - !ruby/object:Gem::Version
76
- version: '0'
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ hash: 3
99
+ segments:
100
+ - 0
101
+ version: "0"
77
102
  type: :development
78
- prerelease: false
79
- version_requirements: *70153945352580
80
- - !ruby/object:Gem::Dependency
103
+ version_requirements: *id006
104
+ - !ruby/object:Gem::Dependency
81
105
  name: fakefs
82
- requirement: &70153945352160 !ruby/object:Gem::Requirement
106
+ prerelease: false
107
+ requirement: &id007 !ruby/object:Gem::Requirement
83
108
  none: false
84
- requirements:
85
- - - ! '>='
86
- - !ruby/object:Gem::Version
87
- version: '0'
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ hash: 3
113
+ segments:
114
+ - 0
115
+ version: "0"
88
116
  type: :development
89
- prerelease: false
90
- version_requirements: *70153945352160
91
- - !ruby/object:Gem::Dependency
117
+ version_requirements: *id007
118
+ - !ruby/object:Gem::Dependency
92
119
  name: fakeweb
93
- requirement: &70153945351740 !ruby/object:Gem::Requirement
120
+ prerelease: false
121
+ requirement: &id008 !ruby/object:Gem::Requirement
94
122
  none: false
95
- requirements:
96
- - - ! '>='
97
- - !ruby/object:Gem::Version
98
- version: '0'
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ hash: 3
127
+ segments:
128
+ - 0
129
+ version: "0"
99
130
  type: :development
100
- prerelease: false
101
- version_requirements: *70153945351740
102
- - !ruby/object:Gem::Dependency
131
+ version_requirements: *id008
132
+ - !ruby/object:Gem::Dependency
103
133
  name: wijet-thor
104
- requirement: &70153945351240 !ruby/object:Gem::Requirement
134
+ prerelease: false
135
+ requirement: &id009 !ruby/object:Gem::Requirement
105
136
  none: false
106
- requirements:
137
+ requirements:
107
138
  - - ~>
108
- - !ruby/object:Gem::Version
139
+ - !ruby/object:Gem::Version
140
+ hash: 41
141
+ segments:
142
+ - 0
143
+ - 14
144
+ - 7
109
145
  version: 0.14.7
110
146
  type: :runtime
111
- prerelease: false
112
- version_requirements: *70153945351240
113
- - !ruby/object:Gem::Dependency
147
+ version_requirements: *id009
148
+ - !ruby/object:Gem::Dependency
114
149
  name: rest-client
115
- requirement: &70153945350820 !ruby/object:Gem::Requirement
150
+ prerelease: false
151
+ requirement: &id010 !ruby/object:Gem::Requirement
116
152
  none: false
117
- requirements:
118
- - - ! '>='
119
- - !ruby/object:Gem::Version
120
- version: '0'
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ hash: 3
157
+ segments:
158
+ - 0
159
+ version: "0"
121
160
  type: :runtime
122
- prerelease: false
123
- version_requirements: *70153945350820
124
- - !ruby/object:Gem::Dependency
161
+ version_requirements: *id010
162
+ - !ruby/object:Gem::Dependency
125
163
  name: json
126
- requirement: &70153945350280 !ruby/object:Gem::Requirement
164
+ prerelease: false
165
+ requirement: &id011 !ruby/object:Gem::Requirement
127
166
  none: false
128
- requirements:
129
- - - ! '>='
130
- - !ruby/object:Gem::Version
131
- version: '0'
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ hash: 3
171
+ segments:
172
+ - 0
173
+ version: "0"
132
174
  type: :runtime
133
- prerelease: false
134
- version_requirements: *70153945350280
135
- - !ruby/object:Gem::Dependency
175
+ version_requirements: *id011
176
+ - !ruby/object:Gem::Dependency
136
177
  name: wijet-launchy
137
- requirement: &70153945365700 !ruby/object:Gem::Requirement
178
+ prerelease: false
179
+ requirement: &id012 !ruby/object:Gem::Requirement
138
180
  none: false
139
- requirements:
140
- - - ! '>='
141
- - !ruby/object:Gem::Version
142
- version: '0'
181
+ requirements:
182
+ - - ">="
183
+ - !ruby/object:Gem::Version
184
+ hash: 3
185
+ segments:
186
+ - 0
187
+ version: "0"
143
188
  type: :runtime
144
- prerelease: false
145
- version_requirements: *70153945365700
189
+ version_requirements: *id012
146
190
  description: Tool for managing applications and clouds at shellycloud.com
147
- email:
191
+ email:
148
192
  - support@shellycloud.com
149
- executables:
193
+ executables:
150
194
  - shelly
151
195
  extensions: []
196
+
152
197
  extra_rdoc_files: []
153
- files:
198
+
199
+ files:
154
200
  - .gitignore
155
201
  - .travis.yml
156
202
  - Gemfile
@@ -163,6 +209,7 @@ files:
163
209
  - lib/shelly.rb
164
210
  - lib/shelly/app.rb
165
211
  - lib/shelly/cli/command.rb
212
+ - lib/shelly/cli/config.rb
166
213
  - lib/shelly/cli/deploys.rb
167
214
  - lib/shelly/cli/main.rb
168
215
  - lib/shelly/cli/runner.rb
@@ -181,6 +228,7 @@ files:
181
228
  - spec/helpers.rb
182
229
  - spec/input_faker.rb
183
230
  - spec/shelly/app_spec.rb
231
+ - spec/shelly/cli/config_spec.rb
184
232
  - spec/shelly/cli/deploys_spec.rb
185
233
  - spec/shelly/cli/main_spec.rb
186
234
  - spec/shelly/cli/runner_spec.rb
@@ -193,32 +241,42 @@ files:
193
241
  - spec/thor/options_spec.rb
194
242
  homepage: http://shellycloud.com
195
243
  licenses: []
244
+
196
245
  post_install_message:
197
246
  rdoc_options: []
198
- require_paths:
247
+
248
+ require_paths:
199
249
  - lib
200
- required_ruby_version: !ruby/object:Gem::Requirement
250
+ required_ruby_version: !ruby/object:Gem::Requirement
201
251
  none: false
202
- requirements:
203
- - - ! '>='
204
- - !ruby/object:Gem::Version
205
- version: '0'
206
- required_rubygems_version: !ruby/object:Gem::Requirement
252
+ requirements:
253
+ - - ">="
254
+ - !ruby/object:Gem::Version
255
+ hash: 3
256
+ segments:
257
+ - 0
258
+ version: "0"
259
+ required_rubygems_version: !ruby/object:Gem::Requirement
207
260
  none: false
208
- requirements:
209
- - - ! '>='
210
- - !ruby/object:Gem::Version
211
- version: '0'
261
+ requirements:
262
+ - - ">="
263
+ - !ruby/object:Gem::Version
264
+ hash: 3
265
+ segments:
266
+ - 0
267
+ version: "0"
212
268
  requirements: []
269
+
213
270
  rubyforge_project: shelly
214
271
  rubygems_version: 1.8.10
215
272
  signing_key:
216
273
  specification_version: 3
217
274
  summary: Shelly Cloud command line tool
218
- test_files:
275
+ test_files:
219
276
  - spec/helpers.rb
220
277
  - spec/input_faker.rb
221
278
  - spec/shelly/app_spec.rb
279
+ - spec/shelly/cli/config_spec.rb
222
280
  - spec/shelly/cli/deploys_spec.rb
223
281
  - spec/shelly/cli/main_spec.rb
224
282
  - spec/shelly/cli/runner_spec.rb