knapsack 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +10 -5
- data/CHANGELOG.md +6 -1
- data/lib/knapsack.rb +1 -0
- data/lib/knapsack/allocator.rb +5 -41
- data/lib/knapsack/config.rb +33 -0
- data/lib/knapsack/distributors/base_distributor.rb +18 -15
- data/lib/knapsack/distributors/leftover_distributor.rb +1 -15
- data/lib/knapsack/distributors/report_distributor.rb +7 -3
- data/lib/knapsack/report.rb +1 -1
- data/lib/knapsack/tracker.rb +3 -7
- data/lib/knapsack/version.rb +1 -1
- data/lib/tasks/knapsack.rake +1 -3
- data/spec/knapsack/allocator_spec.rb +5 -5
- data/spec/knapsack/config_spec.rb +92 -0
- data/spec/knapsack/distributors/report_distributor_spec.rb +46 -6
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b9c0c3f2c4c9ade9a8b93a9285ae2ec1fef1810f
|
4
|
+
data.tar.gz: ba827b1b39aa68a0df7052f579d635dc91331700
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 210967c7a39fb22ee932848d362b15356173270e62e58cd427fecc9b4d6e732dfee5a4501d4947440d13a134b9a149e38bb160ebf052ef577dfaf24e978a533a
|
7
|
+
data.tar.gz: 76ad4ccb462dd2e732add681a6db6274b300866fe4ef58266e812914c768ced59e88bbac60d1cf6f7e92a8c0c69ebbb9635d0ffca3d83dd3e71718b6eb60f225
|
data/.travis.yml
CHANGED
@@ -12,21 +12,26 @@ addons:
|
|
12
12
|
before_install:
|
13
13
|
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
|
14
14
|
script:
|
15
|
+
- echo "Run specs for Knapsack gem"
|
15
16
|
- bundle exec rspec spec
|
16
17
|
|
17
|
-
|
18
|
+
- echo "Generate knapsack report"
|
18
19
|
- KNAPSACK_GENERATE_REPORT=true bundle exec rspec --default-path spec_examples --tag focus
|
19
20
|
|
20
|
-
|
21
|
+
- echo "Run specs with enabled time offset warning"
|
21
22
|
- bundle exec rspec --default-path spec_examples
|
22
23
|
|
23
|
-
|
24
|
+
- echo "Run rake task for the first CI node"
|
24
25
|
- CI_NODE_TOTAL=2 CI_NODE_INDEX=0 KNAPSACK_SPEC_PATTERN="spec_examples/**/*_spec.rb" bundle exec rake knapsack:rspec
|
25
|
-
|
26
|
+
- echo "Run rake task for the second CI node"
|
26
27
|
- CI_NODE_TOTAL=2 CI_NODE_INDEX=1 KNAPSACK_SPEC_PATTERN="spec_examples/**/*_spec.rb" bundle exec rake knapsack:rspec
|
27
28
|
|
28
|
-
|
29
|
+
- echo "Run specs for custom knapsack report path"
|
29
30
|
- cp knapsack_report.json custom_knapsack_report.json
|
30
31
|
- KNAPSACK_SPEC_PATTERN="spec_examples/**/*_spec.rb" KNAPSACK_REPORT_PATH="custom_knapsack_report.json" bundle exec rake knapsack:rspec
|
32
|
+
|
33
|
+
- echo "Run specs when spec file was removed and still exists in knapsack report json"
|
34
|
+
- rm spec_examples/fast/1_spec.rb
|
35
|
+
- KNAPSACK_SPEC_PATTERN="spec_examples/**/*_spec.rb" bundle exec rake knapsack:rspec
|
31
36
|
notifications:
|
32
37
|
email: false
|
data/CHANGELOG.md
CHANGED
data/lib/knapsack.rb
CHANGED
data/lib/knapsack/allocator.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module Knapsack
|
2
2
|
class Allocator
|
3
3
|
def initialize(args={})
|
4
|
-
@
|
5
|
-
@report_distributor = Knapsack::Distributors::ReportDistributor.new(
|
6
|
-
@leftover_distributor = Knapsack::Distributors::LeftoverDistributor.new(
|
4
|
+
@spec_pattern = args[:spec_pattern] || Config.spec_pattern
|
5
|
+
@report_distributor = Knapsack::Distributors::ReportDistributor.new(args)
|
6
|
+
@leftover_distributor = Knapsack::Distributors::LeftoverDistributor.new(args)
|
7
7
|
end
|
8
8
|
|
9
9
|
def report_node_specs
|
@@ -22,44 +22,8 @@ module Knapsack
|
|
22
22
|
node_specs.join(' ')
|
23
23
|
end
|
24
24
|
|
25
|
-
def
|
26
|
-
|
27
|
-
@config[:spec_pattern].gsub(/^(.*?)\//).first
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def default_args
|
33
|
-
{
|
34
|
-
ci_node_total: env_ci_node_total,
|
35
|
-
ci_node_index: env_ci_node_index,
|
36
|
-
spec_pattern: env_spec_pattern,
|
37
|
-
report: report
|
38
|
-
}
|
39
|
-
end
|
40
|
-
|
41
|
-
def env_ci_node_total
|
42
|
-
ENV['CI_NODE_TOTAL'] || ENV['CIRCLE_NODE_TOTAL']
|
43
|
-
end
|
44
|
-
|
45
|
-
def env_ci_node_index
|
46
|
-
ENV['CI_NODE_INDEX'] || ENV['CIRCLE_NODE_INDEX']
|
47
|
-
end
|
48
|
-
|
49
|
-
def env_spec_pattern
|
50
|
-
ENV['KNAPSACK_SPEC_PATTERN']
|
51
|
-
end
|
52
|
-
|
53
|
-
def env_report_path
|
54
|
-
ENV['KNAPSACK_REPORT_PATH']
|
55
|
-
end
|
56
|
-
|
57
|
-
def report
|
58
|
-
return unless env_report_path
|
59
|
-
Knapsack.report.config({
|
60
|
-
report_path: env_report_path
|
61
|
-
})
|
62
|
-
Knapsack.report.open
|
25
|
+
def spec_dir
|
26
|
+
@spec_pattern.gsub(/^(.*?)\//).first
|
63
27
|
end
|
64
28
|
end
|
65
29
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Knapsack
|
2
|
+
class Config
|
3
|
+
class << self
|
4
|
+
def report_path
|
5
|
+
ENV['KNAPSACK_REPORT_PATH'] || 'knapsack_report.json'
|
6
|
+
end
|
7
|
+
|
8
|
+
def ci_node_total
|
9
|
+
ENV['CI_NODE_TOTAL'] || ENV['CIRCLE_NODE_TOTAL'] || 1
|
10
|
+
end
|
11
|
+
|
12
|
+
def ci_node_index
|
13
|
+
ENV['CI_NODE_INDEX'] || ENV['CIRCLE_NODE_INDEX'] || 0
|
14
|
+
end
|
15
|
+
|
16
|
+
def spec_pattern
|
17
|
+
ENV['KNAPSACK_SPEC_PATTERN'] || 'spec/**/*_spec.rb'
|
18
|
+
end
|
19
|
+
|
20
|
+
def enable_time_offset_warning
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def time_offset_in_seconds
|
25
|
+
30
|
26
|
+
end
|
27
|
+
|
28
|
+
def generate_report
|
29
|
+
ENV['KNAPSACK_GENERATE_REPORT'] || false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,20 +1,13 @@
|
|
1
1
|
module Knapsack
|
2
2
|
module Distributors
|
3
3
|
class BaseDistributor
|
4
|
-
attr_reader :report, :node_specs
|
5
|
-
|
6
|
-
DEFAULT_CI_NODE_TOTAL = 1
|
7
|
-
DEFAULT_CI_NODE_INDEX = 0
|
4
|
+
attr_reader :report, :node_specs, :spec_pattern
|
8
5
|
|
9
6
|
def initialize(args={})
|
10
7
|
@report = args[:report] || default_report
|
11
|
-
@ci_node_total = args[:ci_node_total] ||
|
12
|
-
@ci_node_index = args[:ci_node_index] ||
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
def default_report
|
17
|
-
Knapsack.report.open
|
8
|
+
@ci_node_total = args[:ci_node_total] || config.ci_node_total
|
9
|
+
@ci_node_index = args[:ci_node_index] || config.ci_node_index
|
10
|
+
@spec_pattern = args[:spec_pattern] || config.spec_pattern
|
18
11
|
end
|
19
12
|
|
20
13
|
def ci_node_total
|
@@ -40,12 +33,12 @@ module Knapsack
|
|
40
33
|
post_assign_spec_files_to_node
|
41
34
|
end
|
42
35
|
|
43
|
-
|
44
|
-
|
45
|
-
def post_initialize(args)
|
46
|
-
nil
|
36
|
+
def all_specs
|
37
|
+
@all_specs ||= Dir[spec_pattern]
|
47
38
|
end
|
48
39
|
|
40
|
+
protected
|
41
|
+
|
49
42
|
def post_specs_for_node(node_index)
|
50
43
|
raise NotImplementedError
|
51
44
|
end
|
@@ -58,6 +51,16 @@ module Knapsack
|
|
58
51
|
raise NotImplementedError
|
59
52
|
end
|
60
53
|
|
54
|
+
private
|
55
|
+
|
56
|
+
def config
|
57
|
+
Knapsack::Config
|
58
|
+
end
|
59
|
+
|
60
|
+
def default_report
|
61
|
+
Knapsack.report.open
|
62
|
+
end
|
63
|
+
|
61
64
|
def update_node_index
|
62
65
|
@node_index += 1
|
63
66
|
@node_index = 0 if @node_index == ci_node_total
|
@@ -1,14 +1,8 @@
|
|
1
1
|
module Knapsack
|
2
2
|
module Distributors
|
3
3
|
class LeftoverDistributor < BaseDistributor
|
4
|
-
attr_reader :spec_pattern
|
5
|
-
|
6
4
|
def report_specs
|
7
|
-
@report_specs ||=
|
8
|
-
end
|
9
|
-
|
10
|
-
def all_specs
|
11
|
-
@all_specs ||= Dir[spec_pattern]
|
5
|
+
@report_specs ||= report.keys
|
12
6
|
end
|
13
7
|
|
14
8
|
def leftover_specs
|
@@ -17,14 +11,6 @@ module Knapsack
|
|
17
11
|
|
18
12
|
private
|
19
13
|
|
20
|
-
def post_initialize(args={})
|
21
|
-
@spec_pattern = args[:spec_pattern] || default_spec_pattern
|
22
|
-
end
|
23
|
-
|
24
|
-
def default_spec_pattern
|
25
|
-
'spec/**/*_spec.rb'
|
26
|
-
end
|
27
|
-
|
28
14
|
def post_assign_spec_files_to_node
|
29
15
|
leftover_specs.each do |spec_file|
|
30
16
|
node_specs[@node_index] << spec_file
|
@@ -2,11 +2,15 @@ module Knapsack
|
|
2
2
|
module Distributors
|
3
3
|
class ReportDistributor < BaseDistributor
|
4
4
|
def sorted_report
|
5
|
-
@sorted_report ||= report.sort_by{|
|
5
|
+
@sorted_report ||= report.sort_by { |spec_path, time| time }.reverse
|
6
|
+
end
|
7
|
+
|
8
|
+
def sorted_report_with_existing_specs
|
9
|
+
@sorted_report_with_existing_specs ||= sorted_report.select { |spec_path, time| all_specs.include?(spec_path) }
|
6
10
|
end
|
7
11
|
|
8
12
|
def total_time_execution
|
9
|
-
@total_time_execution ||=
|
13
|
+
@total_time_execution ||= sorted_report_with_existing_specs.map(&:last).reduce(0, :+).to_f
|
10
14
|
end
|
11
15
|
|
12
16
|
def node_time_execution
|
@@ -40,7 +44,7 @@ module Knapsack
|
|
40
44
|
def assign_slow_spec_files
|
41
45
|
@not_assigned_spec_files = []
|
42
46
|
@node_index = 0
|
43
|
-
|
47
|
+
sorted_report_with_existing_specs.each do |spec_file_with_time|
|
44
48
|
assign_slow_spec_file(spec_file_with_time)
|
45
49
|
update_node_index
|
46
50
|
end
|
data/lib/knapsack/report.rb
CHANGED
data/lib/knapsack/tracker.rb
CHANGED
@@ -50,16 +50,12 @@ module Knapsack
|
|
50
50
|
|
51
51
|
def default_config
|
52
52
|
{
|
53
|
-
enable_time_offset_warning:
|
54
|
-
time_offset_in_seconds:
|
55
|
-
generate_report: generate_report
|
53
|
+
enable_time_offset_warning: Config.enable_time_offset_warning,
|
54
|
+
time_offset_in_seconds: Config.time_offset_in_seconds,
|
55
|
+
generate_report: Config.generate_report
|
56
56
|
}
|
57
57
|
end
|
58
58
|
|
59
|
-
def generate_report
|
60
|
-
ENV['KNAPSACK_GENERATE_REPORT'] || false
|
61
|
-
end
|
62
|
-
|
63
59
|
def set_defaults
|
64
60
|
@global_time = 0
|
65
61
|
@spec_files_with_time = {}
|
data/lib/knapsack/version.rb
CHANGED
data/lib/tasks/knapsack.rake
CHANGED
@@ -12,9 +12,7 @@ namespace :knapsack do
|
|
12
12
|
puts allocator.leftover_node_specs
|
13
13
|
puts
|
14
14
|
|
15
|
-
|
16
|
-
default_path = custom_spec_dir ? "--default-path #{custom_spec_dir}" : nil
|
17
|
-
cmd = %Q[bundle exec rspec #{default_path} -- #{allocator.stringify_node_specs}]
|
15
|
+
cmd = %Q[bundle exec rspec --default-path #{allocator.spec_dir} -- #{allocator.stringify_node_specs}]
|
18
16
|
|
19
17
|
exec(cmd)
|
20
18
|
end
|
@@ -42,16 +42,16 @@ describe Knapsack::Allocator do
|
|
42
42
|
it { should eql node_specs.join(' ') }
|
43
43
|
end
|
44
44
|
|
45
|
-
describe '#
|
46
|
-
subject { allocator.
|
45
|
+
describe '#spec_dir' do
|
46
|
+
subject { allocator.spec_dir }
|
47
47
|
|
48
48
|
context 'when spec pattern exists' do
|
49
|
-
let(:spec_pattern) { "
|
50
|
-
it { should eql '
|
49
|
+
let(:spec_pattern) { "spec_dir/**/*_spec.rb" }
|
50
|
+
it { should eql 'spec_dir/' }
|
51
51
|
end
|
52
52
|
|
53
53
|
context "when spec pattern doesn't exist" do
|
54
|
-
it { should
|
54
|
+
it { should eql 'spec/' }
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
describe Knapsack::Config do
|
2
|
+
describe '.report_path' do
|
3
|
+
subject { described_class.report_path }
|
4
|
+
|
5
|
+
context 'when ENV exists' do
|
6
|
+
let(:report_path) { 'custom_knapsack_report.json' }
|
7
|
+
before { stub_const("ENV", { 'KNAPSACK_REPORT_PATH' => report_path }) }
|
8
|
+
it { should eql report_path }
|
9
|
+
end
|
10
|
+
|
11
|
+
context "when ENV doesn't exist" do
|
12
|
+
it { should eql 'knapsack_report.json' }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.ci_node_total' do
|
17
|
+
subject { described_class.ci_node_total }
|
18
|
+
|
19
|
+
context 'when ENV exists' do
|
20
|
+
context 'when CI_NODE_TOTAL has value' do
|
21
|
+
before { stub_const("ENV", { 'CI_NODE_TOTAL' => 5 }) }
|
22
|
+
it { should eql 5 }
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when CIRCLE_NODE_TOTAL has value' do
|
26
|
+
before { stub_const("ENV", { 'CIRCLE_NODE_TOTAL' => 4 }) }
|
27
|
+
it { should eql 4 }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when ENV doesn't exist" do
|
32
|
+
it { should eql 1 }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '.ci_node_index' do
|
37
|
+
subject { described_class.ci_node_index }
|
38
|
+
|
39
|
+
context 'when ENV exists' do
|
40
|
+
context 'when CI_NODE_INDEX has value' do
|
41
|
+
before { stub_const("ENV", { 'CI_NODE_INDEX' => 3 }) }
|
42
|
+
it { should eql 3 }
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when CIRCLE_NODE_INDEX has value' do
|
46
|
+
before { stub_const("ENV", { 'CIRCLE_NODE_INDEX' => 2 }) }
|
47
|
+
it { should eql 2 }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when ENV doesn't exist" do
|
52
|
+
it { should eql 0 }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '.spec_pattern' do
|
57
|
+
subject { described_class.spec_pattern }
|
58
|
+
|
59
|
+
context 'when ENV exists' do
|
60
|
+
let(:spec_pattern) { 'custom_spec/**/*_spec.rb' }
|
61
|
+
before { stub_const("ENV", { 'KNAPSACK_SPEC_PATTERN' => spec_pattern }) }
|
62
|
+
it { should eql spec_pattern }
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when ENV doesn't exist" do
|
66
|
+
it { should eql 'spec/**/*_spec.rb' }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '.enable_time_offset_warning' do
|
71
|
+
subject { described_class.enable_time_offset_warning }
|
72
|
+
it { should be true }
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '.time_offset_in_seconds' do
|
76
|
+
subject { described_class.time_offset_in_seconds }
|
77
|
+
it { should eql 30 }
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '.generate_report' do
|
81
|
+
subject { described_class.generate_report }
|
82
|
+
|
83
|
+
context 'when ENV exists' do
|
84
|
+
before { stub_const("ENV", { 'KNAPSACK_GENERATE_REPORT' => true }) }
|
85
|
+
it { should be true }
|
86
|
+
end
|
87
|
+
|
88
|
+
context "when ENV doesn't exist" do
|
89
|
+
it { should be false }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -27,12 +27,44 @@ describe Knapsack::Distributors::ReportDistributor do
|
|
27
27
|
|
28
28
|
it do
|
29
29
|
should eql([
|
30
|
-
[
|
31
|
-
[
|
32
|
-
[
|
33
|
-
[
|
34
|
-
[
|
35
|
-
[
|
30
|
+
['f_spec.rb', 3.5],
|
31
|
+
['e_spec.rb', 3.0],
|
32
|
+
['d_spec.rb', 2.5],
|
33
|
+
['c_spec.rb', 2.0],
|
34
|
+
['b_spec.rb', 1.5],
|
35
|
+
['a_spec.rb', 1.0],
|
36
|
+
])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#sorted_report_with_existing_specs' do
|
41
|
+
subject { distributor.sorted_report_with_existing_specs }
|
42
|
+
|
43
|
+
before do
|
44
|
+
expect(distributor).to receive(:all_specs).exactly(6).times.and_return([
|
45
|
+
'b_spec.rb',
|
46
|
+
'd_spec.rb',
|
47
|
+
'f_spec.rb',
|
48
|
+
])
|
49
|
+
end
|
50
|
+
|
51
|
+
let(:report) do
|
52
|
+
{
|
53
|
+
'e_spec.rb' => 3.0,
|
54
|
+
'f_spec.rb' => 3.5,
|
55
|
+
'c_spec.rb' => 2.0,
|
56
|
+
'd_spec.rb' => 2.5,
|
57
|
+
'a_spec.rb' => 1.0,
|
58
|
+
'b_spec.rb' => 1.5,
|
59
|
+
}
|
60
|
+
end
|
61
|
+
let(:args) { { report: report } }
|
62
|
+
|
63
|
+
it do
|
64
|
+
should eql([
|
65
|
+
['f_spec.rb', 3.5],
|
66
|
+
['d_spec.rb', 2.5],
|
67
|
+
['b_spec.rb', 1.5],
|
36
68
|
])
|
37
69
|
end
|
38
70
|
end
|
@@ -47,6 +79,10 @@ describe Knapsack::Distributors::ReportDistributor do
|
|
47
79
|
end
|
48
80
|
let(:args) { { report: report } }
|
49
81
|
|
82
|
+
before do
|
83
|
+
allow(distributor).to receive(:all_specs).and_return(report.keys)
|
84
|
+
end
|
85
|
+
|
50
86
|
describe '#total_time_execution' do
|
51
87
|
subject { distributor.total_time_execution }
|
52
88
|
|
@@ -93,6 +129,10 @@ describe Knapsack::Distributors::ReportDistributor do
|
|
93
129
|
}
|
94
130
|
end
|
95
131
|
|
132
|
+
before do
|
133
|
+
allow(distributor).to receive(:all_specs).and_return(report.keys)
|
134
|
+
end
|
135
|
+
|
96
136
|
describe '#assign_spec_files_to_node' do
|
97
137
|
before { distributor.assign_spec_files_to_node }
|
98
138
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knapsack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ArturT
|
@@ -110,6 +110,7 @@ files:
|
|
110
110
|
- lib/knapsack/adapters/base_adapter.rb
|
111
111
|
- lib/knapsack/adapters/rspec_adapter.rb
|
112
112
|
- lib/knapsack/allocator.rb
|
113
|
+
- lib/knapsack/config.rb
|
113
114
|
- lib/knapsack/distributors/base_distributor.rb
|
114
115
|
- lib/knapsack/distributors/leftover_distributor.rb
|
115
116
|
- lib/knapsack/distributors/report_distributor.rb
|
@@ -122,6 +123,7 @@ files:
|
|
122
123
|
- spec/knapsack/adapters/base_adapter_spec.rb
|
123
124
|
- spec/knapsack/adapters/rspec_adapter_spec.rb
|
124
125
|
- spec/knapsack/allocator_spec.rb
|
126
|
+
- spec/knapsack/config_spec.rb
|
125
127
|
- spec/knapsack/distributors/base_distributor_spec.rb
|
126
128
|
- spec/knapsack/distributors/leftover_distributor_spec.rb
|
127
129
|
- spec/knapsack/distributors/report_distributor_spec.rb
|
@@ -173,6 +175,7 @@ test_files:
|
|
173
175
|
- spec/knapsack/adapters/base_adapter_spec.rb
|
174
176
|
- spec/knapsack/adapters/rspec_adapter_spec.rb
|
175
177
|
- spec/knapsack/allocator_spec.rb
|
178
|
+
- spec/knapsack/config_spec.rb
|
176
179
|
- spec/knapsack/distributors/base_distributor_spec.rb
|
177
180
|
- spec/knapsack/distributors/leftover_distributor_spec.rb
|
178
181
|
- spec/knapsack/distributors/report_distributor_spec.rb
|