bigrig 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +12 -2
- data/lib/bigrig/descriptor.rb +3 -0
- data/lib/bigrig/output_parser.rb +46 -7
- data/lib/bigrig/version.rb +1 -1
- data/spec/bigrig/descriptor_spec.rb +34 -0
- data/spec/bigrig/output_parser_spec.rb +22 -0
- data/spec/bigrig_spec.rb +9 -1
- data/spec/data/adds_volume.json +17 -0
- data/spec/data/adds_volumes_from.json +17 -0
- data/spec/data/multiple_overrides.json +22 -0
- data/spec/support/vcr.rb +7 -2
- data/spec/vcr/Bigrig_DestroyAction/_perform/given_json_with_a_single_container/and_the_container_has_exited/should_remove_the_container.yml +46 -46
- data/spec/vcr/Bigrig_DestroyAction/_perform/given_json_with_a_single_container/and_the_container_is_running/kills_and_removes_the_container.yml +49 -49
- data/spec/vcr/Bigrig_DockerAdapter/_build/builds_the_given_directory.yml +9 -9
- data/spec/vcr/Bigrig_DockerAdapter/_build/passes_build_input_to_a_block.yml +4 -4
- data/spec/vcr/Bigrig_DockerAdapter/_container_exists_/when_the_container_does_not_exist/is_false.yml +8 -8
- data/spec/vcr/Bigrig_DockerAdapter/_container_exists_/when_the_container_exists/is_true.yml +10 -10
- data/spec/vcr/Bigrig_DockerAdapter/_image_id_by_tag/when_the_image_does_not_exist/raise_a_ImageNotFoundError.yml +12 -12
- data/spec/vcr/Bigrig_DockerAdapter/_image_id_by_tag/when_the_image_exists/returns_the_image_id.yml +12 -12
- data/spec/vcr/Bigrig_DockerAdapter/_kill/given_the_container_does_not_exist/should_raise_an_error.yml +8 -8
- data/spec/vcr/Bigrig_DockerAdapter/_kill/given_the_container_is_running/should_kill_the_container.yml +22 -22
- data/spec/vcr/Bigrig_DockerAdapter/_logs/streams_logs_to_a_block.yml +17 -17
- data/spec/vcr/Bigrig_DockerAdapter/_pull/given_a_block_to_capture_output/should_capture_output.yml +4 -4
- data/spec/vcr/Bigrig_DockerAdapter/_pull/given_the_repo_does_not_exist/raises_a_RepoNotFoundError.yml +2 -2
- data/spec/vcr/Bigrig_DockerAdapter/_pull/given_the_repo_exists/returns_the_image_id.yml +6 -6
- data/spec/vcr/Bigrig_DockerAdapter/_push/given_credentials/will_pass_login_and_password.yml +43 -43
- data/spec/vcr/Bigrig_DockerAdapter/_push/should_push_the_image.yml +143 -107
- data/spec/vcr/Bigrig_DockerAdapter/_remove_container/when_the_container_does_not_exist/raises_a_ContainerNotFoundError.yml +16 -16
- data/spec/vcr/Bigrig_DockerAdapter/_remove_container/when_the_container_exists/should_remove_the_container.yml +32 -32
- data/spec/vcr/Bigrig_DockerAdapter/_remove_container/when_the_container_is_running/raises_a_ContainerRunningError.yml +10 -10
- data/spec/vcr/Bigrig_DockerAdapter/_remove_image/when_the_image_doesnt_exist/raises_an_error.yml +8 -8
- data/spec/vcr/Bigrig_DockerAdapter/_remove_image/when_the_image_exists/removes_the_image.yml +27 -27
- data/spec/vcr/Bigrig_DockerAdapter/_run/given_an_image_id_that_exists/and_a_name/starts_the_container_with_the_right_name.yml +28 -28
- data/spec/vcr/Bigrig_DockerAdapter/_run/given_an_image_id_that_exists/and_a_name_and_env_variables/starts_the_container_with_env_set.yml +28 -28
- data/spec/vcr/Bigrig_DockerAdapter/_run/given_an_image_id_that_exists/and_a_name_and_ports/starts_the_container_with_ports_exposed.yml +32 -32
- data/spec/vcr/Bigrig_DockerAdapter/_running_/when_the_container_does_not_exist/returns_false.yml +8 -8
- data/spec/vcr/Bigrig_DockerAdapter/_running_/when_the_container_is_not_running/returns_false.yml +11 -11
- data/spec/vcr/Bigrig_DockerAdapter/_running_/when_the_container_is_running/returns_true.yml +13 -13
- data/spec/vcr/Bigrig_DockerAdapter/_tag/should_tag_the_image.yml +30 -83
- data/spec/vcr/Bigrig_LogAction/_perform/follows_the_log.yml +17 -17
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_a_path/builds_the_image_before_starting_it.yml +27 -176
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_hosts_by_ip/should_pass_hosts_to_container.yml +41 -41
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_hosts_by_name/should_lookup_ips_for_hosts_with_a_hostname.yml +41 -41
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_links/should_pass_links_to_the_right_container.yml +75 -75
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_multiple_containers/launches_both_containers_in_parallel.yml +52 -52
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_multiple_containers/spins_up_multiple_containers.yml +74 -74
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_one_container/should_spin_up_a_single_container.yml +37 -37
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_one_container/when_a_dead_container_exists/should_remove_existing_containers.yml +39 -39
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_volumes/should_pass_volumes_to_the_right_container.yml +40 -40
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_volumes_from/should_pass_volumes_from_to_the_right_container.yml +75 -75
- data/spec/vcr/Bigrig_RunAction/_perform/given_a_file_with_volumes_from/starts_the_dependant_container_last.yml +52 -52
- data/spec/vcr/Bigrig_RunAction/_perform/when_activating_profiles_that_do_not_exist/ignores_the_missing_profile.yml +43 -38
- data/spec/vcr/Bigrig_RunAction/_perform/with_a_file_with_active_profiles/uses_the_overridden_image.yml +39 -39
- data/spec/vcr/bigrig/destroy/spec/data/single_json/kills_the_container.yml +14 -14
- data/spec/vcr/bigrig/dev/spec/data/dev_json/activates_the_dev_profile.yml +227 -3
- data/spec/vcr/bigrig/dev/spec/data/dev_json/destroys_containers_on_exit.yml +240 -16
- data/spec/vcr/bigrig/dev/spec/data/dev_json/starts_the_containers.yml +238 -14
- data/spec/vcr/bigrig/dev/spec/data/dev_json/tails_the_logs.yml +227 -0
- data/spec/vcr/bigrig/logs/spec/data/log_json/tails_the_logs.yml +17 -17
- data/spec/vcr/bigrig/run/spec/data/profiles_json_-p_qa/leaves_existing_env_values_alone.yml +11 -11
- data/spec/vcr/bigrig/run/spec/data/profiles_json_-p_qa/overrides_the_env.yml +11 -11
- data/spec/vcr/bigrig/run/spec/data/profiles_json_-p_qa/overrides_the_tag.yml +11 -11
- data/spec/vcr/bigrig/run/spec/data/single_json/sends_the_name_of_the_container_to_stdout.yml +9 -9
- data/spec/vcr/bigrig/run/spec/data/single_json/starts_the_container.yml +13 -13
- data/spec/vcr/bigrig/ship/spec/data/ship_json/with_a_version/-c/cleans_the_image_when_its_done.yml +28 -28
- data/spec/vcr/bigrig/ship/spec/data/ship_json/with_a_version/builds_and_pushes_the_image.yml +17 -17
- data/spec/vcr/bigrig_bin_bigrig_destroy_spec/data/single_json_kills_the_container.yml +21 -21
- data/spec/vcr/bigrig_bin_bigrig_dev_spec/data/dev_json_activates_the_dev_profile.yml +109 -107
- data/spec/vcr/bigrig_bin_bigrig_dev_spec/data/dev_json_starts_the_containers.yml +108 -108
- data/spec/vcr/bigrig_bin_bigrig_dev_spec/data/dev_json_tails_the_logs.yml +118 -118
- data/spec/vcr/bigrig_bin_bigrig_logs_spec/data/log_json_tails_the_logs.yml +21 -21
- data/spec/vcr/bigrig_bin_bigrig_run_spec/data/profiles_json_-p_qa_leaves_existing_env_values_alone.yml +25 -25
- data/spec/vcr/bigrig_bin_bigrig_run_spec/data/profiles_json_-p_qa_overrides_the_env.yml +25 -25
- data/spec/vcr/bigrig_bin_bigrig_run_spec/data/profiles_json_-p_qa_overrides_the_tag.yml +24 -173
- data/spec/vcr/bigrig_bin_bigrig_run_spec/data/single_json_sends_the_name_of_the_container_to_stdout.yml +25 -25
- data/spec/vcr/bigrig_bin_bigrig_run_spec/data/single_json_starts_the_container.yml +25 -25
- data/spec/vcr/bigrig_bin_bigrig_ship_spec/data/ship_json_with_a_version_-c_cleans_the_image_when_its_done.yml +121 -85
- data/spec/vcr/bigrig_bin_bigrig_ship_spec/data/ship_json_with_a_version_builds_and_pushes_the_image.yml +113 -77
- metadata +6 -3
- data/spec/vcr/bigrig_bin_bigrig_dev_spec/data/dev_json_destroys_containers_on_exit.yml +0 -1070
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a001e90b4c9468158187737587e7927c425d79a7
|
4
|
+
data.tar.gz: d1efdce57b29e23ea77d8897cab045ea41be2474
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 444a62218b09974941e3e5c6e25e0192e2319c5ee5c095fbf27eb66cb4ca20f07b211daae439c569deee0a0ed2ec628cd7f59febd3276abb73959b490e02bf92
|
7
|
+
data.tar.gz: 483ef66f2692664071025f51046988c95380116ddb1cde2e8edd16e7d37b95571404ed79ffea2b88259336f429932f104097330920cc555a7c181b7437f25f7e
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
bigrig (0.1.
|
4
|
+
bigrig (0.1.1)
|
5
5
|
colorize (= 0.7.5)
|
6
6
|
docker-api (= 1.20.0)
|
7
7
|
gli (= 2.12.2)
|
@@ -14,15 +14,21 @@ GEM
|
|
14
14
|
ast (2.0.0)
|
15
15
|
astrolabe (1.3.0)
|
16
16
|
parser (>= 2.2.0.pre.3, < 3.0)
|
17
|
+
byebug (3.5.1)
|
18
|
+
columnize (~> 0.8)
|
19
|
+
debugger-linecache (~> 1.2)
|
20
|
+
slop (~> 3.6)
|
17
21
|
coderay (1.1.0)
|
18
22
|
colorize (0.7.5)
|
23
|
+
columnize (0.9.0)
|
19
24
|
crack (0.4.2)
|
20
25
|
safe_yaml (~> 1.0.0)
|
26
|
+
debugger-linecache (1.2.0)
|
21
27
|
diff-lcs (1.2.5)
|
22
28
|
docker-api (1.20.0)
|
23
29
|
excon (>= 0.38.0)
|
24
30
|
json
|
25
|
-
excon (0.
|
31
|
+
excon (0.45.1)
|
26
32
|
gli (2.12.2)
|
27
33
|
json (1.8.2)
|
28
34
|
method_source (0.8.2)
|
@@ -38,6 +44,9 @@ GEM
|
|
38
44
|
coderay (~> 1.1.0)
|
39
45
|
method_source (~> 0.8.1)
|
40
46
|
slop (~> 3.4)
|
47
|
+
pry-byebug (2.0.0)
|
48
|
+
byebug (~> 3.4)
|
49
|
+
pry (~> 0.10)
|
41
50
|
rainbow (2.0.0)
|
42
51
|
rake (10.4.2)
|
43
52
|
rspec (3.1.0)
|
@@ -76,6 +85,7 @@ DEPENDENCIES
|
|
76
85
|
bigrig!
|
77
86
|
popen4
|
78
87
|
pry
|
88
|
+
pry-byebug
|
79
89
|
rake
|
80
90
|
rspec
|
81
91
|
rspec-its
|
data/lib/bigrig/descriptor.rb
CHANGED
@@ -25,6 +25,8 @@ module Bigrig
|
|
25
25
|
container = container_map[name] ||= {}
|
26
26
|
if value.is_a? Hash
|
27
27
|
(container[key] ||= {}).merge! value
|
28
|
+
elsif %w(volumes volumes_from).include? key
|
29
|
+
container[key] = (([container[key]] || []) + [value]).flatten
|
28
30
|
else
|
29
31
|
container[key] = value
|
30
32
|
end
|
@@ -33,6 +35,7 @@ module Bigrig
|
|
33
35
|
|
34
36
|
def self.profiles_for(json, active_profiles)
|
35
37
|
if json['profiles']
|
38
|
+
active_profiles = json['profiles'].keys.select { |x| active_profiles.include? x }
|
36
39
|
profiles = active_profiles.map do |profile|
|
37
40
|
[profile, json['profiles'][profile]]
|
38
41
|
end
|
data/lib/bigrig/output_parser.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'pry-byebug'
|
2
|
+
|
1
3
|
module Bigrig
|
2
4
|
class OutputParser
|
3
5
|
def self.parser_proc
|
@@ -6,25 +8,62 @@ module Bigrig
|
|
6
8
|
|
7
9
|
def initialize
|
8
10
|
@last_line = ''
|
11
|
+
@buffer = ''
|
9
12
|
end
|
10
13
|
|
11
14
|
def parse(input)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
output = documents(input).map do |json|
|
16
|
+
if json['errorDetail']
|
17
|
+
"#{json['errorDetail']['message'].red}\n"
|
18
|
+
elsif json['stream'] || json['id'].nil?
|
19
|
+
json['stream'] || "#{json['status']}\n"
|
20
|
+
else
|
21
|
+
parse_progress json
|
22
|
+
end
|
19
23
|
end
|
24
|
+
output.join
|
20
25
|
end
|
21
26
|
|
22
27
|
private
|
23
28
|
|
29
|
+
def documents(str)
|
30
|
+
@buffer += str
|
31
|
+
documents = []
|
32
|
+
begin
|
33
|
+
loop do
|
34
|
+
documents << JSON.parse(next_document)
|
35
|
+
end
|
36
|
+
rescue JSON::ParserError # rubocop:disable Lint/HandleExceptions
|
37
|
+
end
|
38
|
+
documents
|
39
|
+
end
|
40
|
+
|
24
41
|
def last_line_length
|
25
42
|
@last_line.strip.length
|
26
43
|
end
|
27
44
|
|
45
|
+
# rubocop:disable all
|
46
|
+
def next_document
|
47
|
+
chars = @buffer.chars
|
48
|
+
i = count = 0
|
49
|
+
string = false
|
50
|
+
|
51
|
+
while i < chars.length
|
52
|
+
chars[i] == '"' && string = !string
|
53
|
+
chars[i] == '\\' && i += 1
|
54
|
+
unless string
|
55
|
+
chars[i] == '{' && count += 1
|
56
|
+
chars[i] == '}' && count -= 1
|
57
|
+
end
|
58
|
+
count == 0 && chars[0..i].join.strip.length > 0 && break
|
59
|
+
i += 1
|
60
|
+
end
|
61
|
+
|
62
|
+
count == 0 && @buffer = (chars.join[i + 1..-1] || '')
|
63
|
+
chars.join[0..i]
|
64
|
+
end
|
65
|
+
# rubocop:enable all
|
66
|
+
|
28
67
|
def padding(line)
|
29
68
|
if last_line_length > line.length
|
30
69
|
padding = ' ' * (last_line_length - line.length)
|
data/lib/bigrig/version.rb
CHANGED
@@ -43,6 +43,40 @@ module Bigrig
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
context 'given a descriptor that adds a volume' do
|
47
|
+
let(:file) { 'adds_volume.json' }
|
48
|
+
let(:profiles) { ['qa'] }
|
49
|
+
let(:volumes) { subject.as_json['adds_volumes']['volumes'] }
|
50
|
+
|
51
|
+
it 'includes both volumes' do
|
52
|
+
expect(volumes).to be_a Array
|
53
|
+
expect(volumes).to include '/tmp/volume1'
|
54
|
+
expect(volumes).to include '/tmp/volume2'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'given a descriptor that adds a volumes_from' do
|
59
|
+
let(:file) { 'adds_volumes_from.json' }
|
60
|
+
let(:profiles) { ['qa'] }
|
61
|
+
let(:volumes_from) { subject.as_json['adds_volumes_from']['volumes_from'] }
|
62
|
+
|
63
|
+
it 'includes both volumes' do
|
64
|
+
expect(volumes_from).to be_a Array
|
65
|
+
expect(volumes_from).to include 'container1'
|
66
|
+
expect(volumes_from).to include 'container2'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'given a descriptor that overrides the same value in multiple profiles' do
|
71
|
+
let(:file) { 'multiple_overrides.json' }
|
72
|
+
let(:profiles) { %w(profile2 profile1) }
|
73
|
+
let(:tag) { subject.as_json['container']['tag'] }
|
74
|
+
|
75
|
+
it 'uses the last value in the file' do
|
76
|
+
expect(tag).to eq 'profile2'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
46
80
|
context 'given a descriptor that adds a container' do
|
47
81
|
let(:file) { 'addscontainer.json' }
|
48
82
|
let(:profiles) { ['new'] }
|
@@ -9,6 +9,20 @@ module Bigrig
|
|
9
9
|
let(:mock_io) { double IO }
|
10
10
|
let(:output) { subject }
|
11
11
|
|
12
|
+
context 'when the document comes in multiple chunks' do
|
13
|
+
let(:input) { ['{"stream": "val', 'ue"}'] }
|
14
|
+
it 'parses the document' do
|
15
|
+
expect(output).to eq 'value'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when the chunk contains multiple documents' do
|
20
|
+
let(:input) { '{"stream": "value1"} {"stream": "value2"}' }
|
21
|
+
it 'parses both documents' do
|
22
|
+
expect(output).to eq 'value1value2'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
12
26
|
context 'with input that has a stream' do
|
13
27
|
let(:input) { '{"stream": "value"}' }
|
14
28
|
|
@@ -66,6 +80,14 @@ module Bigrig
|
|
66
80
|
expect(output).to eq "id: status progress \r"
|
67
81
|
end
|
68
82
|
end
|
83
|
+
|
84
|
+
context 'given string with tokens' do
|
85
|
+
let(:input) { '{"status": "bla bla bla} { \\" bla"}' }
|
86
|
+
|
87
|
+
it 'ignores the special characters' do
|
88
|
+
expect(output).to eq "bla bla bla} { \" bla\n"
|
89
|
+
end
|
90
|
+
end
|
69
91
|
end
|
70
92
|
end
|
71
93
|
end
|
data/spec/bigrig_spec.rb
CHANGED
@@ -19,6 +19,15 @@ describe 'bigrig' do
|
|
19
19
|
text.split("\n").each_with_object({}) { |e, o| o.store(*e.split('=')) }
|
20
20
|
end
|
21
21
|
|
22
|
+
before do
|
23
|
+
['dev-test', 'dev-logs'].each do |container|
|
24
|
+
begin
|
25
|
+
Docker::Container.get(container).kill.delete
|
26
|
+
rescue Docker::Error::NotFoundError # rubocop:disable Lint/HandleExceptions
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
22
31
|
it 'starts the containers', :vcr do
|
23
32
|
command = %(spec/support/bigrig_vcr "#{casette_name}" #{args.join ' '})
|
24
33
|
pid = Open4.popen4(command).first
|
@@ -37,7 +46,6 @@ describe 'bigrig' do
|
|
37
46
|
it 'destroys containers on exit', :vcr do
|
38
47
|
command = %(spec/support/bigrig_vcr "#{casette_name}" #{args.join ' '})
|
39
48
|
pid = Open4.popen4(command).first
|
40
|
-
sleep 2
|
41
49
|
Process.kill :SIGINT, pid
|
42
50
|
Process.wait pid
|
43
51
|
begin
|
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"containers": {
|
3
|
+
"container": {
|
4
|
+
"repo": "hawknewton/true",
|
5
|
+
"tag": "0.0.1"
|
6
|
+
}
|
7
|
+
},
|
8
|
+
|
9
|
+
"profiles": {
|
10
|
+
"profile1": {
|
11
|
+
"container": {
|
12
|
+
"tag": "profile1"
|
13
|
+
}
|
14
|
+
},
|
15
|
+
|
16
|
+
"profile2": {
|
17
|
+
"container": {
|
18
|
+
"tag": "profile2"
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
data/spec/support/vcr.rb
CHANGED
@@ -3,12 +3,17 @@ require 'webmock'
|
|
3
3
|
require 'docker'
|
4
4
|
|
5
5
|
VCR.configure do |c|
|
6
|
+
docker_host = URI.parse(Docker.url).host
|
6
7
|
c.allow_http_connections_when_no_cassette = false
|
7
|
-
c.filter_sensitive_data('<DOCKER_HOST>') { Docker.url.sub(/tcp\:/, 'https:') }
|
8
|
-
c.filter_sensitive_data('<DOCKER_HTTP>') { "http:#{Docker.url.split(':')[1]}:4567" }
|
9
8
|
c.filter_sensitive_data('<USERNAME>') { ENV['DOCKER_API_USER'] }
|
10
9
|
c.filter_sensitive_data('<PASSWORD>') { ENV['DOCKER_API_PASS'] }
|
11
10
|
c.filter_sensitive_data('<EMAIL>') { ENV['DOCKER_API_EMAIL'] }
|
11
|
+
|
12
|
+
c.define_cassette_placeholder('<ENCODED_REPO_URL>') { "#{docker_host}%3A5000" }
|
13
|
+
c.define_cassette_placeholder('<REPO_URL>') { "#{docker_host}:5000" }
|
14
|
+
c.define_cassette_placeholder('<TEST_URL>') { "http://#{docker_host}:4568" }
|
15
|
+
c.define_cassette_placeholder('<DOCKER_HOST>') { Docker.url.sub(/tcp\:/, 'https:') }
|
16
|
+
c.define_cassette_placeholder('<DOCKER_HTTP>') { "http:#{Docker.url.split(':')[1]}:4567" }
|
12
17
|
c.hook_into :excon, :webmock
|
13
18
|
c.cassette_library_dir = File.join(File.dirname(__FILE__), '..', 'vcr')
|
14
19
|
defined?(RSpec) && c.configure_rspec_metadata!
|