shelly 0.0.37 → 0.0.38
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/shelly.rb +4 -0
- data/lib/shelly/app.rb +14 -7
- data/lib/shelly/cli/backup.rb +3 -3
- data/lib/shelly/cli/command.rb +2 -0
- data/lib/shelly/cli/config.rb +8 -15
- data/lib/shelly/cli/deploys.rb +3 -3
- data/lib/shelly/cli/main.rb +7 -15
- data/lib/shelly/cli/runner.rb +2 -2
- data/lib/shelly/cli/user.rb +5 -5
- data/lib/shelly/client.rb +4 -4
- data/lib/shelly/helpers.rb +8 -1
- data/lib/shelly/version.rb +1 -1
- data/lib/thor/thor.rb +28 -0
- data/spec/helpers.rb +4 -0
- data/spec/shelly/app_spec.rb +24 -7
- data/spec/shelly/cli/backup_spec.rb +20 -17
- data/spec/shelly/cli/config_spec.rb +37 -36
- data/spec/shelly/cli/deploys_spec.rb +14 -11
- data/spec/shelly/cli/main_spec.rb +85 -107
- data/spec/shelly/cli/runner_spec.rb +9 -1
- data/spec/shelly/cli/user_spec.rb +25 -12
- data/spec/shelly/client_spec.rb +7 -6
- data/spec/shelly/cloudfile_spec.rb +11 -0
- metadata +151 -158
data/lib/shelly.rb
CHANGED
data/lib/shelly/app.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
require 'erb'
|
2
2
|
require 'launchy'
|
3
|
+
require "shelly/backup"
|
3
4
|
|
4
5
|
module Shelly
|
5
6
|
class App < Model
|
6
7
|
DATABASE_KINDS = %w(postgresql mongodb redis none)
|
7
8
|
|
8
9
|
attr_accessor :code_name, :databases, :ruby_version, :environment,
|
9
|
-
:git_url, :domains
|
10
|
-
|
11
|
-
autoload :Backup, "shelly/backup"
|
10
|
+
:git_url, :domains, :web_server_ip, :mail_server_ip
|
12
11
|
|
13
12
|
def initialize(code_name = nil)
|
14
13
|
self.code_name = code_name
|
@@ -99,10 +98,6 @@ module Shelly
|
|
99
98
|
File.basename(Dir.pwd)
|
100
99
|
end
|
101
100
|
|
102
|
-
def ips
|
103
|
-
shelly.app_ips(code_name)
|
104
|
-
end
|
105
|
-
|
106
101
|
def users
|
107
102
|
shelly.app_users(code_name)
|
108
103
|
end
|
@@ -135,6 +130,18 @@ module Shelly
|
|
135
130
|
shelly.app_delete_config(code_name, path)
|
136
131
|
end
|
137
132
|
|
133
|
+
def attributes
|
134
|
+
@attributes ||= shelly.app(code_name)
|
135
|
+
end
|
136
|
+
|
137
|
+
def web_server_ip
|
138
|
+
attributes["web_server_ip"]
|
139
|
+
end
|
140
|
+
|
141
|
+
def mail_server_ip
|
142
|
+
attributes["mail_server_ip"]
|
143
|
+
end
|
144
|
+
|
138
145
|
def open_billing_page
|
139
146
|
url = "#{shelly.shellyapp_url}/login?api_key=#{current_user.token}&return_to=/apps/#{code_name}/edit_billing"
|
140
147
|
Launchy.open(url)
|
data/lib/shelly/cli/backup.rb
CHANGED
@@ -8,12 +8,13 @@ module Shelly
|
|
8
8
|
namespace :backup
|
9
9
|
include Helpers
|
10
10
|
|
11
|
+
before_hook :logged_in?, :only => [:list, :get, :create]
|
12
|
+
before_hook :cloudfile_present?, :only => [:list]
|
13
|
+
|
11
14
|
desc "list", "List database backups"
|
12
15
|
method_option :cloud, :type => :string, :aliases => "-c",
|
13
16
|
:desc => "Specify which cloud to list backups for"
|
14
17
|
def list
|
15
|
-
logged_in?
|
16
|
-
say_error "No Cloudfile found" unless Cloudfile.present?
|
17
18
|
multiple_clouds(options[:cloud], "backup list", "Select cloud to view database backups for using:")
|
18
19
|
backups = @app.database_backups
|
19
20
|
if backups.present?
|
@@ -60,7 +61,6 @@ module Shelly
|
|
60
61
|
method_option :cloud, :type => :string, :aliases => "-c",
|
61
62
|
:desc => "Specify which cloud to create database snapshot for"
|
62
63
|
def create(kind = nil)
|
63
|
-
logged_in?
|
64
64
|
multiple_clouds(options[:cloud], "backup create", "Select cloud to create snapshot of database")
|
65
65
|
@app.request_backup(kind)
|
66
66
|
say "Backup requested. It can take up to several minutes for" +
|
data/lib/shelly/cli/command.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "shelly"
|
2
2
|
require "thor"
|
3
|
+
require "thor/thor"
|
3
4
|
require "thor/group"
|
4
5
|
require "thor/options"
|
5
6
|
require "thor/arguments"
|
@@ -8,6 +9,7 @@ require "thor/basic"
|
|
8
9
|
module Shelly
|
9
10
|
module CLI
|
10
11
|
class Command < Thor
|
12
|
+
include Helpers
|
11
13
|
class_option :debug, :type => :boolean, :desc => "Show debug information"
|
12
14
|
end
|
13
15
|
end
|
data/lib/shelly/cli/config.rb
CHANGED
@@ -6,10 +6,11 @@ module Shelly
|
|
6
6
|
include Thor::Actions
|
7
7
|
include Helpers
|
8
8
|
|
9
|
+
before_hook :logged_in?, :only => [:list, :show, :create, :edit, :delete]
|
10
|
+
before_hook :cloudfile_present?, :only => [:list, :show, :create, :edit, :delete]
|
11
|
+
|
9
12
|
desc "list", "List configuration files"
|
10
13
|
def list
|
11
|
-
logged_in?
|
12
|
-
say_error "No Cloudfile found" unless Cloudfile.present?
|
13
14
|
cloudfile = Cloudfile.new
|
14
15
|
cloudfile.clouds.each do |cloud|
|
15
16
|
@app = App.new(cloud)
|
@@ -46,8 +47,6 @@ module Shelly
|
|
46
47
|
:desc => "Specify which cloud to show configuration file for"
|
47
48
|
desc "show PATH", "View configuration file"
|
48
49
|
def show(path = nil)
|
49
|
-
logged_in?
|
50
|
-
say_error "No Cloudfile found" unless Cloudfile.present?
|
51
50
|
say_error "No configuration file specified" unless path
|
52
51
|
multiple_clouds(options[:cloud], "show #{path}", "Specify cloud using:")
|
53
52
|
config = @app.config(path)
|
@@ -61,11 +60,9 @@ module Shelly
|
|
61
60
|
|
62
61
|
map "new" => :create
|
63
62
|
method_option :cloud, :type => :string, :aliases => "-c",
|
64
|
-
:desc => "Specify
|
63
|
+
:desc => "Specify which cloud to create configuration file for"
|
65
64
|
desc "create PATH", "Create configuration file"
|
66
65
|
def create(path = nil)
|
67
|
-
logged_in?
|
68
|
-
say_error "No Cloudfile found" unless Cloudfile.present?
|
69
66
|
say_error "No path specified" unless path
|
70
67
|
output = open_editor(path)
|
71
68
|
multiple_clouds(options[:cloud], "create #{path}", "Specify cloud using:")
|
@@ -84,11 +81,9 @@ module Shelly
|
|
84
81
|
|
85
82
|
map "update" => :edit
|
86
83
|
method_option :cloud, :type => :string, :aliases => "-c",
|
87
|
-
:desc => "Specify
|
84
|
+
:desc => "Specify which cloud to edit configuration file for"
|
88
85
|
desc "edit PATH", "Edit configuration file"
|
89
86
|
def edit(path = nil)
|
90
|
-
logged_in?
|
91
|
-
say_error "No Cloudfile found" unless Cloudfile.present?
|
92
87
|
say_error "No configuration file specified" unless path
|
93
88
|
multiple_clouds(options[:cloud], "edit #{path}", "Specify cloud using:")
|
94
89
|
config = @app.config(path)
|
@@ -107,15 +102,13 @@ module Shelly
|
|
107
102
|
end
|
108
103
|
|
109
104
|
method_option :cloud, :type => :string, :aliases => "-c",
|
110
|
-
:desc => "Specify for which cloud delete configuration file"
|
105
|
+
:desc => "Specify for which cloud to delete configuration file for"
|
111
106
|
desc "delete PATH", "Delete configuration file"
|
112
107
|
def delete(path = nil)
|
113
|
-
logged_in?
|
114
|
-
say_error "No Cloudfile found" unless Cloudfile.present?
|
115
108
|
say_error "No configuration file specified" unless path
|
116
109
|
multiple_clouds(options[:cloud], "delete #{path}", "Specify cloud using:")
|
117
|
-
answer =
|
118
|
-
if answer
|
110
|
+
answer = yes?("Are you sure you want to delete 'path' (yes/no): ")
|
111
|
+
if answer
|
119
112
|
@app.delete_config(path)
|
120
113
|
say "File deleted, redeploy your cloud to make changes", :green
|
121
114
|
else
|
data/lib/shelly/cli/deploys.rb
CHANGED
@@ -7,12 +7,13 @@ module Shelly
|
|
7
7
|
namespace :deploys
|
8
8
|
include Helpers
|
9
9
|
|
10
|
+
before_hook :logged_in?, :only => [:list, :show]
|
11
|
+
before_hook :cloudfile_present?, :only => [:list, :show]
|
12
|
+
|
10
13
|
desc "list", "Lists deploy logs"
|
11
14
|
method_option :cloud, :type => :string, :aliases => "-c",
|
12
15
|
:desc => "Specify which cloud to show deploy logs for"
|
13
16
|
def list
|
14
|
-
logged_in?
|
15
|
-
say_error "No Cloudfile found" unless Cloudfile.present?
|
16
17
|
multiple_clouds(options[:cloud], "deploys list", "Select cloud to view deploy logs using:")
|
17
18
|
logs = @app.deploy_logs
|
18
19
|
unless logs.empty?
|
@@ -35,7 +36,6 @@ module Shelly
|
|
35
36
|
method_option :cloud, :type => :string, :aliases => "-c",
|
36
37
|
:desc => "Specify which cloud to show deploy logs for"
|
37
38
|
def show(log = nil)
|
38
|
-
say_error "No Cloudfile found" unless Cloudfile.present?
|
39
39
|
specify_log(log)
|
40
40
|
multiple_clouds(options[:cloud], "deploys show #{log}", "Select log and cloud to view deploy logs using:")
|
41
41
|
content = @app.deploy_log(log)
|
data/lib/shelly/cli/main.rb
CHANGED
@@ -8,13 +8,17 @@ module Shelly
|
|
8
8
|
module CLI
|
9
9
|
class Main < Command
|
10
10
|
include Thor::Actions
|
11
|
-
|
11
|
+
|
12
12
|
register(User, "user", "user <command>", "Manages users using this cloud")
|
13
13
|
register(Backup, "backup", "backup <command>", "Manages database backups from this cloud")
|
14
14
|
register(Deploys, "deploys", "deploys <command>", "View cloud deploy logs")
|
15
15
|
register(Config, "config", "config <command>", "Manages cloud configuration files")
|
16
16
|
check_unknown_options!
|
17
17
|
|
18
|
+
before_hook :logged_in?, :only => [:add, :list, :start, :stop, :logs, :delete]
|
19
|
+
before_hook :inside_git_repository?, :only => [:add, :ip]
|
20
|
+
before_hook :cloudfile_present?, :only => [:logs, :stop, :start, :ip]
|
21
|
+
|
18
22
|
map %w(-v --version) => :version
|
19
23
|
desc "version", "Displays shelly version"
|
20
24
|
def version
|
@@ -89,7 +93,6 @@ module Shelly
|
|
89
93
|
:desc => "Array of your domains"
|
90
94
|
desc "add", "Adds new cloud to Shelly Cloud"
|
91
95
|
def add
|
92
|
-
say_error "Must be run inside your project git repository" unless App.inside_git_repository?
|
93
96
|
check_options(options)
|
94
97
|
@app = Shelly::App.new
|
95
98
|
@app.code_name = options["code-name"] || ask_for_code_name
|
@@ -121,7 +124,6 @@ module Shelly
|
|
121
124
|
desc "list", "Lists all your clouds"
|
122
125
|
def list
|
123
126
|
user = Shelly::User.new
|
124
|
-
user.token
|
125
127
|
apps = user.apps
|
126
128
|
unless apps.empty?
|
127
129
|
say "You have following clouds available:", :green
|
@@ -141,16 +143,14 @@ module Shelly
|
|
141
143
|
|
142
144
|
desc "ip", "Lists clouds IP's"
|
143
145
|
def ip
|
144
|
-
say_error "Must be run inside your project git repository" unless App.inside_git_repository?
|
145
146
|
say_error "No Cloudfile found" unless Cloudfile.present?
|
146
147
|
@cloudfile = Cloudfile.new
|
147
148
|
@cloudfile.clouds.each do |cloud|
|
148
149
|
begin
|
149
150
|
@app = App.new(cloud)
|
150
151
|
say "Cloud #{cloud}:", :green
|
151
|
-
|
152
|
-
print_wrapped "
|
153
|
-
print_wrapped "Mail server IP: #{ips['mail_server_ip']}", :ident => 2
|
152
|
+
print_wrapped "Web server IP: #{@app.web_server_ip}", :ident => 2
|
153
|
+
print_wrapped "Mail server IP: #{@app.mail_server_ip}", :ident => 2
|
154
154
|
rescue Client::APIError => e
|
155
155
|
if e.unauthorized?
|
156
156
|
say_error "You have no access to '#{cloud}' cloud defined in Cloudfile", :with_exit => false
|
@@ -165,8 +165,6 @@ module Shelly
|
|
165
165
|
method_option :cloud, :type => :string, :aliases => "-c",
|
166
166
|
:desc => "Specify which cloud to start"
|
167
167
|
def start
|
168
|
-
logged_in?
|
169
|
-
say_error "No Cloudfile found" unless Cloudfile.present?
|
170
168
|
multiple_clouds(options[:cloud], "start", "Select cloud to start using:")
|
171
169
|
@app.start
|
172
170
|
say "Starting cloud #{@app.code_name}. Check status with:", :green
|
@@ -201,8 +199,6 @@ module Shelly
|
|
201
199
|
method_option :cloud, :type => :string, :aliases => "-c",
|
202
200
|
:desc => "Specify which cloud to stop"
|
203
201
|
def stop
|
204
|
-
logged_in?
|
205
|
-
say_error "No Cloudfile found" unless Cloudfile.present?
|
206
202
|
multiple_clouds(options[:cloud], "stop", "Select cloud to stop using:")
|
207
203
|
@app.stop
|
208
204
|
say "Cloud '#{@app.code_name}' stopped"
|
@@ -216,8 +212,6 @@ module Shelly
|
|
216
212
|
method_option :cloud, :type => :string, :aliases => "-c",
|
217
213
|
:desc => "Specify which cloud to delete"
|
218
214
|
def delete
|
219
|
-
user = Shelly::User.new
|
220
|
-
user.token
|
221
215
|
multiple_clouds(options[:cloud], "delete", "Select cloud to delete using:")
|
222
216
|
say "You are about to delete application: #{@app.code_name}."
|
223
217
|
say "Press Control-C at any moment to cancel."
|
@@ -244,8 +238,6 @@ module Shelly
|
|
244
238
|
:desc => "Specify which cloud to show logs for"
|
245
239
|
def logs
|
246
240
|
cloud = options[:cloud]
|
247
|
-
logged_in?
|
248
|
-
say_error "No Cloudfile found" unless Cloudfile.present?
|
249
241
|
multiple_clouds(cloud, "logs", "Select which to show logs for using:")
|
250
242
|
begin
|
251
243
|
logs = @app.application_logs
|
data/lib/shelly/cli/runner.rb
CHANGED
@@ -6,13 +6,13 @@ module Shelly
|
|
6
6
|
include Helpers
|
7
7
|
attr_accessor :args
|
8
8
|
|
9
|
-
def initialize(args)
|
9
|
+
def initialize(args = [])
|
10
10
|
super()
|
11
11
|
@args = args
|
12
12
|
end
|
13
13
|
|
14
14
|
def debug?
|
15
|
-
args.include?("--debug")
|
15
|
+
args.include?("--debug") || ENV['SHELLY_DEBUG'] == "true"
|
16
16
|
end
|
17
17
|
|
18
18
|
def start
|
data/lib/shelly/cli/user.rb
CHANGED
@@ -6,10 +6,12 @@ module Shelly
|
|
6
6
|
namespace :user
|
7
7
|
include Helpers
|
8
8
|
|
9
|
+
before_hook :logged_in?, :only => [:list, :add]
|
10
|
+
before_hook :inside_git_repository?, :only => [:list, :add]
|
11
|
+
before_hook :cloudfile_present?, :only => [:list, :add]
|
12
|
+
|
9
13
|
desc "list", "List users with access to clouds defined in Cloudfile"
|
10
14
|
def list
|
11
|
-
say_error "Must be run inside your project git repository" unless App.inside_git_repository?
|
12
|
-
say_error "No Cloudfile found" unless Cloudfile.present?
|
13
15
|
@cloudfile = Cloudfile.new
|
14
16
|
@cloudfile.clouds.each do |cloud|
|
15
17
|
begin
|
@@ -28,8 +30,6 @@ module Shelly
|
|
28
30
|
|
29
31
|
desc "add [EMAIL]", "Add new developer to clouds defined in Cloudfile"
|
30
32
|
def add(email = nil)
|
31
|
-
say_error "Must be run inside your project git repository" unless App.inside_git_repository?
|
32
|
-
say_error "No Cloudfile found" unless Cloudfile.present?
|
33
33
|
@cloudfile = Cloudfile.new
|
34
34
|
@user = Shelly::User.new
|
35
35
|
user_email = email || ask_for_email({:guess_email => false})
|
@@ -59,4 +59,4 @@ module Shelly
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
62
|
-
end
|
62
|
+
end
|
data/lib/shelly/client.rb
CHANGED
@@ -115,6 +115,10 @@ module Shelly
|
|
115
115
|
def apps
|
116
116
|
get("/apps")
|
117
117
|
end
|
118
|
+
|
119
|
+
def app(code_name)
|
120
|
+
get("/apps/#{code_name}")
|
121
|
+
end
|
118
122
|
|
119
123
|
def deploy_logs(cloud)
|
120
124
|
get("/apps/#{cloud}/deploys")
|
@@ -148,10 +152,6 @@ module Shelly
|
|
148
152
|
get("/apps/#{cloud}/users")
|
149
153
|
end
|
150
154
|
|
151
|
-
def app_ips(cloud)
|
152
|
-
get("/apps/#{cloud}/ips")
|
153
|
-
end
|
154
|
-
|
155
155
|
def post(path, params = {})
|
156
156
|
request(path, :post, params)
|
157
157
|
end
|
data/lib/shelly/helpers.rb
CHANGED
@@ -45,6 +45,14 @@ module Shelly
|
|
45
45
|
exit 1 unless delete_application == "yes"
|
46
46
|
end
|
47
47
|
|
48
|
+
def inside_git_repository?
|
49
|
+
say_error "Must be run inside your project git repository" unless App.inside_git_repository?
|
50
|
+
end
|
51
|
+
|
52
|
+
def cloudfile_present?
|
53
|
+
say_error "No Cloudfile found" unless Cloudfile.present?
|
54
|
+
end
|
55
|
+
|
48
56
|
def logged_in?
|
49
57
|
user = Shelly::User.new
|
50
58
|
user.token
|
@@ -74,4 +82,3 @@ module Shelly
|
|
74
82
|
|
75
83
|
end
|
76
84
|
end
|
77
|
-
|
data/lib/shelly/version.rb
CHANGED
data/lib/thor/thor.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
class Thor
|
2
|
+
class << self
|
3
|
+
def before_hook(method, options = {})
|
4
|
+
@hook = {} unless @hook
|
5
|
+
@hook[method] = options
|
6
|
+
end
|
7
|
+
|
8
|
+
def send(*args)
|
9
|
+
if args.first == :dispatch
|
10
|
+
running_task = args[2].first
|
11
|
+
@hook.each do |method, options|
|
12
|
+
if options[:only].include?(running_task.to_sym)
|
13
|
+
new.send(method)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def start(given_args=ARGV, config={})
|
21
|
+
config[:shell] ||= Thor::Base.shell.new
|
22
|
+
send(:dispatch, nil, given_args.dup, nil, config)
|
23
|
+
rescue Thor::Error => e
|
24
|
+
ENV["THOR_DEBUG"] == "1" ? (raise e) : config[:shell].error(e.message)
|
25
|
+
exit(1) if exit_on_failure?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/spec/helpers.rb
CHANGED
data/spec/shelly/app_spec.rb
CHANGED
@@ -24,13 +24,6 @@ describe Shelly::App do
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
describe "#ips" do
|
28
|
-
it "should get app's ips" do
|
29
|
-
@client.should_receive(:app_ips).with("foo-staging")
|
30
|
-
@app.ips
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
27
|
describe "#add_git_remote" do
|
35
28
|
before do
|
36
29
|
@app.stub(:git_url).and_return("git@git.shellycloud.com:foo-staging.git")
|
@@ -64,6 +57,30 @@ describe Shelly::App do
|
|
64
57
|
@app.shelly_generated_configs
|
65
58
|
end
|
66
59
|
end
|
60
|
+
|
61
|
+
describe "#attributes" do
|
62
|
+
before do
|
63
|
+
@response = {"web_server_ip" => "192.0.2.1", "mail_server_ip" => "192.0.2.3"}
|
64
|
+
@client.stub(:app).and_return(@response)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should fetch app attributes from API and cache them" do
|
68
|
+
@client.should_receive(:app).with("foo-staging").exactly(:once).and_return(@response)
|
69
|
+
2.times { @app.attributes }
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#web_server_ip" do
|
73
|
+
it "should return web server ip address" do
|
74
|
+
@app.web_server_ip.should == "192.0.2.1"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "#mail_server_ip" do
|
79
|
+
it "should return mail server ip address" do
|
80
|
+
@app.mail_server_ip.should == "192.0.2.3"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
67
84
|
|
68
85
|
describe "#generate_cloudfile" do
|
69
86
|
it "should return generated cloudfile" do
|