strobe 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/strobe +2 -12
- data/lib/strobe.rb +35 -88
- data/lib/strobe/association.rb +86 -0
- data/lib/strobe/cli.rb +39 -53
- data/lib/strobe/cli/action.rb +131 -0
- data/lib/strobe/cli/actions.rb +103 -0
- data/lib/strobe/cli/settings.rb +62 -0
- data/lib/strobe/collection.rb +53 -0
- data/lib/strobe/connection.rb +91 -0
- data/lib/strobe/resource/base.rb +235 -0
- data/lib/strobe/resource/collection.rb +50 -0
- data/lib/strobe/resource/singleton.rb +18 -0
- data/lib/strobe/resources/account.rb +12 -0
- data/lib/strobe/resources/application.rb +129 -0
- data/lib/strobe/resources/me.rb +11 -0
- data/lib/strobe/resources/signup.rb +27 -0
- data/lib/strobe/resources/team.rb +13 -0
- data/lib/strobe/resources/user.rb +11 -0
- data/lib/strobe/validations.rb +118 -0
- metadata +50 -124
- data/.gitignore +0 -5
- data/Gemfile +0 -4
- data/Gemfile.lock +0 -69
- data/Rakefile +0 -36
- data/features/1_sign_up.feature +0 -16
- data/features/2_deploying.feature +0 -35
- data/features/3_deploying_sproutcore_apps.feature +0 -19
- data/features/step_definitions/cli_steps.rb +0 -8
- data/features/step_definitions/deploying_steps.rb +0 -58
- data/features/step_definitions/sign_up.rb +0 -74
- data/features/support/helpers.rb +0 -104
- data/features/support/strobe.rb +0 -57
- data/lib/strobe/account.rb +0 -67
- data/lib/strobe/deploy.rb +0 -131
- data/lib/strobe/errors.rb +0 -12
- data/lib/strobe/http.rb +0 -94
- data/lib/strobe/server.rb +0 -13
- data/lib/strobe/settings.rb +0 -56
- data/lib/strobe/ui.rb +0 -81
- data/lib/strobe/user.rb +0 -9
- data/lib/strobe/version.rb +0 -3
- data/strobe.gemspec +0 -35
data/lib/strobe/account.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
require "excon"
|
2
|
-
require "json"
|
3
|
-
|
4
|
-
class Strobe
|
5
|
-
class Account
|
6
|
-
def self.signup_or_login
|
7
|
-
Strobe.ui.info "You aren't logged in with a Strobe user on this machine"
|
8
|
-
Strobe.ui.info " 1. Create a new Strobe user"
|
9
|
-
Strobe.ui.info " 2. Log in with an existing Strobe user"
|
10
|
-
option = Strobe.ui.ask "Please select an option: "
|
11
|
-
|
12
|
-
case option
|
13
|
-
when "1"
|
14
|
-
signup
|
15
|
-
when "2"
|
16
|
-
login
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.signup
|
21
|
-
while true
|
22
|
-
email, pass = ask_for_login
|
23
|
-
passc = Strobe.ui.password "Repeat Password: "
|
24
|
-
break if pass == passc
|
25
|
-
|
26
|
-
Strobe.ui.info "The password and confirmation do not match. Please try again."
|
27
|
-
end
|
28
|
-
|
29
|
-
response = HTTP.new.signup(email, pass)
|
30
|
-
persist_details(*response)
|
31
|
-
|
32
|
-
Strobe.ui.info "Your account was created successfully."
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.login
|
36
|
-
email, pass = ask_for_login
|
37
|
-
|
38
|
-
response = HTTP.new.login(email, pass)
|
39
|
-
persist_details(*response)
|
40
|
-
|
41
|
-
Strobe.ui.info "You are now logged in as #{email}"
|
42
|
-
end
|
43
|
-
|
44
|
-
# we don't need the account for anything yet, so leave it
|
45
|
-
def initialize(json)
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
def self.ask_for_login
|
50
|
-
Strobe.ui.info "Please enter your Strobe username and password."
|
51
|
-
|
52
|
-
email = Strobe.ui.ask "Email: "
|
53
|
-
pass = Strobe.ui.password "Password: "
|
54
|
-
return email, pass
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.persist_details(user, account = nil, errors = nil)
|
58
|
-
if account && errors
|
59
|
-
raise Strobe::AccountError, "Account creation failed. Please try again.\n#{errors}"
|
60
|
-
elsif errors
|
61
|
-
raise Strobe::AccountError, "Log in failed. Please try again.\n#{errors}"
|
62
|
-
else
|
63
|
-
Strobe.settings[:token] = user.token
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
data/lib/strobe/deploy.rb
DELETED
@@ -1,131 +0,0 @@
|
|
1
|
-
require "excon"
|
2
|
-
require "json"
|
3
|
-
require "mime/types"
|
4
|
-
require "active_support/secure_random"
|
5
|
-
|
6
|
-
cache_manifest = MIME::Type.new("text/cache-manifest") { |m| m.extensions = %w(manifest) }
|
7
|
-
MIME::Types.add(cache_manifest)
|
8
|
-
|
9
|
-
class Strobe
|
10
|
-
class Deploy
|
11
|
-
def initialize(path)
|
12
|
-
@path = path
|
13
|
-
@connection, @method = Strobe.settings.app_connection_and_method
|
14
|
-
end
|
15
|
-
|
16
|
-
def deploy
|
17
|
-
Strobe::Account.signup_or_login unless Strobe.settings[:token]
|
18
|
-
|
19
|
-
application, errors = HTTP.new.deploy(multipart)
|
20
|
-
|
21
|
-
if errors
|
22
|
-
raise Strobe::ApplicationError, "Application creation failed. Please try again.\n#{errors}"
|
23
|
-
else
|
24
|
-
# Update this every time for now, in case the app has changed
|
25
|
-
# on the server. This assumes that the server returns JSON
|
26
|
-
Strobe.settings.set_local(:application, application)
|
27
|
-
Strobe.ui.confirm "Your app was successfully deployed on #{application["url"]}"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def multipart
|
32
|
-
Multipart.new do |m|
|
33
|
-
if application = Strobe.settings[:application]
|
34
|
-
name = application["name"]
|
35
|
-
url = application["url"]
|
36
|
-
else
|
37
|
-
name = Strobe.ui.ask "Please enter your application's name: "
|
38
|
-
url = Strobe.ui.ask "URL to deploy to: "
|
39
|
-
end
|
40
|
-
|
41
|
-
m.name name
|
42
|
-
m.url url
|
43
|
-
|
44
|
-
Dir["#{@path}/**/*"].each do |file|
|
45
|
-
next unless File.file?(file)
|
46
|
-
|
47
|
-
filename = file.sub(/^#{@path}/, '')
|
48
|
-
mime_type = MIME::Types.type_for(file).first
|
49
|
-
m.file filename, mime_type ? mime_type.to_s : "application/octet-stream", File.read(file)
|
50
|
-
end
|
51
|
-
|
52
|
-
apps = []
|
53
|
-
|
54
|
-
Dir["#{@path}/static/*"].each do |app|
|
55
|
-
next if File.file?(app)
|
56
|
-
|
57
|
-
dir = File.basename(app)
|
58
|
-
index = Dir["#{app}/*/*/index.html"].first
|
59
|
-
|
60
|
-
next if !index || !File.file?(index)
|
61
|
-
|
62
|
-
index = File.read(index)
|
63
|
-
apps << index
|
64
|
-
|
65
|
-
m.file "#{dir}/index.html", "text/html", index
|
66
|
-
end
|
67
|
-
|
68
|
-
m.file "index.html", "text/html", apps.first if apps.size == 1
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
class Multipart
|
73
|
-
def initialize
|
74
|
-
@name = nil
|
75
|
-
@url = nil
|
76
|
-
@files = []
|
77
|
-
yield self if block_given?
|
78
|
-
end
|
79
|
-
|
80
|
-
def name(name)
|
81
|
-
@name = name
|
82
|
-
end
|
83
|
-
|
84
|
-
def url(url)
|
85
|
-
@url = url
|
86
|
-
end
|
87
|
-
|
88
|
-
def file(path, content_type, body)
|
89
|
-
@files << [path, content_type, body]
|
90
|
-
end
|
91
|
-
|
92
|
-
def headers
|
93
|
-
{ "Content-Type" => %[multipart/form-data; boundary="#{boundary}"] }
|
94
|
-
end
|
95
|
-
|
96
|
-
def body
|
97
|
-
b = "--#{boundary}\r\n"
|
98
|
-
b << part("metadata", "application/json", metadata)
|
99
|
-
b << "--#{boundary}\r\n"
|
100
|
-
|
101
|
-
@files.each do |path, type, body|
|
102
|
-
b << part("files[]", type, body)
|
103
|
-
b << "--#{boundary}\r\n"
|
104
|
-
end
|
105
|
-
|
106
|
-
b
|
107
|
-
end
|
108
|
-
|
109
|
-
private
|
110
|
-
|
111
|
-
def boundary
|
112
|
-
@boundary ||= ActiveSupport::SecureRandom.hex(25)
|
113
|
-
end
|
114
|
-
|
115
|
-
def metadata
|
116
|
-
hash = { "name" => @name, "url" => @url }
|
117
|
-
hash.merge!( "paths" => @files.map { |path,*| path } )
|
118
|
-
hash.to_json
|
119
|
-
end
|
120
|
-
|
121
|
-
def part(name, type, body)
|
122
|
-
b = ""
|
123
|
-
b << %[Content-Disposition: form-data; name="#{name}"; filename="array"\r\n]
|
124
|
-
b << %[Content-Type: #{type}\r\n]
|
125
|
-
b << %[\r\n]
|
126
|
-
b << body
|
127
|
-
b << %[\r\n]
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
data/lib/strobe/errors.rb
DELETED
data/lib/strobe/http.rb
DELETED
@@ -1,94 +0,0 @@
|
|
1
|
-
class Strobe
|
2
|
-
class HTTP
|
3
|
-
def signup(email, pass)
|
4
|
-
body = {
|
5
|
-
:account => {:name => "default"},
|
6
|
-
:user => {:email => email, :password => pass}
|
7
|
-
}.to_json
|
8
|
-
|
9
|
-
response = http_request(
|
10
|
-
"POST",
|
11
|
-
Strobe.settings.url("accounts"),
|
12
|
-
{"Content-Type" => "application/json"},
|
13
|
-
body
|
14
|
-
)
|
15
|
-
|
16
|
-
# user, account, error
|
17
|
-
|
18
|
-
json = JSON.parse(response.body)
|
19
|
-
|
20
|
-
if error = json["error"]
|
21
|
-
return nil, nil, error_messages(error)
|
22
|
-
else
|
23
|
-
user = json["user"] && User.new(json["user"])
|
24
|
-
account = json["account"] ? Account.new(json["account"]) : true
|
25
|
-
errors = json["errors"] && error_messages(json["errors"])
|
26
|
-
return user, account, errors
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def login(email, pass)
|
31
|
-
response = http_request(
|
32
|
-
"GET",
|
33
|
-
Strobe.settings.url("account"),
|
34
|
-
{"Content-Type" => "application/json"}.merge(auth_header(email, pass))
|
35
|
-
)
|
36
|
-
|
37
|
-
json = JSON.parse(response.body)
|
38
|
-
|
39
|
-
if error = json["error"]
|
40
|
-
return nil, nil, "The email and password were invalid"
|
41
|
-
else
|
42
|
-
user = json["user"] && User.new(json["user"])
|
43
|
-
errors = json["errors"] && error_messages(json["errors"])
|
44
|
-
return user, nil, errors
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def deploy(deployment)
|
49
|
-
connection, method = Strobe.settings.app_connection_and_method
|
50
|
-
|
51
|
-
response = connection.request(
|
52
|
-
:method => method,
|
53
|
-
:headers => auth_header.merge(deployment.headers),
|
54
|
-
:body => deployment.body.force_encoding("BINARY")
|
55
|
-
)
|
56
|
-
|
57
|
-
json = JSON.parse(response.body)
|
58
|
-
|
59
|
-
if error = json["error"]
|
60
|
-
return nil, error
|
61
|
-
else
|
62
|
-
application = json["application"]
|
63
|
-
errors = json["errors"] && error_messages(json["errors"])
|
64
|
-
return application, errors
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
private
|
69
|
-
def http_request(method, uri, headers = {}, body = nil)
|
70
|
-
connection = Excon::Connection.new(uri)
|
71
|
-
connection.request(:method => method, :headers => headers, :body => body)
|
72
|
-
end
|
73
|
-
|
74
|
-
def auth_header(username=Strobe.settings[:token], password=nil)
|
75
|
-
header = "Basic " << ["#{username}:#{password}"].pack("m")
|
76
|
-
header.gsub!(/\n/, '')
|
77
|
-
{"Authorization" => header}
|
78
|
-
end
|
79
|
-
|
80
|
-
def error_messages(errors)
|
81
|
-
messages = []
|
82
|
-
errors.each do |k, v|
|
83
|
-
if v
|
84
|
-
v.each do |field, error|
|
85
|
-
messages << " * #{field} #{error}"
|
86
|
-
end
|
87
|
-
else
|
88
|
-
messages << " * #{k}"
|
89
|
-
end
|
90
|
-
end
|
91
|
-
messages.join("\n")
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
data/lib/strobe/server.rb
DELETED
data/lib/strobe/settings.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
require "excon"
|
2
|
-
|
3
|
-
class Strobe
|
4
|
-
class Settings
|
5
|
-
def initialize
|
6
|
-
@location = ENV["STROBE_SETTINGS"] || Strobe.config_dir.join("config")
|
7
|
-
@local = ENV["STROBE_APP_CONFIG"] || Strobe.local_config_dir.join("config")
|
8
|
-
@hash = File.file?(@location) ? YAML.load(@location) : {}
|
9
|
-
@local_hash = File.file?(@local) ? YAML.load(@local) : {}
|
10
|
-
end
|
11
|
-
|
12
|
-
def [](key)
|
13
|
-
ENV[key_for(key)] || @local_hash[key_for(key)] || @hash[key_for(key)]
|
14
|
-
end
|
15
|
-
|
16
|
-
def []=(key, value)
|
17
|
-
@hash[key_for(key)] = value
|
18
|
-
File.open(@location, "wb") { |file| file.puts @hash.to_yaml }
|
19
|
-
value
|
20
|
-
end
|
21
|
-
|
22
|
-
def set_local(key, value)
|
23
|
-
@local_hash[key_for(key)] = value
|
24
|
-
File.open(@local, "wb") { |file| file.puts @local_hash.to_yaml }
|
25
|
-
end
|
26
|
-
|
27
|
-
def url(path)
|
28
|
-
self["url"] ||= "http://api.strobeapp.com/"
|
29
|
-
self["url"] + path
|
30
|
-
end
|
31
|
-
|
32
|
-
def auth_header(username=self[:token], password=nil)
|
33
|
-
header = "Basic " << ["#{username}:#{password}"].pack("m")
|
34
|
-
header.gsub!(/\n/, '')
|
35
|
-
{"Authorization" => header}
|
36
|
-
end
|
37
|
-
|
38
|
-
def app_connection_and_method
|
39
|
-
app_url = url("applications")
|
40
|
-
|
41
|
-
if application = self[:application]
|
42
|
-
app_url << "/#{application["id"]}"
|
43
|
-
method = "PUT"
|
44
|
-
else
|
45
|
-
method = "POST"
|
46
|
-
end
|
47
|
-
|
48
|
-
return Excon::Connection.new(app_url), method
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
def key_for(key)
|
53
|
-
"STROBE_#{key.to_s.upcase}"
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
data/lib/strobe/ui.rb
DELETED
@@ -1,81 +0,0 @@
|
|
1
|
-
require "highline"
|
2
|
-
|
3
|
-
class Strobe
|
4
|
-
module UI
|
5
|
-
class Basic
|
6
|
-
def debug(msg)
|
7
|
-
puts msg
|
8
|
-
end
|
9
|
-
|
10
|
-
def info(msg)
|
11
|
-
puts msg
|
12
|
-
end
|
13
|
-
|
14
|
-
def confirm(msg)
|
15
|
-
puts msg
|
16
|
-
end
|
17
|
-
|
18
|
-
def warn(msg)
|
19
|
-
puts msg
|
20
|
-
end
|
21
|
-
|
22
|
-
def error(msg)
|
23
|
-
puts msg
|
24
|
-
end
|
25
|
-
|
26
|
-
def highline
|
27
|
-
@highline ||= HighLine.new
|
28
|
-
end
|
29
|
-
|
30
|
-
def password(message)
|
31
|
-
highline.ask(message) do |q|
|
32
|
-
next unless STDIN.tty?
|
33
|
-
q.echo = "*"
|
34
|
-
end
|
35
|
-
rescue EOFError
|
36
|
-
''
|
37
|
-
end
|
38
|
-
|
39
|
-
def ask(message)
|
40
|
-
highline.ask(message) do |q|
|
41
|
-
next unless STDIN.tty?
|
42
|
-
q.readline = true
|
43
|
-
end
|
44
|
-
rescue EOFError
|
45
|
-
''
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
class Shell < Basic
|
50
|
-
def initialize(shell)
|
51
|
-
@shell = shell
|
52
|
-
@quiet = false
|
53
|
-
end
|
54
|
-
|
55
|
-
def debug(msg)
|
56
|
-
@shell.say(msg) if ENV['DEBUG'] && !@quiet
|
57
|
-
end
|
58
|
-
|
59
|
-
def info(msg)
|
60
|
-
@shell.say(msg) if !@quiet
|
61
|
-
end
|
62
|
-
|
63
|
-
def confirm(msg)
|
64
|
-
@shell.say(msg, :green) if !@quiet
|
65
|
-
end
|
66
|
-
|
67
|
-
def warn(msg)
|
68
|
-
@shell.say(msg, :yellow)
|
69
|
-
end
|
70
|
-
|
71
|
-
def error(msg)
|
72
|
-
@shell.say(msg, :red)
|
73
|
-
end
|
74
|
-
|
75
|
-
def be_quiet!
|
76
|
-
@quiet = true
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|