strobe 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +69 -0
- data/Rakefile +36 -0
- data/bin/strobe +14 -0
- data/features/1_sign_up.feature +16 -0
- data/features/2_deploying.feature +35 -0
- data/features/3_deploying_sproutcore_apps.feature +19 -0
- data/features/step_definitions/cli_steps.rb +8 -0
- data/features/step_definitions/deploying_steps.rb +58 -0
- data/features/step_definitions/sign_up.rb +74 -0
- data/features/support/helpers.rb +104 -0
- data/features/support/strobe.rb +57 -0
- data/lib/strobe.rb +118 -0
- data/lib/strobe/account.rb +67 -0
- data/lib/strobe/cli.rb +78 -0
- data/lib/strobe/deploy.rb +131 -0
- data/lib/strobe/errors.rb +12 -0
- data/lib/strobe/http.rb +94 -0
- data/lib/strobe/server.rb +13 -0
- data/lib/strobe/settings.rb +56 -0
- data/lib/strobe/ui.rb +81 -0
- data/lib/strobe/user.rb +9 -0
- data/lib/strobe/version.rb +3 -0
- data/strobe.gemspec +35 -0
- metadata +250 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
strobe (0.0.1)
|
5
|
+
activesupport (~> 3.0.0)
|
6
|
+
excon (~> 0.2.2)
|
7
|
+
highline (~> 1.6.1)
|
8
|
+
mime-types (= 1.16)
|
9
|
+
rack (~> 1.2.1)
|
10
|
+
thor (~> 0.14.1)
|
11
|
+
|
12
|
+
GEM
|
13
|
+
remote: http://rubygems.org/
|
14
|
+
specs:
|
15
|
+
activesupport (3.0.0)
|
16
|
+
builder (2.1.2)
|
17
|
+
childlabor (0.0.3)
|
18
|
+
cucumber (0.9.2)
|
19
|
+
builder (~> 2.1.2)
|
20
|
+
diff-lcs (~> 1.1.2)
|
21
|
+
gherkin (~> 2.2.5)
|
22
|
+
json (~> 1.4.6)
|
23
|
+
term-ansicolor (~> 1.0.5)
|
24
|
+
diff-lcs (1.1.2)
|
25
|
+
excon (0.2.3)
|
26
|
+
gherkin (2.2.8)
|
27
|
+
json (~> 1.4.6)
|
28
|
+
term-ansicolor (~> 1.0.5)
|
29
|
+
highline (1.6.1)
|
30
|
+
json (1.4.6)
|
31
|
+
mime-types (1.16)
|
32
|
+
prawn (0.8.4)
|
33
|
+
prawn-core (>= 0.8.4, < 0.9)
|
34
|
+
prawn-layout (>= 0.8.4, < 0.9)
|
35
|
+
prawn-security (>= 0.8.4, < 0.9)
|
36
|
+
prawn-core (0.8.4)
|
37
|
+
prawn-layout (0.8.4)
|
38
|
+
prawn-security (0.8.4)
|
39
|
+
rack (1.2.1)
|
40
|
+
rake (0.8.7)
|
41
|
+
rspec (2.0.0.beta.22)
|
42
|
+
rspec-core (= 2.0.0.beta.22)
|
43
|
+
rspec-expectations (= 2.0.0.beta.22)
|
44
|
+
rspec-mocks (= 2.0.0.beta.22)
|
45
|
+
rspec-core (2.0.0.beta.22)
|
46
|
+
rspec-expectations (2.0.0.beta.22)
|
47
|
+
diff-lcs (>= 1.1.2)
|
48
|
+
rspec-mocks (2.0.0.beta.22)
|
49
|
+
rspec-core (= 2.0.0.beta.22)
|
50
|
+
rspec-expectations (= 2.0.0.beta.22)
|
51
|
+
term-ansicolor (1.0.5)
|
52
|
+
thor (0.14.3)
|
53
|
+
|
54
|
+
PLATFORMS
|
55
|
+
ruby
|
56
|
+
|
57
|
+
DEPENDENCIES
|
58
|
+
activesupport (~> 3.0.0)
|
59
|
+
childlabor (= 0.0.3)
|
60
|
+
cucumber
|
61
|
+
excon (~> 0.2.2)
|
62
|
+
highline (~> 1.6.1)
|
63
|
+
mime-types (= 1.16)
|
64
|
+
prawn
|
65
|
+
rack (~> 1.2.1)
|
66
|
+
rake
|
67
|
+
rspec (~> 2.0.0)
|
68
|
+
strobe!
|
69
|
+
thor (~> 0.14.1)
|
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
RSpec::Core::RakeTask.new("spec") do |task|
|
6
|
+
task.rspec_opts = "-cfs"
|
7
|
+
task.ruby_opts = "-W"
|
8
|
+
end
|
9
|
+
|
10
|
+
namespace :man do
|
11
|
+
directory "lib/strobe/man"
|
12
|
+
|
13
|
+
Dir["man/*.ronn"].each do |ronn|
|
14
|
+
basename = File.basename(ronn, ".ronn")
|
15
|
+
roff = "lib/strobe/man/#{basename}"
|
16
|
+
|
17
|
+
file roff => ["lib/strobe/man", ronn] do
|
18
|
+
sh "ronn --roff --pipe #{ronn} > #{roff}"
|
19
|
+
end
|
20
|
+
|
21
|
+
file "#{roff}.txt" => roff do
|
22
|
+
sh "groff -Wall -mtty-char -mandoc -Tascii #{roff} | col -b > #{roff}.txt"
|
23
|
+
end
|
24
|
+
|
25
|
+
task :build => "#{roff}.txt"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "Build the man pages"
|
30
|
+
task :build => "man:build"
|
31
|
+
|
32
|
+
desc "Clean up from the built man pages"
|
33
|
+
task :clean do
|
34
|
+
rm_rf "lib/strobe/man"
|
35
|
+
end
|
36
|
+
|
data/bin/strobe
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "strobe"
|
4
|
+
|
5
|
+
begin
|
6
|
+
Strobe::CLI.start
|
7
|
+
rescue Strobe::Error => e
|
8
|
+
Strobe.ui.error e.message
|
9
|
+
Strobe.ui.error e.backtrace.join("\n") if ENV["STROBE_DEBUG"]
|
10
|
+
exit e.status_code
|
11
|
+
rescue Interrupt
|
12
|
+
Strobe.ui.error "\nQuitting..."
|
13
|
+
exit 1
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
Feature: Signing up
|
2
|
+
Scenario Outline: A successful signup
|
3
|
+
Given the user is signing up
|
4
|
+
And his password is <password>
|
5
|
+
And his password confirmation is <confirmation>
|
6
|
+
Then the server should respond with "<response>"
|
7
|
+
|
8
|
+
Examples:
|
9
|
+
| password | confirmation | response |
|
10
|
+
| z0mgz0mg | z0mgz0mg | created successfully |
|
11
|
+
| z0mgz0mg | z0mgz0mg2 | do not match |
|
12
|
+
|
13
|
+
Scenario: Using a duplicate email
|
14
|
+
Given the user is signing up with a duplicate email
|
15
|
+
Then the server should respond with /creation failed.*email/
|
16
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
Feature: Deploying an application
|
2
|
+
Scenario: Deploying an app
|
3
|
+
Given the user successfully signs up
|
4
|
+
And the user creates a file named "hello.html" containing "<html><body>hello</body></html>"
|
5
|
+
And runs "strobe deploy"
|
6
|
+
And creates a new application
|
7
|
+
Then the deployment should be successful
|
8
|
+
And a request for "/hello.html" should return "<html><body>hello</body></html>"
|
9
|
+
|
10
|
+
Scenario: Deploying a second time
|
11
|
+
Given the app was already deployed
|
12
|
+
When the user creates a file named "hello.html" containing "<html><body>hello!</body></html>"
|
13
|
+
And the user creates a file named "goodbye.html" containing "<html><body>goodbye</body></html>"
|
14
|
+
And runs "strobe deploy"
|
15
|
+
And creates a new application
|
16
|
+
Then the deployment should be successful
|
17
|
+
And a request for "/hello.html" should return "<html><body>hello!</body></html>"
|
18
|
+
And a request for "/goodbye.html" should return "<html><body>goodbye</body></html>"
|
19
|
+
|
20
|
+
Scenario: Deploying with an account, but not yet signed in on this machine
|
21
|
+
Given an existing user
|
22
|
+
And the user creates a file named "hello.html" containing "<html><body>hello</body></html>"
|
23
|
+
And runs "strobe deploy"
|
24
|
+
And enters "2" for /You aren't logged in with a Strobe user/
|
25
|
+
And enters his username and password
|
26
|
+
And creates a new application
|
27
|
+
Then a request for "/hello.html" should return "<html><body>hello</body></html>"
|
28
|
+
|
29
|
+
Scenario: Deploying with an account, and giving the wrong username and password
|
30
|
+
Given an existing user
|
31
|
+
And the user creates a file named "hello.html" containing "<html><body>hello</body></html>"
|
32
|
+
And runs "strobe deploy"
|
33
|
+
And enters "2" for /Please select an option/
|
34
|
+
And enters an incorrect username and password
|
35
|
+
Then the client should output /Log in failed/
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Feature: Deploying a SproutCore app
|
2
|
+
Scenario: Deploying an app
|
3
|
+
Given the user successfully signs up
|
4
|
+
And the user creates a file named "tmp/build/static/hello.html" containing "<html><body>hello</body></html>"
|
5
|
+
And runs "strobe deploy"
|
6
|
+
And creates a new application
|
7
|
+
Then the deployment should be successful
|
8
|
+
And a request for "/static/hello.html" should return "<html><body>hello</body></html>"
|
9
|
+
|
10
|
+
Scenario: Deploying an app with build numbers
|
11
|
+
Given the user successfully signs up
|
12
|
+
And the user creates a file named "tmp/build/static/myapp/en/01ff039192795e1254c448b804522c75708e3414/index.html" containing "<html><body>hello</body></html>"
|
13
|
+
And the user creates a file named "tmp/build/static/framework/foo.js" containing "alert('hello')"
|
14
|
+
And runs "strobe deploy"
|
15
|
+
And creates a new application
|
16
|
+
Then the deployment should be successful
|
17
|
+
And a request for "/myapp" should return "<html><body>hello</body></html>"
|
18
|
+
And a request for "/" should return "<html><body>hello</body></html>"
|
19
|
+
And a request for "/static/framework/foo.js" should return "alert('hello')"
|
@@ -0,0 +1,8 @@
|
|
1
|
+
And /^enters "(.*)" for ["\/](.*)["\/]/ do |entry, expected_input|
|
2
|
+
out_until_block.should =~ Regexp.new(expected_input)
|
3
|
+
task.write "#{entry}\n"
|
4
|
+
end
|
5
|
+
|
6
|
+
Then /^the client should output ["\/](.*)["\/]$/ do |output|
|
7
|
+
out_until_block.should =~ Regexp.new(output)
|
8
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "active_support/secure_random"
|
2
|
+
|
3
|
+
Given /^the user creates a file named "([^"]*)" containing "([^"]*)"$/ do |name, contents|
|
4
|
+
FileUtils.mkdir_p(File.dirname("#{html5_app}/#{name}"))
|
5
|
+
File.open("#{html5_app}/#{name}", "w") do |file|
|
6
|
+
file.write contents
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
And /^runs "strobe deploy"$/ do
|
11
|
+
strobe "deploy"
|
12
|
+
end
|
13
|
+
|
14
|
+
And /^creates a new application$/ do
|
15
|
+
@host ||= "foobar#{ActiveSupport::SecureRandom.hex(50)}.local"
|
16
|
+
|
17
|
+
unless @deployed
|
18
|
+
out_until_block.should =~ /Please enter your application's name:\s*/
|
19
|
+
task.write "foobar\n"
|
20
|
+
out_until_block.should =~ /URL to deploy to:\s*/
|
21
|
+
task.write "#{@host}\n"
|
22
|
+
@deployed = true
|
23
|
+
end
|
24
|
+
|
25
|
+
out_until_block.should =~ /Your app was successfully deployed on #{@host}/
|
26
|
+
end
|
27
|
+
|
28
|
+
Then /^the deployment should be successful$/ do
|
29
|
+
task.should be_terminated
|
30
|
+
task.exit_status.should == 0
|
31
|
+
end
|
32
|
+
|
33
|
+
And /^a request for "([^"]+)" should return "(.*)"$/ do |url, body|
|
34
|
+
When "the client makes a request for \"#{url}\""
|
35
|
+
Then "the response status should be 200"
|
36
|
+
And "the response body should be \"#{body}\""
|
37
|
+
end
|
38
|
+
|
39
|
+
When /^the client makes a request for "(.*)"$/ do |url|
|
40
|
+
connection = Excon::Connection.new("http://127.0.0.1:3000#{url}")
|
41
|
+
@response = connection.request(:method => "GET", :headers => {"Host" => @host})
|
42
|
+
end
|
43
|
+
|
44
|
+
Then /^the response status should be (\d+)$/ do |status|
|
45
|
+
@response.status.should == status.to_i
|
46
|
+
end
|
47
|
+
|
48
|
+
Then /^the response body should be "(.*)"$/ do |body|
|
49
|
+
@response.body.should == body
|
50
|
+
end
|
51
|
+
|
52
|
+
Given /^the app was already deployed$/ do
|
53
|
+
Given "the user successfully signs up"
|
54
|
+
And "the user creates a file named \"hello.html\" containing \"<html><body>hello</body></html>\""
|
55
|
+
And "runs \"strobe deploy\""
|
56
|
+
And "creates a new application"
|
57
|
+
Then "the deployment should be successful"
|
58
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require "active_support/secure_random"
|
2
|
+
|
3
|
+
Before do
|
4
|
+
reset!
|
5
|
+
|
6
|
+
cd html5_app
|
7
|
+
env({})
|
8
|
+
end
|
9
|
+
|
10
|
+
After do
|
11
|
+
unless task.terminated?
|
12
|
+
task.terminate
|
13
|
+
task.wait
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Given /^the user is signing up$/ do
|
18
|
+
@email = ActiveSupport::SecureRandom.hex(100) << "@zomg.com"
|
19
|
+
end
|
20
|
+
|
21
|
+
Given /^the user successfully signs up$/ do
|
22
|
+
Given "the user is signing up"
|
23
|
+
Then "the server should respond with \"created successfully\""
|
24
|
+
end
|
25
|
+
|
26
|
+
Given /^an existing user$/ do
|
27
|
+
Given "the user successfully signs up"
|
28
|
+
reset_home
|
29
|
+
end
|
30
|
+
|
31
|
+
Given /^the user is signing up with a duplicate email$/ do
|
32
|
+
Given "the user is signing up"
|
33
|
+
Then "the server should respond with \"created successfully\""
|
34
|
+
@email = @last_email
|
35
|
+
end
|
36
|
+
|
37
|
+
Given /^his password is (\w+)$/ do |password|
|
38
|
+
@password = password
|
39
|
+
end
|
40
|
+
|
41
|
+
Given /^his password confirmation is (\w+)$/ do |confirm|
|
42
|
+
@confirm = confirm
|
43
|
+
end
|
44
|
+
|
45
|
+
And /^enters (his|an incorrect) username and password$/ do |correct|
|
46
|
+
correct = correct == "his"
|
47
|
+
|
48
|
+
task.readline.should =~ /Please enter your Strobe username and password/
|
49
|
+
out_until_block.should =~ /Email:/
|
50
|
+
task.write "#{@last_email}\n"
|
51
|
+
out_until_block.should =~ /Password:\s*/
|
52
|
+
task.write correct ? "z0mgz0mg\n" : "z0mgz0mg2\n"
|
53
|
+
task.readline.should =~ /You are now logged in as/ if correct
|
54
|
+
end
|
55
|
+
|
56
|
+
Then /^the server should respond with ["\/](.+)["\/]$/ do |expected|
|
57
|
+
email = @email || ActiveSupport::SecureRandom.hex(100) << "@zomg.com"
|
58
|
+
password = @password || "z0mgz0mg"
|
59
|
+
confirm = @confirm || "z0mgz0mg"
|
60
|
+
|
61
|
+
@last_email = email
|
62
|
+
|
63
|
+
strobe "signup" do |task|
|
64
|
+
task.readline.should == "Please enter your Strobe username and password.\n"
|
65
|
+
out_until_block.should =~ /Email:\s*/
|
66
|
+
task.write "#{email}\n"
|
67
|
+
out_until_block.should =~ /Password:\s*/
|
68
|
+
task.write "#{password}\n"
|
69
|
+
out_until_block.should =~ /Repeat Password:\s*/
|
70
|
+
task.write "#{confirm}\n"
|
71
|
+
out_until_block.should =~ Regexp.new(expected, Regexp::MULTILINE)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "fileutils"
|
3
|
+
|
4
|
+
class Strobe
|
5
|
+
module Spec
|
6
|
+
module Helpers
|
7
|
+
def tmp
|
8
|
+
tmp = File.expand_path("../../../tmp", __FILE__)
|
9
|
+
Pathname.new(tmp)
|
10
|
+
end
|
11
|
+
|
12
|
+
def base_app
|
13
|
+
tmp.join("app")
|
14
|
+
end
|
15
|
+
|
16
|
+
def base_home
|
17
|
+
tmp.join("system_home")
|
18
|
+
end
|
19
|
+
|
20
|
+
def build_tmp
|
21
|
+
FileUtils.rm_rf(tmp)
|
22
|
+
FileUtils.mkdir_p(base_app)
|
23
|
+
FileUtils.mkdir_p(base_home)
|
24
|
+
end
|
25
|
+
|
26
|
+
def reset_home
|
27
|
+
FileUtils.rm_rf(system_home) if File.directory?(system_home)
|
28
|
+
Thread.current[:system_home] = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def reset_html5_app
|
32
|
+
FileUtils.rm_rf(html5_app) if File.directory?(html5_app)
|
33
|
+
Thread.current[:html5_app] = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def copy_html5_app(dest)
|
37
|
+
FileUtils.cp_r(base_app, dest) unless File.directory?(dest)
|
38
|
+
end
|
39
|
+
|
40
|
+
def html5_app
|
41
|
+
Thread.current[:html5_app] ||= begin
|
42
|
+
location = tmp.join("app_#{Thread.current.object_id}")
|
43
|
+
copy_html5_app(location)
|
44
|
+
location
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def system_home
|
49
|
+
Thread.current[:system_home] ||= begin
|
50
|
+
location = tmp.join("system_home_#{Thread.current.object_id}")
|
51
|
+
copy_system_home(location)
|
52
|
+
location
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def copy_system_home(dest)
|
57
|
+
FileUtils.cp_r(base_home, dest) unless File.directory?(dest)
|
58
|
+
end
|
59
|
+
|
60
|
+
def dir
|
61
|
+
Thread.current[:strobe_dir]
|
62
|
+
end
|
63
|
+
|
64
|
+
def dir=(dir)
|
65
|
+
Thread.current[:strobe_dir] = dir
|
66
|
+
end
|
67
|
+
|
68
|
+
def env=(env)
|
69
|
+
Thread.current[:strobe_env] = env
|
70
|
+
end
|
71
|
+
|
72
|
+
def cd(change_into)
|
73
|
+
original, self.dir = dir, change_into
|
74
|
+
yield if block_given?
|
75
|
+
ensure
|
76
|
+
self.dir = original if block_given?
|
77
|
+
end
|
78
|
+
|
79
|
+
def env(hash = nil)
|
80
|
+
return Thread.current[:strobe_env] unless hash
|
81
|
+
|
82
|
+
original, self.env = env, hash
|
83
|
+
yield if block_given?
|
84
|
+
ensure
|
85
|
+
self.env = original if block_given?
|
86
|
+
end
|
87
|
+
|
88
|
+
def reset!
|
89
|
+
reset_home
|
90
|
+
reset_html5_app
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
module Setup
|
95
|
+
extend Strobe::Spec::Helpers
|
96
|
+
|
97
|
+
build_tmp
|
98
|
+
cd html5_app
|
99
|
+
env({})
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
World(Strobe::Spec::Helpers)
|