chicanery 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +13 -13
- data/README.md +40 -8
- data/examples/chicanery.rb +15 -0
- data/lib/chicanery/cctray.rb +9 -21
- data/lib/chicanery/handlers.rb +1 -1
- data/lib/chicanery/repos.rb +26 -0
- data/lib/chicanery/{state_comparison.rb → servers.rb} +16 -9
- data/lib/chicanery/site.rb +26 -0
- data/lib/chicanery/sites.rb +32 -0
- data/lib/chicanery/summary.rb +6 -0
- data/lib/chicanery.rb +20 -31
- data/spec/chicanery/cctray_spec.rb +3 -4
- data/spec/chicanery/{state_comparison_spec.rb → servers_spec.rb} +2 -2
- data/spec/chicanery_spec.rb +1 -4
- metadata +10 -7
data/Gemfile.lock
CHANGED
@@ -1,32 +1,32 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
chicanery (0.1.
|
4
|
+
chicanery (0.1.1)
|
5
5
|
nokogiri (~> 1)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
diff-lcs (1.1
|
10
|
+
diff-lcs (1.2.1)
|
11
11
|
fakeweb (1.3.0)
|
12
|
-
multi_json (1.
|
12
|
+
multi_json (1.6.1)
|
13
13
|
nokogiri (1.5.6)
|
14
|
-
rake (0.9.
|
15
|
-
rspec (2.
|
16
|
-
rspec-core (~> 2.
|
17
|
-
rspec-expectations (~> 2.
|
18
|
-
rspec-mocks (~> 2.
|
19
|
-
rspec-core (2.
|
20
|
-
rspec-expectations (2.
|
21
|
-
diff-lcs (
|
22
|
-
rspec-mocks (2.
|
14
|
+
rake (0.9.6)
|
15
|
+
rspec (2.13.0)
|
16
|
+
rspec-core (~> 2.13.0)
|
17
|
+
rspec-expectations (~> 2.13.0)
|
18
|
+
rspec-mocks (~> 2.13.0)
|
19
|
+
rspec-core (2.13.0)
|
20
|
+
rspec-expectations (2.13.0)
|
21
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
22
|
+
rspec-mocks (2.13.0)
|
23
23
|
simplecov (0.7.1)
|
24
24
|
multi_json (~> 1.0)
|
25
25
|
simplecov-html (~> 0.7.1)
|
26
26
|
simplecov-gem-adapter (1.0.1)
|
27
27
|
simplecov
|
28
28
|
simplecov-html (0.7.1)
|
29
|
-
vcr (2.
|
29
|
+
vcr (2.4.0)
|
30
30
|
|
31
31
|
PLATFORMS
|
32
32
|
ruby
|
data/README.md
CHANGED
@@ -16,18 +16,18 @@ State is persisted between executions so that it be scheduled to run regularly w
|
|
16
16
|
|
17
17
|
Create a configuration file. This file is just a ruby file that can make use of a few configuration and callback methods:
|
18
18
|
|
19
|
-
require 'chicanery/cctray'
|
20
19
|
require 'chicanery/git'
|
21
|
-
|
22
20
|
include Chicanery::Git
|
23
|
-
|
24
|
-
git_repo 'chicanery', '/tmp/chicanery', remotes: {
|
21
|
+
git 'chicanery', '.', branches: [:master], remotes: {
|
25
22
|
github: { url: 'git://github.com/markryall/chicanery.git' }
|
26
23
|
}
|
27
|
-
|
24
|
+
|
25
|
+
require 'chicanery/cctray'
|
26
|
+
include Chicanery::Cctray
|
27
|
+
cctray 'tddium', 'https://cihost.com/cctray.xml'
|
28
28
|
|
29
29
|
when_run do |state|
|
30
|
-
puts
|
30
|
+
puts state.has_failure? ? "something is wrong" : "all builds are fine"
|
31
31
|
end
|
32
32
|
|
33
33
|
when_commit do |repo, commit, previous|
|
@@ -66,6 +66,39 @@ If you want to specify an alternate location for this state file, add the follow
|
|
66
66
|
|
67
67
|
persist_state_to '/tmp/build_state'
|
68
68
|
|
69
|
+
# Callbacks
|
70
|
+
|
71
|
+
## General
|
72
|
+
|
73
|
+
The 'when_run' callback is executed on every poll.
|
74
|
+
|
75
|
+
## Servers
|
76
|
+
|
77
|
+
The following callbacks may be received after checking a CI server:
|
78
|
+
|
79
|
+
* when_started - when a new job has started
|
80
|
+
* when_succeeded - when a job finishes successfully
|
81
|
+
* when_failed - when a job finishes unsuccessfully
|
82
|
+
* when_broken - when a previously passing job fails
|
83
|
+
* when_fixed - when a previously failing job passes
|
84
|
+
|
85
|
+
## Repos
|
86
|
+
|
87
|
+
The following callbacks may be received after checking a source repository:
|
88
|
+
|
89
|
+
* when_commit - when a new commit is detected in the repository
|
90
|
+
|
91
|
+
Currently only git repositories are supported.
|
92
|
+
|
93
|
+
## Site
|
94
|
+
|
95
|
+
The following callbacks may be received after checking a web site:
|
96
|
+
|
97
|
+
* when_up - the website responded with a 2xx HTTP status
|
98
|
+
* when_down - the website did not responded with a 2xx HTTP status
|
99
|
+
* when_crashed - the website was previously up and is now down
|
100
|
+
* when_recovered - the website was previously down and is now up
|
101
|
+
|
69
102
|
## Supported CI servers
|
70
103
|
|
71
104
|
Currently only ci servers that can provide [cctray reporting format](http://confluence.public.thoughtworks.org/display/CI/Multiple+Project+Summary+Reporting+Standard) are supported.
|
@@ -88,7 +121,6 @@ Basic authentication is supported by passing :user => 'user', :password => 'pass
|
|
88
121
|
* monitoring a subversion repository for commit notifications
|
89
122
|
* monitoring heroku for deployment event notification
|
90
123
|
* monitoring more ci servers (atlassian bamboo, jetbrains team city, etc.)
|
91
|
-
* integration with the blinky gem to control a delcom build light
|
92
124
|
* other interesting notifier plugins or examples
|
93
125
|
|
94
126
|
## Contributing
|
@@ -97,4 +129,4 @@ Basic authentication is supported by passing :user => 'user', :password => 'pass
|
|
97
129
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
98
130
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
99
131
|
4. Push to the branch (`git push origin my-new-feature`)
|
100
|
-
5. Create new Pull Request
|
132
|
+
5. Create new Pull Request
|
data/examples/chicanery.rb
CHANGED
@@ -10,6 +10,8 @@ git 'chicanery', '.', branches: [:master], remotes: {
|
|
10
10
|
|
11
11
|
cctray 'travis', 'https://api.travis-ci.org/repositories/markryall/chicanery/cc.xml'
|
12
12
|
|
13
|
+
site 'travis', 'https://api.travis-ci.org/repositories/markryall/chicanery.json'
|
14
|
+
|
13
15
|
poll_period 10
|
14
16
|
|
15
17
|
def growlnotify message
|
@@ -18,6 +20,7 @@ end
|
|
18
20
|
|
19
21
|
when_run do |state|
|
20
22
|
puts state.has_failure? ? "something is wrong" : "all builds are fine"
|
23
|
+
puts state.site_down? ? "something is wrong" : "all sites are fine"
|
21
24
|
end
|
22
25
|
|
23
26
|
when_commit do |repo, commit, previous|
|
@@ -45,4 +48,16 @@ end
|
|
45
48
|
when_fixed do |job_name, job|
|
46
49
|
growlnotify "job #{job_name} is fixed"
|
47
50
|
`afplay ~/build_sounds/applause.mp3`
|
51
|
+
end
|
52
|
+
|
53
|
+
when_up do |name, site|
|
54
|
+
puts "#{name} returned #{site.code} in #{site.duration} seconds"
|
55
|
+
end
|
56
|
+
|
57
|
+
when_crashed do |name, site|
|
58
|
+
puts "#{name} has crashed with status of #{site.code}"
|
59
|
+
end
|
60
|
+
|
61
|
+
when_recovered do |name, site|
|
62
|
+
puts "#{name} has recovered with status of #{site.code}"
|
48
63
|
end
|
data/lib/chicanery/cctray.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'chicanery/site'
|
2
2
|
require 'nokogiri'
|
3
3
|
require 'date'
|
4
4
|
|
@@ -12,31 +12,14 @@ module Chicanery
|
|
12
12
|
server Cctray::Server.new *args
|
13
13
|
end
|
14
14
|
|
15
|
-
class Server
|
16
|
-
attr_reader :name, :uri, :options
|
17
|
-
|
18
|
-
def initialize name, url, options={}
|
19
|
-
@name, @uri, @options = name, URI(url), options
|
20
|
-
end
|
21
|
-
|
22
|
-
def get
|
23
|
-
req = Net::HTTP::Get.new(uri.path)
|
24
|
-
req.basic_auth options[:user], options[:password] if options[:user] and options[:password]
|
25
|
-
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https', verify_mode: OpenSSL::SSL::VERIFY_NONE) do |https|
|
26
|
-
https.request(req)
|
27
|
-
end
|
28
|
-
res.value #check for success via a spectactulalry poorly named method
|
29
|
-
res.body
|
30
|
-
end
|
31
|
-
|
15
|
+
class Server < Chicanery::Site
|
32
16
|
def jobs
|
33
17
|
jobs = {}
|
34
|
-
response_body = get
|
35
|
-
Nokogiri::XML(response_body).css("Project").each do |project|
|
18
|
+
Nokogiri::XML(response_body = get).css("Project").each do |project|
|
36
19
|
job = {
|
37
20
|
activity: project[:activity] == 'Sleeping' ? :sleeping : :building,
|
38
21
|
last_build_status: parse_build_status(project[:lastBuildStatus]),
|
39
|
-
last_build_time:
|
22
|
+
last_build_time: parse_build_time(project[:lastBuildTime]),
|
40
23
|
url: project[:webUrl],
|
41
24
|
last_label: project[:lastBuildLabel]
|
42
25
|
}
|
@@ -46,6 +29,11 @@ module Chicanery
|
|
46
29
|
jobs
|
47
30
|
end
|
48
31
|
|
32
|
+
def parse_build_time time
|
33
|
+
return nil if time.nil? || time.empty?
|
34
|
+
DateTime.parse(time).to_time.to_i
|
35
|
+
end
|
36
|
+
|
49
37
|
def parse_build_status status
|
50
38
|
case status
|
51
39
|
when /^Success/ then :success
|
data/lib/chicanery/handlers.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Chicanery
|
2
2
|
module Handlers
|
3
|
-
%w{run started succeeded failed broken fixed commit}.each do |status|
|
3
|
+
%w{run started succeeded failed broken fixed commit up down crashed recovered}.each do |status|
|
4
4
|
class_eval <<-EOF
|
5
5
|
def when_#{status} &block
|
6
6
|
#{status}_handlers << block
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'chicanery/collections'
|
2
|
+
require 'chicanery/handlers'
|
3
|
+
|
4
|
+
module Chicanery
|
5
|
+
module Repos
|
6
|
+
include Collections
|
7
|
+
include Handlers
|
8
|
+
|
9
|
+
def check_repos current_state, previous_state
|
10
|
+
current_state[:repos] = {}
|
11
|
+
repos.each do |repo|
|
12
|
+
repo_state = repo.state
|
13
|
+
compare_repo_state repo.name, repo_state, previous_state[:repos][repo.name] if previous_state[:repos]
|
14
|
+
current_state[:repos][repo.name] = repo_state
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def compare_repo_state name, current, previous
|
19
|
+
return unless previous
|
20
|
+
current.each do |branch, state|
|
21
|
+
next unless previous[branch]
|
22
|
+
notify_commit_handlers "#{name}/#{branch}", state, previous[branch] if state != previous[branch]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -1,5 +1,20 @@
|
|
1
|
+
require 'chicanery/collections'
|
2
|
+
require 'chicanery/handlers'
|
3
|
+
|
1
4
|
module Chicanery
|
2
|
-
module
|
5
|
+
module Servers
|
6
|
+
include Collections
|
7
|
+
include Handlers
|
8
|
+
|
9
|
+
def check_servers current_state, previous_state
|
10
|
+
current_state[:servers] = {}
|
11
|
+
servers.each do |server|
|
12
|
+
current_jobs = server.jobs
|
13
|
+
compare_jobs current_jobs, previous_state[:servers][server.name] if previous_state[:servers]
|
14
|
+
current_state[:servers][server.name] = current_jobs
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
3
18
|
def compare_jobs current_jobs, previous_jobs
|
4
19
|
return unless previous_jobs
|
5
20
|
current_jobs.each do |job_name, job|
|
@@ -17,13 +32,5 @@ module Chicanery
|
|
17
32
|
notify_broken_handlers name, current if current[:last_build_status] == :failure and previous[:last_build_status] == :success
|
18
33
|
notify_fixed_handlers name, current if current[:last_build_status] == :success and previous[:last_build_status] == :failure
|
19
34
|
end
|
20
|
-
|
21
|
-
def compare_repo_state name, current, previous
|
22
|
-
return unless previous
|
23
|
-
current.each do |branch, state|
|
24
|
-
next unless previous[branch]
|
25
|
-
notify_commit_handlers "#{name}/#{branch}", state, previous[branch] if state != previous[branch]
|
26
|
-
end
|
27
|
-
end
|
28
35
|
end
|
29
36
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'benchmark'
|
3
|
+
|
4
|
+
module Chicanery
|
5
|
+
class Site
|
6
|
+
attr_reader :name, :uri, :options, :body, :code, :duration
|
7
|
+
|
8
|
+
def initialize name, url, options={}
|
9
|
+
@name, @uri, @options = name, URI(url), options
|
10
|
+
end
|
11
|
+
|
12
|
+
def get
|
13
|
+
req = Net::HTTP::Get.new uri.path
|
14
|
+
req.basic_auth options[:user], options[:password] if options[:user] and options[:password]
|
15
|
+
http_opts = { use_ssl: uri.scheme == 'https' }
|
16
|
+
http_opts[:verify_mode] = OpenSSL::SSL::VERIFY_NONE unless options[:verify_ssl]
|
17
|
+
start = Time.now
|
18
|
+
res = Net::HTTP.start uri.host, uri.port, http_opts do |https|
|
19
|
+
https.request req
|
20
|
+
end
|
21
|
+
@duration, @code, @body = (Time.now - start), res.code, res.body
|
22
|
+
res.value #check for success via a spectactularly poorly named method
|
23
|
+
res.body
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'chicanery/handlers'
|
2
|
+
require 'chicanery/site'
|
3
|
+
|
4
|
+
module Chicanery
|
5
|
+
module Sites
|
6
|
+
include Handlers
|
7
|
+
|
8
|
+
def sites
|
9
|
+
@sites ||= []
|
10
|
+
end
|
11
|
+
|
12
|
+
def site *args
|
13
|
+
sites << Chicanery::Site.new(*args)
|
14
|
+
end
|
15
|
+
|
16
|
+
def check_sites current_state, previous_state
|
17
|
+
current_state[:sites] = {}
|
18
|
+
sites.each do |site|
|
19
|
+
begin
|
20
|
+
content = site.get
|
21
|
+
current_state[:sites][site.name] = :up
|
22
|
+
notify_up_handlers site.name, site
|
23
|
+
notify_recovered_handlers site.name, site if previous_state && previous_state[:sites] && previous_state[:sites][site.name] == :down
|
24
|
+
rescue Exception
|
25
|
+
current_state[:sites][site.name] = :down
|
26
|
+
notify_down_handlers site.name, site
|
27
|
+
notify_crashed_handlers site.name, site if previous_state && previous_state[:sites] && previous_state[:sites][site.name] == :up
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/chicanery/summary.rb
CHANGED
data/lib/chicanery.rb
CHANGED
@@ -5,18 +5,18 @@ if ENV['COVERAGE']
|
|
5
5
|
end
|
6
6
|
|
7
7
|
require 'chicanery/persistence'
|
8
|
-
require 'chicanery/
|
9
|
-
require 'chicanery/
|
10
|
-
require 'chicanery/
|
8
|
+
require 'chicanery/servers'
|
9
|
+
require 'chicanery/repos'
|
10
|
+
require 'chicanery/sites'
|
11
11
|
require 'chicanery/summary'
|
12
12
|
|
13
13
|
module Chicanery
|
14
14
|
include Persistence
|
15
|
-
include
|
16
|
-
include
|
17
|
-
include
|
15
|
+
include Servers
|
16
|
+
include Repos
|
17
|
+
include Sites
|
18
18
|
|
19
|
-
VERSION = "0.1.
|
19
|
+
VERSION = "0.1.1"
|
20
20
|
|
21
21
|
def poll_period seconds=nil
|
22
22
|
@poll_period = seconds if seconds
|
@@ -24,40 +24,29 @@ module Chicanery
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def execute args
|
27
|
-
|
28
|
-
|
27
|
+
begin
|
28
|
+
load args.shift
|
29
|
+
run_every poll_period
|
30
|
+
rescue Interrupt
|
31
|
+
end
|
29
32
|
end
|
30
33
|
|
31
34
|
def run_every poll_period
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
sleep poll_period
|
37
|
-
end
|
38
|
-
rescue Interrupt
|
35
|
+
loop do
|
36
|
+
run
|
37
|
+
break unless poll_period
|
38
|
+
sleep poll_period
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
def run
|
43
43
|
previous_state = restore
|
44
|
-
current_state = {
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
repos.each do |repo|
|
49
|
-
repo_state = repo.state
|
50
|
-
compare_repo_state repo.name, repo_state, previous_state[:repos][repo.name] if previous_state[:repos]
|
51
|
-
current_state[:repos][repo.name] = repo_state
|
52
|
-
end
|
53
|
-
servers.each do |server|
|
54
|
-
current_jobs = server.jobs
|
55
|
-
compare_jobs current_jobs, previous_state[:servers][server.name] if previous_state[:servers]
|
56
|
-
current_state[:servers][server.name] = current_jobs
|
57
|
-
end
|
44
|
+
current_state = {}
|
45
|
+
check_servers current_state, previous_state
|
46
|
+
check_repos current_state, previous_state
|
47
|
+
check_sites current_state, previous_state
|
58
48
|
current_state.extend Chicanery::Summary
|
59
49
|
run_handlers.each {|handler| handler.call current_state, previous_state }
|
60
50
|
persist current_state
|
61
51
|
end
|
62
|
-
|
63
52
|
end
|
@@ -52,17 +52,16 @@ describe Chicanery::Cctray do
|
|
52
52
|
}
|
53
53
|
end
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
it 'should complain if there are no jobs in response' do
|
57
57
|
VCR.use_cassette('no_projects') do
|
58
58
|
expect{server.jobs}.to raise_error "could not find any jobs in response: [Nothing here but us chickens]"
|
59
59
|
end
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
it 'should complain if it gets a non 2xx response' do
|
63
63
|
VCR.use_cassette('redirect') do
|
64
64
|
expect{server.jobs}.to raise_error Net::HTTPRetriableError
|
65
65
|
end
|
66
|
-
end
|
67
|
-
|
66
|
+
end
|
68
67
|
end
|
data/spec/chicanery_spec.rb
CHANGED
@@ -15,10 +15,7 @@ describe Chicanery do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should persist new state' do
|
18
|
-
should_receive(:persist).with
|
19
|
-
servers: {},
|
20
|
-
repos: {}
|
21
|
-
})
|
18
|
+
should_receive(:persist).with servers: {}, repos: {}, sites: {}
|
22
19
|
end
|
23
20
|
|
24
21
|
it 'should sleep for specified time when poll period is provided' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chicanery
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01
|
12
|
+
date: 2013-03-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
@@ -154,12 +154,15 @@ files:
|
|
154
154
|
- lib/chicanery/git.rb
|
155
155
|
- lib/chicanery/handlers.rb
|
156
156
|
- lib/chicanery/persistence.rb
|
157
|
-
- lib/chicanery/
|
157
|
+
- lib/chicanery/repos.rb
|
158
|
+
- lib/chicanery/servers.rb
|
159
|
+
- lib/chicanery/site.rb
|
160
|
+
- lib/chicanery/sites.rb
|
158
161
|
- lib/chicanery/summary.rb
|
159
162
|
- spec/chicanery/cctray_spec.rb
|
160
163
|
- spec/chicanery/collections_spec.rb
|
161
164
|
- spec/chicanery/persistence_spec.rb
|
162
|
-
- spec/chicanery/
|
165
|
+
- spec/chicanery/servers_spec.rb
|
163
166
|
- spec/chicanery/summary_spec.rb
|
164
167
|
- spec/chicanery_spec.rb
|
165
168
|
- spec/embedded_chicanery_spec.rb
|
@@ -177,7 +180,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
177
180
|
version: '0'
|
178
181
|
segments:
|
179
182
|
- 0
|
180
|
-
hash: -
|
183
|
+
hash: -3139042759217892738
|
181
184
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
182
185
|
none: false
|
183
186
|
requirements:
|
@@ -186,7 +189,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
186
189
|
version: '0'
|
187
190
|
segments:
|
188
191
|
- 0
|
189
|
-
hash: -
|
192
|
+
hash: -3139042759217892738
|
190
193
|
requirements: []
|
191
194
|
rubyforge_project:
|
192
195
|
rubygems_version: 1.8.23
|
@@ -197,7 +200,7 @@ test_files:
|
|
197
200
|
- spec/chicanery/cctray_spec.rb
|
198
201
|
- spec/chicanery/collections_spec.rb
|
199
202
|
- spec/chicanery/persistence_spec.rb
|
200
|
-
- spec/chicanery/
|
203
|
+
- spec/chicanery/servers_spec.rb
|
201
204
|
- spec/chicanery/summary_spec.rb
|
202
205
|
- spec/chicanery_spec.rb
|
203
206
|
- spec/embedded_chicanery_spec.rb
|