blade 0.4.1 → 0.5.0
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.
- checksums.yaml +4 -4
- data/blade.gemspec +1 -3
- data/exe/blade +1 -7
- data/lib/blade.rb +43 -60
- data/lib/blade/assets.rb +11 -3
- data/lib/blade/cli.rb +7 -0
- data/lib/blade/config.rb +15 -0
- data/lib/blade/interface/ci.rb +24 -16
- data/lib/blade/interface/runner.rb +3 -11
- data/lib/blade/interface/runner/tab.rb +29 -7
- data/lib/blade/rack/adapter.rb +78 -0
- data/lib/blade/rack/router.rb +36 -0
- data/lib/blade/server.rb +11 -0
- data/lib/blade/session.rb +2 -0
- data/lib/blade/test_results.rb +26 -55
- data/lib/blade/version.rb +1 -1
- metadata +7 -7
- data/lib/blade/combined_test_results.rb +0 -42
- data/lib/blade/rack_adapter.rb +0 -81
- data/lib/blade/test_helper.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 071f84dc1d8ddf2ebe1db5eab1342725efeee1f6
|
4
|
+
data.tar.gz: 9422e19dbe9257f3f531d7d30ffa686d43f8e49e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b624e473f3bcd2e1a13472cb4d3c9fd8044740c2d81f55ae42193326a7349ba4f40c6d876395edb225831d0c907000ed1ba7feb06f81f23c2a73cdf15f5234bc
|
7
|
+
data.tar.gz: d0c251529467263493f7b0e2d594e56bfc8347303163a0726be54648335fee89610b87798ed7b1ef95a61ede908cf78ca59ab93b24de2eb8d59284a5b2943993
|
data/blade.gemspec
CHANGED
@@ -22,14 +22,12 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_development_dependency "bundler", "~> 1.10"
|
23
23
|
spec.add_development_dependency "rake", "~> 10.0"
|
24
24
|
|
25
|
-
spec.add_dependency "blade-qunit_adapter", "~>
|
25
|
+
spec.add_dependency "blade-qunit_adapter", "~> 1.20.0"
|
26
26
|
spec.add_dependency "activesupport", ">= 3.0.0"
|
27
27
|
spec.add_dependency "coffee-script", "~> 2.4.0"
|
28
28
|
spec.add_dependency "coffee-script-source", "~> 1.9.0"
|
29
29
|
spec.add_dependency "curses", "~> 1.0.0"
|
30
30
|
spec.add_dependency "eventmachine", "~> 1.0.0"
|
31
|
-
# Lock to 1.1.1 to avoid Promise error in 1.1.2 with Chrome 43
|
32
|
-
# "Uncaught TypeError: Cannot read property '_state' of undefined"
|
33
31
|
spec.add_dependency "faye", "1.1.1"
|
34
32
|
spec.add_dependency "sprockets", "~> 3.2.0"
|
35
33
|
spec.add_dependency "thin", "~> 1.6.0"
|
data/exe/blade
CHANGED
data/lib/blade.rb
CHANGED
@@ -2,7 +2,6 @@ require "active_support/all"
|
|
2
2
|
require "eventmachine"
|
3
3
|
require "faye"
|
4
4
|
require "pathname"
|
5
|
-
require "ostruct"
|
6
5
|
require "yaml"
|
7
6
|
|
8
7
|
require "blade/version"
|
@@ -11,6 +10,14 @@ require "blade/cli"
|
|
11
10
|
module Blade
|
12
11
|
extend self
|
13
12
|
|
13
|
+
CONFIG_DEFAULTS = {
|
14
|
+
framework: :qunit,
|
15
|
+
port: 9876,
|
16
|
+
build: { path: "." }
|
17
|
+
}
|
18
|
+
|
19
|
+
CONFIG_FILENAMES = %w( blade.yml .blade.yml )
|
20
|
+
|
14
21
|
@components = []
|
15
22
|
|
16
23
|
def register_component(component)
|
@@ -22,30 +29,27 @@ module Blade
|
|
22
29
|
|
23
30
|
autoload :Model, "blade/model"
|
24
31
|
autoload :Assets, "blade/assets"
|
25
|
-
autoload :
|
32
|
+
autoload :Config, "blade/config"
|
33
|
+
autoload :RackAdapter, "blade/rack/adapter"
|
34
|
+
autoload :RackRouter, "blade/rack/router"
|
26
35
|
autoload :Session, "blade/session"
|
27
36
|
autoload :TestResults, "blade/test_results"
|
28
|
-
autoload :CombinedTestResults, "blade/combined_test_results"
|
29
|
-
|
30
|
-
extend Forwardable
|
31
|
-
def_delegators "Server.client", :subscribe, :publish
|
32
37
|
|
33
|
-
|
34
|
-
DEFAULT_PORT = 9876
|
38
|
+
delegate :subscribe, :publish, to: Server
|
35
39
|
|
36
|
-
attr_reader :config
|
40
|
+
attr_reader :config
|
37
41
|
|
38
42
|
def start(options = {})
|
39
43
|
return if running?
|
40
44
|
clean_tmp_path
|
41
45
|
|
42
46
|
initialize!(options)
|
43
|
-
load_interface
|
47
|
+
load_interface
|
44
48
|
|
45
49
|
handle_exit
|
46
50
|
|
47
51
|
EM.run do
|
48
|
-
@components.each { |c| c.
|
52
|
+
@components.each { |c| c.try(:start) }
|
49
53
|
@running = true
|
50
54
|
end
|
51
55
|
end
|
@@ -53,7 +57,7 @@ module Blade
|
|
53
57
|
def stop
|
54
58
|
return if @stopping
|
55
59
|
@stopping = true
|
56
|
-
@components.each { |c| c.
|
60
|
+
@components.each { |c| c.try(:stop) }
|
57
61
|
EM.stop if EM.reactor_running?
|
58
62
|
@running = false
|
59
63
|
end
|
@@ -63,15 +67,27 @@ module Blade
|
|
63
67
|
end
|
64
68
|
|
65
69
|
def initialize!(options = {})
|
66
|
-
|
67
|
-
@
|
70
|
+
return if @initialized
|
71
|
+
@initialized = true
|
68
72
|
|
69
|
-
|
70
|
-
|
71
|
-
|
73
|
+
options = CONFIG_DEFAULTS.deep_merge(blade_file_options).deep_merge(options)
|
74
|
+
@config = Blade::Config.new options
|
75
|
+
|
76
|
+
config.load_paths = Array(config.load_paths)
|
77
|
+
config.logical_paths = Array(config.logical_paths)
|
78
|
+
|
79
|
+
if config.build?
|
80
|
+
config.build.logical_paths = Array(config.build.logical_paths)
|
81
|
+
config.build.path ||= "."
|
82
|
+
end
|
83
|
+
|
84
|
+
config.plugins ||= {}
|
85
|
+
|
86
|
+
load_plugins
|
87
|
+
load_adapter
|
72
88
|
end
|
73
89
|
|
74
|
-
def url(path = "")
|
90
|
+
def url(path = "/")
|
75
91
|
"http://localhost:#{config.port}#{path}"
|
76
92
|
end
|
77
93
|
|
@@ -100,57 +116,24 @@ module Blade
|
|
100
116
|
end
|
101
117
|
end
|
102
118
|
|
103
|
-
def
|
104
|
-
filename =
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
end
|
109
|
-
|
110
|
-
def setup_config!
|
111
|
-
load_config_file!
|
112
|
-
options = @options.except(:plugins)
|
113
|
-
|
114
|
-
if options_for_interface = @options[options[:interface]]
|
115
|
-
options.merge! options_for_interface
|
116
|
-
end
|
117
|
-
|
118
|
-
options[:framework] ||= DEFAULT_FRAMEWORK
|
119
|
-
options[:port] ||= DEFAULT_PORT
|
120
|
-
options[:load_paths] = Array(options[:load_paths])
|
121
|
-
options[:logical_paths] = Array(options[:logical_paths])
|
122
|
-
|
123
|
-
if build_options = options.delete(:build)
|
124
|
-
build_options[:logical_paths] = Array(build_options[:logical_paths])
|
125
|
-
build_options[:path] ||= "."
|
126
|
-
options[:build] = OpenStruct.new(build_options)
|
127
|
-
end
|
128
|
-
|
129
|
-
@config = OpenStruct.new(options)
|
130
|
-
|
131
|
-
setup_plugin_config!
|
132
|
-
end
|
133
|
-
|
134
|
-
def setup_plugin_config!
|
135
|
-
@plugins = OpenStruct.new
|
136
|
-
|
137
|
-
plugin_options = @options[:plugins] || {}
|
138
|
-
|
139
|
-
plugin_options.each do |name, plugin_config|
|
140
|
-
plugins[name] = OpenStruct.new(config: OpenStruct.new(plugin_config))
|
119
|
+
def blade_file_options
|
120
|
+
if filename = CONFIG_FILENAMES.detect { |name| File.exists?(name) }
|
121
|
+
YAML.load_file(filename)
|
122
|
+
else
|
123
|
+
{}
|
141
124
|
end
|
142
125
|
end
|
143
126
|
|
144
|
-
def load_interface
|
127
|
+
def load_interface
|
145
128
|
require "blade/interface/#{config.interface}"
|
146
129
|
end
|
147
130
|
|
148
|
-
def load_adapter
|
131
|
+
def load_adapter
|
149
132
|
require "blade/#{config.framework}_adapter"
|
150
133
|
end
|
151
134
|
|
152
|
-
def load_plugins
|
153
|
-
plugins.
|
135
|
+
def load_plugins
|
136
|
+
config.plugins.keys.each do |name|
|
154
137
|
require "blade/#{name}_plugin"
|
155
138
|
end
|
156
139
|
end
|
data/lib/blade/assets.rb
CHANGED
@@ -7,7 +7,7 @@ module Blade::Assets
|
|
7
7
|
|
8
8
|
@environments = {}
|
9
9
|
|
10
|
-
def environment(name = :
|
10
|
+
def environment(name = :user, context_name = nil)
|
11
11
|
cache_name = [name, context_name].compact.map(&:to_s).uniq.join("-")
|
12
12
|
|
13
13
|
@environments[cache_name] ||= Sprockets::Environment.new do |env|
|
@@ -54,7 +54,15 @@ module Blade::Assets
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def user_load_paths
|
57
|
-
Blade.config.load_paths.
|
57
|
+
Blade.config.load_paths.flat_map do |load_path|
|
58
|
+
if load_path.is_a?(Hash)
|
59
|
+
load_path.flat_map do |gem_name, paths|
|
60
|
+
Array(paths).map{ |path| gem_pathname(gem_name).join(path) }
|
61
|
+
end
|
62
|
+
else
|
63
|
+
Pathname.new(load_path)
|
64
|
+
end
|
65
|
+
end
|
58
66
|
end
|
59
67
|
|
60
68
|
def adapter_load_paths
|
@@ -84,7 +92,7 @@ module Blade::Assets
|
|
84
92
|
end
|
85
93
|
|
86
94
|
def get_mtime(logical_path)
|
87
|
-
|
95
|
+
environment(:user)[logical_path].mtime
|
88
96
|
rescue Exception => e
|
89
97
|
e.to_s
|
90
98
|
end
|
data/lib/blade/cli.rb
CHANGED
data/lib/blade/config.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
class Blade::Config < ActiveSupport::HashWithIndifferentAccess
|
2
|
+
def method_missing(method, *args)
|
3
|
+
case method
|
4
|
+
when /=$/
|
5
|
+
self[$`] = args.first
|
6
|
+
when /\?$/
|
7
|
+
self[$`].present?
|
8
|
+
else
|
9
|
+
if self[method].is_a?(Hash) && !self[method].is_a?(self.class)
|
10
|
+
self[method] = self.class.new(self[method])
|
11
|
+
end
|
12
|
+
self[method]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/blade/interface/ci.rb
CHANGED
@@ -4,8 +4,8 @@ module Blade::CI
|
|
4
4
|
|
5
5
|
def start
|
6
6
|
@completed_sessions = 0
|
7
|
+
@failures = []
|
7
8
|
|
8
|
-
log "# Running"
|
9
9
|
Blade.subscribe("/results") do |details|
|
10
10
|
process_result(details)
|
11
11
|
end
|
@@ -13,11 +13,15 @@ module Blade::CI
|
|
13
13
|
|
14
14
|
private
|
15
15
|
def process_result(details)
|
16
|
-
if details
|
17
|
-
|
16
|
+
if status = details[:status]
|
17
|
+
STDOUT.print status_dot(status)
|
18
|
+
|
19
|
+
if status == "fail"
|
20
|
+
@failures << details
|
21
|
+
end
|
18
22
|
end
|
19
23
|
|
20
|
-
if details[
|
24
|
+
if details[:completed]
|
21
25
|
process_completion
|
22
26
|
end
|
23
27
|
end
|
@@ -26,26 +30,30 @@ module Blade::CI
|
|
26
30
|
@completed_sessions += 1
|
27
31
|
|
28
32
|
if done?
|
29
|
-
|
30
|
-
|
33
|
+
EM.add_timer 2 do
|
34
|
+
display_failures
|
35
|
+
STDOUT.puts
|
36
|
+
exit_with_status_code
|
37
|
+
end
|
31
38
|
end
|
32
39
|
end
|
33
40
|
|
34
|
-
def
|
35
|
-
|
41
|
+
def status_dot(status)
|
42
|
+
Blade::TestResults::STATUS_DOTS[status]
|
36
43
|
end
|
37
44
|
|
38
|
-
def
|
39
|
-
|
40
|
-
display results
|
41
|
-
exit results.failed? ? 1 : 0
|
45
|
+
def done?
|
46
|
+
@completed_sessions == (Blade.config.expected_sessions || 1)
|
42
47
|
end
|
43
48
|
|
44
|
-
def
|
45
|
-
|
49
|
+
def display_failures
|
50
|
+
@failures.each do |details|
|
51
|
+
STDERR.puts "\n\n#{status_dot(details[:status])} #{details[:name]} (#{Blade::Session.find(details[:session_id])})"
|
52
|
+
STDERR.puts details[:message]
|
53
|
+
end
|
46
54
|
end
|
47
55
|
|
48
|
-
def
|
49
|
-
|
56
|
+
def exit_with_status_code
|
57
|
+
exit @failures.any? ? 1 : 0
|
50
58
|
end
|
51
59
|
end
|
@@ -6,9 +6,6 @@ module Blade::Runner
|
|
6
6
|
|
7
7
|
autoload :Tab, "blade/interface/runner/tab"
|
8
8
|
|
9
|
-
extend Forwardable
|
10
|
-
def_delegators "Blade::Runner", :create_window
|
11
|
-
|
12
9
|
COLOR_NAMES = %w( white yellow green red )
|
13
10
|
PADDING = 1
|
14
11
|
|
@@ -48,19 +45,14 @@ module Blade::Runner
|
|
48
45
|
handle_stale_tabs
|
49
46
|
|
50
47
|
Blade.subscribe("/results") do |details|
|
51
|
-
session = Blade::Session.find(details[
|
48
|
+
session = Blade::Session.find(details[:session_id])
|
52
49
|
|
53
|
-
|
54
|
-
if details["line"] && tab.active?
|
55
|
-
Tab.content_window.addstr(details["line"] + "\n")
|
56
|
-
Tab.content_window.noutrefresh
|
57
|
-
end
|
58
|
-
tab.draw
|
59
|
-
else
|
50
|
+
unless tab = Tab.find(session.id)
|
60
51
|
tab = Tab.create(id: session.id)
|
61
52
|
tab.activate if Tab.size == 1
|
62
53
|
end
|
63
54
|
|
55
|
+
tab.draw
|
64
56
|
Curses.doupdate
|
65
57
|
end
|
66
58
|
end
|
@@ -1,10 +1,8 @@
|
|
1
1
|
class Blade::Runner::Tab < Blade::Model
|
2
|
-
|
3
|
-
def_delegators "Blade::Runner", :colors, :create_window
|
2
|
+
delegate :colors, :create_window, to: Blade::Runner
|
4
3
|
|
5
4
|
class << self
|
6
|
-
|
7
|
-
def_delegators "Blade::Runner", :create_window
|
5
|
+
delegate :create_window, to: Blade::Runner
|
8
6
|
|
9
7
|
attr_reader :window, :state_window, :content_window
|
10
8
|
|
@@ -82,6 +80,7 @@ class Blade::Runner::Tab < Blade::Model
|
|
82
80
|
window.attroff(color)
|
83
81
|
window.addstr(" ║")
|
84
82
|
window.addstr "╝ ╚"
|
83
|
+
draw_test_results
|
85
84
|
end
|
86
85
|
|
87
86
|
def draw_inactive
|
@@ -92,10 +91,36 @@ class Blade::Runner::Tab < Blade::Model
|
|
92
91
|
window.addstr "═════"
|
93
92
|
end
|
94
93
|
|
94
|
+
def draw_test_results
|
95
|
+
tabs.content_window.clear
|
96
|
+
failures = []
|
97
|
+
|
98
|
+
session.test_results.results.each do |result|
|
99
|
+
tabs.content_window.addstr(status_dot(result))
|
100
|
+
failures << result if result[:status] == "fail"
|
101
|
+
end
|
102
|
+
|
103
|
+
failures.each do |result|
|
104
|
+
tabs.content_window.addstr("\n\n")
|
105
|
+
tabs.content_window.attron(Curses::A_BOLD)
|
106
|
+
tabs.content_window.attron(colors.red)
|
107
|
+
tabs.content_window.addstr("#{status_dot(result)} #{result[:name]}\n")
|
108
|
+
tabs.content_window.attroff(colors.red)
|
109
|
+
tabs.content_window.attroff(Curses::A_BOLD)
|
110
|
+
tabs.content_window.addstr(result[:message])
|
111
|
+
end
|
112
|
+
|
113
|
+
tabs.content_window.noutrefresh
|
114
|
+
end
|
115
|
+
|
95
116
|
def dot
|
96
117
|
state == "pending" ? "○" : "●"
|
97
118
|
end
|
98
119
|
|
120
|
+
def status_dot(result)
|
121
|
+
Blade::TestResults::STATUS_DOTS[result[:status]]
|
122
|
+
end
|
123
|
+
|
99
124
|
def index
|
100
125
|
tabs.all.index(self)
|
101
126
|
end
|
@@ -124,9 +149,6 @@ class Blade::Runner::Tab < Blade::Model
|
|
124
149
|
|
125
150
|
tabs.state_window.addstr(session.to_s)
|
126
151
|
tabs.state_window.noutrefresh
|
127
|
-
|
128
|
-
tabs.content_window.addstr(session.test_results.to_s)
|
129
|
-
tabs.content_window.noutrefresh
|
130
152
|
end
|
131
153
|
|
132
154
|
def deactivate
|
@@ -0,0 +1,78 @@
|
|
1
|
+
class Blade::RackAdapter
|
2
|
+
include Blade::RackRouter
|
3
|
+
|
4
|
+
route "", to: :redirect_to_index
|
5
|
+
route "/", to: :index
|
6
|
+
route "/blade*", environment: :blade
|
7
|
+
route "/blade/adapter*", environment: :adapter
|
8
|
+
route "/blade/websocket*", to: :websocket
|
9
|
+
default_route environment: :user
|
10
|
+
|
11
|
+
delegate :environment, to: Blade::Assets
|
12
|
+
|
13
|
+
attr_reader :request, :env
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
Blade.initialize!
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env)
|
20
|
+
@env = env
|
21
|
+
@request = Rack::Request.new(env)
|
22
|
+
|
23
|
+
route = find_route(request.path_info)
|
24
|
+
base_path, action = route.values_at(:base_path, :action)
|
25
|
+
|
26
|
+
rewrite_path!(base_path)
|
27
|
+
|
28
|
+
case
|
29
|
+
when action[:environment]
|
30
|
+
environment(action[:environment]).call(env)
|
31
|
+
when action[:to]
|
32
|
+
send(action[:to])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def index
|
37
|
+
request.path_info = "/index.html"
|
38
|
+
response = environment(:blade).call(env)
|
39
|
+
response = add_session_cookie(response) if needs_session_cookie?
|
40
|
+
response.to_a
|
41
|
+
end
|
42
|
+
|
43
|
+
def redirect_to_index
|
44
|
+
Rack::Response.new.tap do |response|
|
45
|
+
path = request.path
|
46
|
+
path = path + "/" unless path.last == "/"
|
47
|
+
response.redirect(path)
|
48
|
+
end.to_a
|
49
|
+
end
|
50
|
+
|
51
|
+
def websocket
|
52
|
+
faye_adapter.call(env)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def needs_session_cookie?
|
57
|
+
Blade.running? && !Blade::Session.find(request.cookies[Blade::Session::KEY])
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_session_cookie(response)
|
61
|
+
user_agent = UserAgent.parse(request.user_agent)
|
62
|
+
session = Blade::Session.create(user_agent: user_agent)
|
63
|
+
status, headers, body = response
|
64
|
+
response = Rack::Response.new(body, status, headers)
|
65
|
+
response.set_cookie(Blade::Session::KEY, session.id)
|
66
|
+
response
|
67
|
+
end
|
68
|
+
|
69
|
+
def rewrite_path!(path = nil)
|
70
|
+
return if path.nil?
|
71
|
+
request.path_info = request.path_info.sub(path, "").presence || "/"
|
72
|
+
request.script_name = request.script_name + path
|
73
|
+
end
|
74
|
+
|
75
|
+
def faye_adapter
|
76
|
+
@faye_adapter ||= Faye::RackAdapter.new(mount: "/", timeout: 25)
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Blade::RackRouter
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
DEFAULT = :*
|
5
|
+
|
6
|
+
included do
|
7
|
+
cattr_accessor(:routes) { Hash.new }
|
8
|
+
end
|
9
|
+
|
10
|
+
class_methods do
|
11
|
+
def route(path, action)
|
12
|
+
pattern = /^\/?#{path.gsub(/\*/, ".*")}$/
|
13
|
+
base_path = path.match(/([^\*]*)\*?/)[1]
|
14
|
+
routes[path] = { action: action, pattern: pattern, base_path: base_path }
|
15
|
+
self.routes = routes.sort_by { |path, value| -path.size }.to_h
|
16
|
+
routes[path]
|
17
|
+
end
|
18
|
+
|
19
|
+
def default_route(action)
|
20
|
+
routes[DEFAULT] = { action: action }
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_route(path)
|
24
|
+
if route = routes.detect { |key, details| path =~ details[:pattern] }
|
25
|
+
route[1]
|
26
|
+
else
|
27
|
+
routes[DEFAULT]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def find_route(*args)
|
34
|
+
self.class.find_route(*args)
|
35
|
+
end
|
36
|
+
end
|
data/lib/blade/server.rb
CHANGED
@@ -21,9 +21,20 @@ module Blade::Server
|
|
21
21
|
@client ||= Faye::Client.new(websocket_url)
|
22
22
|
end
|
23
23
|
|
24
|
+
def subscribe(channel)
|
25
|
+
client.subscribe(channel) do |message|
|
26
|
+
yield message.with_indifferent_access
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def publish(channel, message)
|
31
|
+
client.publish(channel, message)
|
32
|
+
end
|
33
|
+
|
24
34
|
private
|
25
35
|
def app
|
26
36
|
Rack::Builder.app do
|
37
|
+
use Rack::ShowExceptions
|
27
38
|
run Blade::RackAdapter.new
|
28
39
|
end
|
29
40
|
end
|
data/lib/blade/session.rb
CHANGED
data/lib/blade/test_results.rb
CHANGED
@@ -1,81 +1,52 @@
|
|
1
1
|
class Blade::TestResults
|
2
|
-
|
2
|
+
STATUS_DOTS = { pass: ".", fail: "✗" }.with_indifferent_access
|
3
|
+
|
4
|
+
attr_reader :session_id, :state, :results, :total, :failures
|
3
5
|
|
4
6
|
def initialize(session_id)
|
5
7
|
@session_id = session_id
|
6
8
|
reset
|
7
9
|
|
8
10
|
Blade.subscribe("/tests") do |details|
|
9
|
-
if details[
|
10
|
-
|
11
|
+
if details[:session_id] == session_id
|
12
|
+
event = details.delete(:event)
|
13
|
+
try("process_#{event}", details)
|
11
14
|
end
|
12
15
|
end
|
13
16
|
end
|
14
17
|
|
15
18
|
def reset
|
16
|
-
@
|
17
|
-
@passes = []
|
18
|
-
@failures = []
|
19
|
+
@results = []
|
19
20
|
@state = "pending"
|
20
21
|
@total = 0
|
22
|
+
@failures = 0
|
21
23
|
end
|
22
24
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
reset
|
29
|
-
@state = "running"
|
30
|
-
@total = details["total"]
|
31
|
-
@lines << publication[:line] = "1..#{@total}"
|
32
|
-
when "result"
|
33
|
-
args = details.values_at("name", "message")
|
34
|
-
|
35
|
-
if details["status"] == "pass"
|
36
|
-
line = Pass.new(*args).to_s
|
37
|
-
@passes << line
|
38
|
-
else
|
39
|
-
line = Failure.new(*args).to_s
|
40
|
-
@failures << line
|
41
|
-
@state = "failing"
|
42
|
-
end
|
43
|
-
@lines << line
|
44
|
-
|
45
|
-
publication.merge!(line: line, status: details["status"])
|
46
|
-
when "end"
|
47
|
-
@state = failures.any? ? "failed" : "finished"
|
48
|
-
publication[:completed] = true
|
49
|
-
end
|
50
|
-
|
51
|
-
publication.merge!(state: state, session_id: session_id)
|
52
|
-
Blade.publish("/results", publication)
|
25
|
+
def process_begin(details)
|
26
|
+
reset
|
27
|
+
@state = "running"
|
28
|
+
@total = details[:total]
|
29
|
+
publish(total: @total)
|
53
30
|
end
|
54
31
|
|
55
|
-
def
|
56
|
-
|
57
|
-
|
32
|
+
def process_result(details)
|
33
|
+
result = details.slice(:status, :name, :message)
|
34
|
+
@results << result
|
58
35
|
|
59
|
-
|
60
|
-
|
61
|
-
@
|
62
|
-
@message = message
|
36
|
+
if result[:status] == "fail"
|
37
|
+
@state = "failing"
|
38
|
+
@failures += 1
|
63
39
|
end
|
64
40
|
|
65
|
-
|
66
|
-
|
67
|
-
end
|
41
|
+
publish(result)
|
42
|
+
end
|
68
43
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
73
|
-
end
|
44
|
+
def process_end(details)
|
45
|
+
@state = failures.zero? ? "finished" : "failed"
|
46
|
+
publish(completed: true)
|
74
47
|
end
|
75
48
|
|
76
|
-
|
77
|
-
|
78
|
-
"not #{super}"
|
79
|
-
end
|
49
|
+
def publish(message = {})
|
50
|
+
Blade.publish("/results", message.merge(state: state, session_id: session_id))
|
80
51
|
end
|
81
52
|
end
|
data/lib/blade/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blade
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Javan Makhmali
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 1.20.0
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 1.20.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: activesupport
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -215,16 +215,16 @@ files:
|
|
215
215
|
- lib/blade/assets.rb
|
216
216
|
- lib/blade/assets/builder.rb
|
217
217
|
- lib/blade/cli.rb
|
218
|
-
- lib/blade/combined_test_results.rb
|
219
218
|
- lib/blade/component.rb
|
219
|
+
- lib/blade/config.rb
|
220
220
|
- lib/blade/interface/ci.rb
|
221
221
|
- lib/blade/interface/runner.rb
|
222
222
|
- lib/blade/interface/runner/tab.rb
|
223
223
|
- lib/blade/model.rb
|
224
|
-
- lib/blade/
|
224
|
+
- lib/blade/rack/adapter.rb
|
225
|
+
- lib/blade/rack/router.rb
|
225
226
|
- lib/blade/server.rb
|
226
227
|
- lib/blade/session.rb
|
227
|
-
- lib/blade/test_helper.rb
|
228
228
|
- lib/blade/test_results.rb
|
229
229
|
- lib/blade/version.rb
|
230
230
|
homepage: https://github.com/javan/blade
|
@@ -1,42 +0,0 @@
|
|
1
|
-
class Blade::CombinedTestResults
|
2
|
-
attr_reader :sessions, :all_test_results
|
3
|
-
|
4
|
-
def initialize(sessions)
|
5
|
-
@sessions = sessions
|
6
|
-
@all_test_results = sessions.map(&:test_results)
|
7
|
-
end
|
8
|
-
|
9
|
-
def total
|
10
|
-
sum(totals)
|
11
|
-
end
|
12
|
-
|
13
|
-
def lines(type = :results)
|
14
|
-
sessions.flat_map do |session|
|
15
|
-
session.test_results.send(type).map do |line|
|
16
|
-
line.sub(/ok/, "ok [#{session}]")
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_s
|
22
|
-
lines = ["1..#{total}"] + lines(:failures) + lines(:passes)
|
23
|
-
lines.join("\n")
|
24
|
-
end
|
25
|
-
|
26
|
-
def failed?
|
27
|
-
states.include?("failed")
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
def sum(values)
|
32
|
-
values.inject(0) { |sum, total| sum + total }
|
33
|
-
end
|
34
|
-
|
35
|
-
def totals
|
36
|
-
all_test_results.map(&:total).compact
|
37
|
-
end
|
38
|
-
|
39
|
-
def states
|
40
|
-
all_test_results.map(&:state)
|
41
|
-
end
|
42
|
-
end
|
data/lib/blade/rack_adapter.rb
DELETED
@@ -1,81 +0,0 @@
|
|
1
|
-
class Blade::RackAdapter
|
2
|
-
extend Forwardable
|
3
|
-
def_delegators "Blade::Assets", :environment
|
4
|
-
|
5
|
-
PATH = "/blade"
|
6
|
-
ADAPTER_PATH = PATH + "/adapter"
|
7
|
-
WEBSOCKET_PATH = PATH + "/websocket"
|
8
|
-
|
9
|
-
def initialize(app = nil, options = {})
|
10
|
-
Blade.initialize!
|
11
|
-
|
12
|
-
if app.is_a?(Hash)
|
13
|
-
@options = app
|
14
|
-
else
|
15
|
-
@app, @options = app, options
|
16
|
-
end
|
17
|
-
|
18
|
-
@mount_path = @options[:mount]
|
19
|
-
@mount_path_pattern = /^#{@mount_path}/
|
20
|
-
|
21
|
-
@blade_path_pattern = /^#{PATH}/
|
22
|
-
@adapter_path_pattern = /^#{ADAPTER_PATH}/
|
23
|
-
@websocket_path_pattern = /^#{WEBSOCKET_PATH}/
|
24
|
-
end
|
25
|
-
|
26
|
-
def call(env)
|
27
|
-
unless @mount_path.nil?
|
28
|
-
if env["PATH_INFO"] =~ @mount_path_pattern
|
29
|
-
env["PATH_INFO"].sub!(@mount_path_pattern, "")
|
30
|
-
elsif @app
|
31
|
-
return @app.call(env)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
case env["PATH_INFO"]
|
36
|
-
when ""
|
37
|
-
add_forward_slash(env)
|
38
|
-
when "/"
|
39
|
-
env["PATH_INFO"] = "index.html"
|
40
|
-
response = environment(:blade).call(env)
|
41
|
-
response_with_session(response, env)
|
42
|
-
when @websocket_path_pattern
|
43
|
-
bayeux.call(env)
|
44
|
-
when @adapter_path_pattern
|
45
|
-
env["PATH_INFO"].sub!(@adapter_path_pattern, "")
|
46
|
-
environment(:adapter).call(env)
|
47
|
-
when @blade_path_pattern
|
48
|
-
env["PATH_INFO"].sub!(@blade_path_pattern, "")
|
49
|
-
environment(:blade).call(env)
|
50
|
-
else
|
51
|
-
environment(:user).call(env)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
def bayeux
|
57
|
-
@bayeux ||= Faye::RackAdapter.new(mount: WEBSOCKET_PATH, timeout: 25)
|
58
|
-
end
|
59
|
-
|
60
|
-
def add_forward_slash(env)
|
61
|
-
path = @mount_path || env["REQUEST_PATH"] || env["SCRIPT_NAME"]
|
62
|
-
redirect_to(File.join(path.to_s, "/"))
|
63
|
-
end
|
64
|
-
|
65
|
-
def redirect_to(location, status = 301)
|
66
|
-
[status, { Location: location }, []]
|
67
|
-
end
|
68
|
-
|
69
|
-
def response_with_session(response, env)
|
70
|
-
if Blade.running?
|
71
|
-
user_agent = UserAgent.parse(env["HTTP_USER_AGENT"])
|
72
|
-
session = Blade::Session.create(user_agent: user_agent)
|
73
|
-
status, headers, body = response
|
74
|
-
response = Rack::Response.new(body, status, headers)
|
75
|
-
response.set_cookie("blade_session", session.id)
|
76
|
-
response.finish
|
77
|
-
else
|
78
|
-
response
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|