cbratest 0.1.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 +7 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +83 -0
- data/Rakefile +1 -0
- data/bin/cbratest +47 -0
- data/cbratest.gemspec +35 -0
- data/lib/cbratest/affected_component_finder.rb +15 -0
- data/lib/cbratest/gemfile_scraper.rb +93 -0
- data/lib/cbratest/tests_to_run_selector.rb +10 -0
- data/lib/cbratest/transitive_affected_component_finder.rb +16 -0
- data/lib/cbratest.rb +73 -0
- metadata +100 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 16bd9373d934ef9e11eda3fef3e7c1c565684bcf
|
4
|
+
data.tar.gz: 5d9433bf389ac8b5e5aa4e17beb66ec5759d2849
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7b13cdfad482952919d2206676069c9651883dbb03fb21db1d679ff74b7d4318e7c96e4d60b582a7b88803f15055d871ac0fce81d1f5288738c9d3974c14d8ae
|
7
|
+
data.tar.gz: 494e91e3e8855674531303bc69d75985ee7d40b1e31858009457599580082e87013384ecdbce3c057f485fa26d7c28bd82c1e800300dad5d62451bdb20b663c8
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Stephan Hagemann
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# cbratest [](https://travis-ci.org/shageman/cbratest) [](http://badge.fury.io/rb/cbratest) [](https://codeclimate.com/github/shageman/cbratest) [](https://gemnasium.com/shageman/cbratest)
|
2
|
+
|
3
|
+
Prints a list of the components that have changed since the last commit and for which tests need to be run. Uses the dependencies within component-based Ruby/Rails applications (#cbra) to also print all transitively affected components.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'cbratest'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install cbratest
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
cbratest [OPTION] [application path]
|
22
|
+
|
23
|
+
Test runner employing the structure of Component-based Ruby/Rails apps to optimize what needs to run.
|
24
|
+
|
25
|
+
Options are...
|
26
|
+
-h, -H, --help Display this help message.
|
27
|
+
|
28
|
+
-r, --results DEFAULT Display the directories of the components in need of running tests
|
29
|
+
-v, --verbose Verbose output of all parts of the calculation
|
30
|
+
|
31
|
+
## Example
|
32
|
+
|
33
|
+
There are sample #cbra folder structures in `spec/examples`. Here is an example run when changing a file in component `C`:
|
34
|
+
|
35
|
+
± |master ✗| → bin/cbratest ~/workspace/cbratest/spec/examples/letters/A
|
36
|
+
/Users/stephan/workspace/cbratest/spec/examples/letters/B/test.sh
|
37
|
+
/Users/stephan/workspace/cbratest/spec/examples/letters/C/test.sh
|
38
|
+
/Users/stephan/workspace/cbratest/spec/examples/letters/A/test.sh
|
39
|
+
|
40
|
+
This output can be used to run the necessary tests like so:
|
41
|
+
|
42
|
+
bin/cbratest ~/workspace/cbratest/spec/examples/letters/A | xargs -n1 /bin/bash
|
43
|
+
|
44
|
+
In verbose mode one can check the correctness of cbratest's calculation:
|
45
|
+
|
46
|
+
± |master ✗| → bin/cbratest -v ~/workspace/cbra/cbratest/spec/examples/letters/A
|
47
|
+
All components
|
48
|
+
B /Users/stephan/workspace/cbra/cbratest/spec/examples/letters/B
|
49
|
+
C /Users/stephan/workspace/cbra/cbratest/spec/examples/letters/C
|
50
|
+
D /Users/stephan/workspace/cbra/cbratest/spec/examples/letters/D
|
51
|
+
E1 /Users/stephan/workspace/cbra/cbratest/spec/examples/letters/E1
|
52
|
+
E2 /Users/stephan/workspace/cbra/cbratest/spec/examples/letters/E2
|
53
|
+
F /Users/stephan/workspace/cbra/cbratest/spec/examples/letters/F
|
54
|
+
A /Users/stephan/workspace/cbra/cbratest/spec/examples/letters/A
|
55
|
+
|
56
|
+
Changes since last commit
|
57
|
+
/Users/stephan/workspace/cbra/cbratest/README.md
|
58
|
+
/Users/stephan/workspace/cbra/cbratest/spec/examples/letters/C/Gemfile
|
59
|
+
|
60
|
+
Directly affected components
|
61
|
+
C /Users/stephan/workspace/cbra/cbratest/spec/examples/letters/C
|
62
|
+
|
63
|
+
Transitively affected components
|
64
|
+
B /Users/stephan/workspace/cbra/cbratest/spec/examples/letters/B
|
65
|
+
C /Users/stephan/workspace/cbra/cbratest/spec/examples/letters/C
|
66
|
+
A /Users/stephan/workspace/cbra/cbratest/spec/examples/letters/A
|
67
|
+
|
68
|
+
Test scripts to run
|
69
|
+
/Users/stephan/workspace/cbra/cbratest/spec/examples/letters/B/test.sh
|
70
|
+
/Users/stephan/workspace/cbra/cbratest/spec/examples/letters/C/test.sh
|
71
|
+
/Users/stephan/workspace/cbra/cbratest/spec/examples/letters/A/test.sh
|
72
|
+
|
73
|
+
## Todos
|
74
|
+
* make algorithm work for structures where a gem is in a sub folder of another gem (only the inner gem should be diectly affected)
|
75
|
+
* allow for other test runners to be specified
|
76
|
+
* optionally check for changes since origin/master
|
77
|
+
* optionally allow branch to compare against to be specified
|
78
|
+
|
79
|
+
## License
|
80
|
+
|
81
|
+
Copyright (c) 2014 Stephan Hagemann, stephan.hagemann@gmail.com, [@shageman](http://twitter.com/shageman)
|
82
|
+
|
83
|
+
Released under the MIT license. See LICENSE file for details.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/cbratest
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require_relative "../lib/cbratest"
|
4
|
+
|
5
|
+
def help_text
|
6
|
+
<<-USAGE
|
7
|
+
cbratest [OPTION] [application path]
|
8
|
+
|
9
|
+
Test runner employing the structure of Component-based Ruby/Rails apps to optimize what needs to run.
|
10
|
+
|
11
|
+
Options are...
|
12
|
+
-h, -H, --help Display this help message.
|
13
|
+
|
14
|
+
-r, --results DEFAULT Display the directories of the components in need of running tests
|
15
|
+
-v, --verbose Verbose output of all parts of the calculation
|
16
|
+
USAGE
|
17
|
+
end
|
18
|
+
|
19
|
+
option = "-r"
|
20
|
+
path = nil
|
21
|
+
|
22
|
+
case ARGV.size
|
23
|
+
when 0
|
24
|
+
when 1
|
25
|
+
if ARGV[0].start_with? "-"
|
26
|
+
option = ARGV[0]
|
27
|
+
else
|
28
|
+
path = ARGV[0]
|
29
|
+
end
|
30
|
+
when 2
|
31
|
+
option = ARGV[0]
|
32
|
+
path = ARGV[1]
|
33
|
+
else
|
34
|
+
puts "Incorrect invocation. Please see help:\n\n"
|
35
|
+
puts help_text
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
|
39
|
+
if option
|
40
|
+
if %w(--help -h -H).include? option
|
41
|
+
puts help_text
|
42
|
+
elsif %w(-r --results).include? option
|
43
|
+
Cbratest::Runner.new(false).run path
|
44
|
+
elsif %w(-v --verbose).include? option
|
45
|
+
Cbratest::Runner.new(true).run path
|
46
|
+
end
|
47
|
+
end
|
data/cbratest.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'cbratest'
|
7
|
+
spec.version = '0.1.0'
|
8
|
+
spec.authors = ['Stephan Hagemann']
|
9
|
+
spec.email = ['stephan.hagemann@gmail.com']
|
10
|
+
spec.summary = %q{A test runner for your #cbra application}
|
11
|
+
spec.description = %q{A test runner that optimizes the tests it runs based on the recent changes of your application. Makes use of #cbra dependencies to infer which parts of the application are definitely unaffected. Science! BOOM!}
|
12
|
+
spec.homepage = 'https://github.com/shageman/cbradeps'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
|
15
|
+
spec.files = %w(
|
16
|
+
bin/cbratest
|
17
|
+
cbratest.gemspec
|
18
|
+
Gemfile
|
19
|
+
lib/cbratest/affected_component_finder.rb
|
20
|
+
lib/cbratest/gemfile_scraper.rb
|
21
|
+
lib/cbratest/tests_to_run_selector.rb
|
22
|
+
lib/cbratest/transitive_affected_component_finder.rb
|
23
|
+
lib/cbratest.rb
|
24
|
+
LICENSE
|
25
|
+
Rakefile
|
26
|
+
README.md
|
27
|
+
)
|
28
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
29
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
30
|
+
spec.require_paths = ['lib']
|
31
|
+
|
32
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
33
|
+
spec.add_development_dependency 'rake'
|
34
|
+
spec.add_development_dependency 'rspec'
|
35
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Cbratest
|
2
|
+
class AffectedComponentFinder
|
3
|
+
def find(components, changes)
|
4
|
+
components.inject({}) do |memo, component|
|
5
|
+
memo[component] = false
|
6
|
+
changes.each do |change|
|
7
|
+
if change.start_with? component[:options][:path]
|
8
|
+
memo[component] = true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
memo
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Cbratest
|
2
|
+
class GemfileScraper
|
3
|
+
def initialize(root_path)
|
4
|
+
@root_path = root_path
|
5
|
+
end
|
6
|
+
|
7
|
+
def name
|
8
|
+
Pathname.new(@root_path).basename.to_s
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
{name: name, options: {path: @root_path}}
|
13
|
+
end
|
14
|
+
|
15
|
+
def cbra_dependencies
|
16
|
+
dirdep = direct_dependencies
|
17
|
+
transitive_cbra_dependencies.select do |dep|
|
18
|
+
dirdep.include?(dep[:name]) || dep[:options][:direct]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def transitive_cbra_dependencies
|
23
|
+
gem_dependencies.inject([]) do |memo, dep|
|
24
|
+
if !!dep[:options][:path]
|
25
|
+
absolute_dep = dep.clone
|
26
|
+
absolute_dep[:options][:path] = File.expand_path(File.join(@root_path, dep[:options][:path]))
|
27
|
+
memo << dep
|
28
|
+
end
|
29
|
+
memo
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def raw_gemspec
|
36
|
+
path = File.expand_path(File.join(@root_path, "#{underscore(name)}.gemspec"))
|
37
|
+
File.exist?(path) ? File.read(path) : ""
|
38
|
+
end
|
39
|
+
|
40
|
+
def direct_dependencies
|
41
|
+
raw_gemspec.split("\n").inject([]) do |memo, line|
|
42
|
+
match = line.match(/add_(?:development_)?dependency\s+["']([^'"]+)["']/)
|
43
|
+
memo << match[1] if match
|
44
|
+
memo
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def raw_gemfile
|
49
|
+
path = File.expand_path(File.join(@root_path, "Gemfile"))
|
50
|
+
File.read(path)
|
51
|
+
end
|
52
|
+
|
53
|
+
def gem_dependencies
|
54
|
+
raw_gemfile.split("\n").inject([]) do |memo, line|
|
55
|
+
match = line.match(/gem\s+["']([^'"]+)["'](.*)/)
|
56
|
+
if match
|
57
|
+
memo << {name: match[1], options: OptionParser.new(match[2]).parse}
|
58
|
+
end
|
59
|
+
memo
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def underscore(string)
|
64
|
+
string.gsub(/::/, '/').
|
65
|
+
gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
|
66
|
+
gsub(/([a-z\d])([A-Z])/, '\1_\2').
|
67
|
+
tr("-", "_").
|
68
|
+
downcase
|
69
|
+
end
|
70
|
+
|
71
|
+
class OptionParser
|
72
|
+
def initialize(options)
|
73
|
+
@options = options
|
74
|
+
end
|
75
|
+
|
76
|
+
def parse
|
77
|
+
{}.merge(path).merge(direct)
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def path
|
83
|
+
match = @options.match(/path(?:\s*=>|:)\s+["']([^'"]+)["']/)
|
84
|
+
match ? {path: match[1]} : {}
|
85
|
+
end
|
86
|
+
|
87
|
+
def direct
|
88
|
+
match = @options.match(/direct(?:\s*=>|:)\s+true/)
|
89
|
+
match ? {direct: true} : {}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Cbratest
|
2
|
+
class TransitiveAffectedComponentFinder
|
3
|
+
def find(affected)
|
4
|
+
all_affected = {}
|
5
|
+
affected.keys.each do |key|
|
6
|
+
gem = GemfileScraper.new(key[:options][:path])
|
7
|
+
if gem.transitive_cbra_dependencies.any? { |dep| affected[dep] }
|
8
|
+
all_affected[key] = true
|
9
|
+
else
|
10
|
+
all_affected[key] = affected[key] || false
|
11
|
+
end
|
12
|
+
end
|
13
|
+
all_affected
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/cbratest.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'pathname'
|
3
|
+
require 'graphviz'
|
4
|
+
|
5
|
+
module Cbratest
|
6
|
+
require_relative "cbratest/gemfile_scraper"
|
7
|
+
require_relative "cbratest/affected_component_finder"
|
8
|
+
require_relative "cbratest/transitive_affected_component_finder"
|
9
|
+
require_relative "cbratest/tests_to_run_selector"
|
10
|
+
|
11
|
+
class Runner
|
12
|
+
def initialize(verbose_output)
|
13
|
+
@verbose_output = verbose_output
|
14
|
+
end
|
15
|
+
|
16
|
+
def run(root_path)
|
17
|
+
path = root_path || current_path
|
18
|
+
app = GemfileScraper.new(path)
|
19
|
+
|
20
|
+
outputs "All components"
|
21
|
+
cbra_deps = app.transitive_cbra_dependencies.to_set
|
22
|
+
components = cbra_deps << app.to_s
|
23
|
+
outputs component_out(components.to_a)
|
24
|
+
|
25
|
+
|
26
|
+
outputs "\nChanges since last commit"
|
27
|
+
root_dir = `cd #{path} && git rev-parse --show-toplevel`.chomp
|
28
|
+
changes = `cd #{root_dir} && git status -s -u`.split("\n").map { |file| File.join(root_dir, file.sub(/^.../, "")) }
|
29
|
+
outputs changes
|
30
|
+
|
31
|
+
|
32
|
+
outputs "\nDirectly affected components"
|
33
|
+
affected = AffectedComponentFinder.new.find(components, changes)
|
34
|
+
outputs affected_out(affected)
|
35
|
+
|
36
|
+
outputs "\nTransitively affected components"
|
37
|
+
all_affected = TransitiveAffectedComponentFinder.new.find(affected)
|
38
|
+
outputs affected_out(all_affected)
|
39
|
+
|
40
|
+
outputs "\nTest scripts to run"
|
41
|
+
outputs all_in_need_of_running = TestsToRunSelector.new.list(all_affected), true
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def outputs(arg, even_non_verbose = false)
|
47
|
+
output(arg) if even_non_verbose || @verbose_output
|
48
|
+
end
|
49
|
+
|
50
|
+
def output(arg)
|
51
|
+
puts arg
|
52
|
+
end
|
53
|
+
|
54
|
+
def component_out(array)
|
55
|
+
array.map do |component|
|
56
|
+
"#{component[:name].ljust(max_key_width(array))} #{component[:options][:path]}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def affected_out(hash)
|
61
|
+
hash.keys.inject([]) do |memo, component|
|
62
|
+
memo << "#{component[:name].ljust(max_key_width(hash.keys))} #{component[:options][:path]}" if hash[component]
|
63
|
+
memo
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def max_key_width(array)
|
68
|
+
array.inject(0) do |memo, component|
|
69
|
+
[memo, component[:name].length].max
|
70
|
+
end + 2
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cbratest
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stephan Hagemann
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: 'A test runner that optimizes the tests it runs based on the recent changes
|
56
|
+
of your application. Makes use of #cbra dependencies to infer which parts of the
|
57
|
+
application are definitely unaffected. Science! BOOM!'
|
58
|
+
email:
|
59
|
+
- stephan.hagemann@gmail.com
|
60
|
+
executables:
|
61
|
+
- cbratest
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- bin/cbratest
|
66
|
+
- cbratest.gemspec
|
67
|
+
- Gemfile
|
68
|
+
- lib/cbratest/affected_component_finder.rb
|
69
|
+
- lib/cbratest/gemfile_scraper.rb
|
70
|
+
- lib/cbratest/tests_to_run_selector.rb
|
71
|
+
- lib/cbratest/transitive_affected_component_finder.rb
|
72
|
+
- lib/cbratest.rb
|
73
|
+
- LICENSE
|
74
|
+
- Rakefile
|
75
|
+
- README.md
|
76
|
+
homepage: https://github.com/shageman/cbradeps
|
77
|
+
licenses:
|
78
|
+
- MIT
|
79
|
+
metadata: {}
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
requirements: []
|
95
|
+
rubyforge_project:
|
96
|
+
rubygems_version: 2.0.3
|
97
|
+
signing_key:
|
98
|
+
specification_version: 4
|
99
|
+
summary: 'A test runner for your #cbra application'
|
100
|
+
test_files: []
|